JAL-1270 unit tests for HiddenSequences
[jalview.git] / test / jalview / datamodel / HiddenSequencesTest.java
diff --git a/test/jalview/datamodel/HiddenSequencesTest.java b/test/jalview/datamodel/HiddenSequencesTest.java
new file mode 100644 (file)
index 0000000..8b50a8b
--- /dev/null
@@ -0,0 +1,378 @@
+package jalview.datamodel;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertNotNull;
+import static org.testng.AssertJUnit.assertNotSame;
+import static org.testng.AssertJUnit.assertNull;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
+
+import jalview.gui.AlignViewport;
+
+import java.util.List;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+@Test(singleThreaded = true)
+public class HiddenSequencesTest
+{
+  static int SEQ_COUNT = 10;
+
+  SequenceI[] seqs;
+  
+  /**
+   * Set up an alignment of 10 sequences
+   */
+  @BeforeTest(alwaysRun = true)
+  public void setUp()
+  {
+    seqs = new SequenceI[SEQ_COUNT];
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      // sequence lengths are 1, 2, ... 10
+      seqs[i] = new Sequence("Seq" + i, "abcdefghijk".substring(0, i + 1));
+    }
+  }
+
+  /**
+   * Test the method that converts sequence alignment index to what it would be
+   * if all sequences were unhidden
+   */
+  @Test(groups = "Functional")
+  public void testAdjustForHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.adjustForHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.adjustForHiddenSeqs(0));
+    assertEquals(2, hs.adjustForHiddenSeqs(1));
+    assertEquals(3, hs.adjustForHiddenSeqs(2));
+    assertEquals(4, hs.adjustForHiddenSeqs(3));
+    assertEquals(7, hs.adjustForHiddenSeqs(4));
+    assertEquals(8, hs.adjustForHiddenSeqs(5));
+    assertEquals(9, hs.adjustForHiddenSeqs(6));
+  }
+
+  /**
+   * Test the method that increments the internal array size if a sequence is
+   * added to the alignment (ugh this should not be exposed to the light of day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceAdded()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide one sequence
+    hs.hideSequence(seqs[3]);
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * add a sequence to the alignment
+     * - the safe way to call hs.adjustHeightSequenceAdded!
+     * (implementation depends on alignment height having
+     * been already updated for the added sequence)
+     */
+    al.addSequence(new Sequence("a", "b"));
+    assertEquals(1, hs.getSize());
+    assertEquals(SEQ_COUNT, al.getHeight());
+    assertEquals(SEQ_COUNT + 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that decrements the internal array size if a sequence is
+   * deleted from the alignment (ugh this should not be exposed to the light of
+   * day)
+   */
+  @Test(groups = "Functional")
+  public void testAdjustHeightSequenceDeleted()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertEquals(SEQ_COUNT, al.getHeight());
+
+    HiddenSequences hs = al.getHiddenSequences();
+    // initially does nothing
+    hs.adjustHeightSequenceAdded();
+    assertNull(hs.hiddenSequences);
+
+    // hide two sequences
+    hs.hideSequence(seqs[3]);
+    hs.hideSequence(seqs[5]);
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertTrue(hs.isHidden(seqs[5]));
+    assertEquals(SEQ_COUNT - 2, al.getHeight());
+    assertEquals(SEQ_COUNT, hs.hiddenSequences.length);
+
+    /*
+     * delete a visible sequence from the alignment
+     * - the safe way to call hs.adjustHeightSequenceDeleted!
+     * (implementation depends on alignment height having
+     * been already updated for the removed sequence)
+     */
+    al.deleteSequence(seqs[2]);
+    assertEquals(2, hs.getSize());
+    // the visible alignment is unchanged:
+    assertEquals(SEQ_COUNT - 3, al.getHeight());
+    // sequences array size has decremented:
+    assertEquals(SEQ_COUNT - 1, hs.hiddenSequences.length);
+  }
+
+  /**
+   * Test the method that converts a 'full alignment' sequence index into the
+   * equivalent in the alignment with sequences hidden
+   */
+  @Test(groups = "Functional")
+  public void testFindIndexWithoutHiddenSeqs()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    for (int i = 0; i < SEQ_COUNT; i++)
+    {
+      assertEquals(i, hs.findIndexWithoutHiddenSeqs(i));
+    }
+
+    // hide seq1 and seq5 and seq6
+    hs.hideSequence(seqs[1]);
+    hs.hideSequence(seqs[5]);
+    hs.hideSequence(seqs[6]);
+
+    /*
+     * alignment is now seq0/2/3/4/7/8/9
+     */
+    assertEquals(7, al.getHeight());
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(0));
+    assertEquals(0, hs.findIndexWithoutHiddenSeqs(1));
+    assertEquals(1, hs.findIndexWithoutHiddenSeqs(2));
+    assertEquals(2, hs.findIndexWithoutHiddenSeqs(3));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(4));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(5));
+    assertEquals(3, hs.findIndexWithoutHiddenSeqs(6));
+    assertEquals(4, hs.findIndexWithoutHiddenSeqs(7));
+    assertEquals(5, hs.findIndexWithoutHiddenSeqs(8));
+    assertEquals(6, hs.findIndexWithoutHiddenSeqs(9));
+  }
+
+  /**
+   * Test the method that reconstructs (sort of) the full alignment including
+   * hidden sequences
+   */
+  @Test(groups = "Functional")
+  public void testGetFullAlignment()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertArrayEquals(seqs, al.getSequencesArray());
+    al.setProperty("a", "b");
+    al.addAnnotation(new AlignmentAnnotation("ann", "label", 12f));
+    al.setSeqrep(seqs[4]);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[8], false);
+    al.addGroup(sg);
+    ((Alignment) al).hasRNAStructure = true;
+
+    HiddenSequences hs = al.getHiddenSequences();
+    AlignmentI al2 = hs.getFullAlignment();
+    // new alignment but with original sequences
+    assertNotSame(al, al2);
+    assertArrayEquals(al.getSequencesArray(), al2.getSequencesArray());
+
+    hs.hideSequence(seqs[4]);
+    hs.hideSequence(seqs[9]);
+    al2 = hs.getFullAlignment();
+    assertNotSame(al, al2);
+    assertArrayEquals(seqs, al2.getSequencesArray());
+    assertNotNull(al2.getProperties());
+    assertSame(al.getProperties(), al2.getProperties());
+    assertNotNull(al2.getAlignmentAnnotation());
+    assertSame(al.getAlignmentAnnotation(), al2.getAlignmentAnnotation());
+    assertSame(seqs[4], al2.getSeqrep());
+    assertNotNull(al2.getGroups());
+    assertSame(al.getGroups(), al2.getGroups());
+    assertTrue(al2.hasRNAStructure());
+  }
+
+  /**
+   * Test the method that returns the hidden sequence at a given index in the
+   * full alignment
+   * 
+   * @return either the sequence (if hidden) or null (if not hidden)
+   */
+  @Test(groups = "Functional")
+  public void testGetHiddenSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertNull(hs.getHiddenSequence(0));
+    hs.hideSequence(seqs[3]);
+    assertSame(seqs[3], hs.getHiddenSequence(3));
+    assertNull(hs.getHiddenSequence(2));
+    assertNull(hs.getHiddenSequence(4));
+  }
+
+  @Test(groups = "Functional")
+  public void testGetSize()
+  {
+  }
+
+  @Test(groups = "Functional")
+  public void testGetWidth()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getWidth());
+    hs.hideSequence(seqs[6]);
+    hs.hideSequence(seqs[8]);
+    assertEquals(9, hs.getWidth());
+  }
+
+  /**
+   * Test the method that adds a sequence to the hidden sequences and deletes it
+   * from the alignment, and its converse
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+    assertTrue(al.getSequences().contains(seqs[1]));
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+
+    /*
+     * hide the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[1]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertEquals(1, hs.getSize());
+    assertEquals(9, al.getHeight());
+    assertSame(seqs[2], al.getSequenceAt(1));
+
+    /*
+     * hide what is now the second sequence in the alignment
+     */
+    hs.hideSequence(seqs[2]);
+    assertFalse(hs.isHidden(seqs[0]));
+    assertTrue(hs.isHidden(seqs[1]));
+    assertTrue(hs.isHidden(seqs[2]));
+    assertFalse(al.getSequences().contains(seqs[1]));
+    assertFalse(al.getSequences().contains(seqs[2]));
+    assertEquals(2, hs.getSize());
+    assertEquals(8, al.getHeight());
+
+    /*
+     * perform 'reveal' on what is now the second sequence in the alignment
+     * this should unhide the two sequences that precede it
+     */
+    List<SequenceI> revealed = hs.showSequence(1, null);
+    assertEquals(2, revealed.size());
+    assertTrue(revealed.contains(seqs[1]));
+    assertTrue(revealed.contains(seqs[2]));
+    assertEquals(0, hs.getSize());
+    assertEquals(10, al.getHeight());
+  }
+
+  @Test(groups = "Functional")
+  public void testIsHidden()
+  {
+    AlignmentI al = new Alignment(seqs);
+    HiddenSequences hs = al.getHiddenSequences();
+    hs.hideSequence(seqs[7]);
+    hs.hideSequence(seqs[4]);
+    assertTrue(hs.isHidden(seqs[4]));
+    assertFalse(hs.isHidden(seqs[5]));
+    assertFalse(hs.isHidden(seqs[6]));
+    assertTrue(hs.isHidden(seqs[7]));
+    assertFalse(hs.isHidden(null));
+    assertFalse(hs.isHidden(new Sequence("", "")));
+  }
+
+  /**
+   * Test hiding and unhiding a group with a representative sequence. The
+   * representative should be left visible when the group is hidden, and
+   * included in the selected group when it is unhidden.
+   */
+  @Test(groups = "Functional")
+  public void testHideShowSequence_withHiddenRepSequence()
+  {
+    AlignmentI al = new Alignment(seqs);
+
+    /*
+     * represent seqs 2-4 with seq3
+     * this hides seq2 and seq4 but not seq3
+     */
+    AlignViewport av = new AlignViewport(al);
+    SequenceGroup sg = new SequenceGroup();
+    sg.addSequence(seqs[1], false);
+    sg.addSequence(seqs[2], false);
+    sg.addSequence(seqs[3], false);
+    av.setSelectionGroup(sg);
+
+    /*
+     * hiding group with reference sequence is done via AlignViewport
+     */
+    av.hideSequences(seqs[2], true);
+    HiddenSequences hs = al.getHiddenSequences();
+    assertEquals(2, hs.getSize());
+    assertTrue(hs.isHidden(seqs[1]));
+    assertFalse(hs.isHidden(seqs[2]));
+    assertTrue(hs.isHidden(seqs[3]));
+
+    /*
+     * should now be no sequences selected in the alignment
+     */
+    assertNull(av.getSelectionGroup());
+
+    /*
+     * visible alignment is now seq0/2/4/5/6/7/8/9
+     * 'reveal sequences' at the representative sequence (index = 1)
+     * this should unhide the one above i.e. seq1
+     * and return a selection list including seq2
+     * 
+     * note have to call via AlignViewport to get the expected
+     * resulting sequence selection
+     */
+    av.showSequence(1);
+
+    /*
+     * only seq3 is now hidden
+     */
+    assertEquals(1, hs.getSize());
+    assertTrue(hs.isHidden(seqs[3]));
+    assertEquals(SEQ_COUNT - 1, al.getHeight());
+    sg = av.getSelectionGroup();
+
+    /*
+     * unhidden and representative sequence selected
+     * (this behaviour may change! JAL-2133)
+     */
+    assertEquals(2, sg.getSize());
+    assertTrue(sg.getSequences().contains(seqs[1]));
+    assertTrue(sg.getSequences().contains(seqs[2]));
+    assertFalse(sg.getSequences().contains(seqs[3]));
+  }
+}