JAL-2172 unit test added
[jalview.git] / test / jalview / datamodel / ColumnSelectionTest.java
index 38e9c93..04af3ce 100644 (file)
@@ -1,7 +1,31 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.datamodel;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+import static org.testng.AssertJUnit.assertSame;
+import static org.testng.AssertJUnit.assertTrue;
 
+import java.util.Arrays;
 import java.util.List;
 
 import org.testng.annotations.Test;
@@ -9,23 +33,23 @@ import org.testng.annotations.Test;
 public class ColumnSelectionTest
 {
 
-  @Test(groups ={ "Functional" })
+  @Test(groups = { "Functional" })
   public void testAddElement()
   {
     ColumnSelection cs = new ColumnSelection();
     cs.addElement(2);
     cs.addElement(5);
+    cs.addElement(3);
+    cs.addElement(5); // ignored
     List<Integer> sel = cs.getSelected();
-    assertEquals(2, sel.size());
-    assertEquals(new Integer(2), sel.get(0));
-    assertEquals(new Integer(5), sel.get(1));
+    assertEquals("[2, 5, 3]", sel.toString());
   }
 
   /**
    * Test the remove method - in particular to verify that remove(int i) removes
    * the element whose value is i, _NOT_ the i'th element.
    */
-  @Test(groups ={ "Functional" })
+  @Test(groups = { "Functional" })
   public void testRemoveElement()
   {
     ColumnSelection cs = new ColumnSelection();
@@ -50,7 +74,7 @@ public class ColumnSelectionTest
    * Test the method that finds the visible column position of an alignment
    * column, allowing for hidden columns.
    */
-  @Test(groups ={ "Functional" })
+  @Test(groups = { "Functional" })
   public void testFindColumnPosition()
   {
     ColumnSelection cs = new ColumnSelection();
@@ -60,10 +84,6 @@ public class ColumnSelectionTest
     cs.hideColumns(6, 6);
     assertEquals(5, cs.findColumnPosition(5));
 
-    // hiding column 5 makes no difference
-    cs.hideColumns(5, 5);
-    assertEquals(5, cs.findColumnPosition(5));
-
     // hiding column 4 moves column 5 to column 4
     cs.hideColumns(4, 4);
     assertEquals(4, cs.findColumnPosition(5));
@@ -72,4 +92,474 @@ public class ColumnSelectionTest
     cs.hideColumns(1, 2);
     assertEquals(2, cs.findColumnPosition(5));
   }
+
+  /**
+   * Test the code used to locate the reference sequence ruler origin
+   */
+  @Test(groups = { "Functional" })
+  public void testLocateVisibleBoundsofSequence()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
+    assertEquals(2, seq.findIndex(seq.getStart()));
+
+    // no hidden columns
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    // hidden column on gap after end of sequence - should not affect bounds
+    cs.hideColumns(13);
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns();
+    // hidden column on gap before beginning of sequence - should vis bounds by
+    // one
+    cs.hideColumns(0);
+    assertEquals(
+            Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
+                seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
+                seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+    cs.revealAllHiddenColumns();
+    // hide columns around most of sequence - leave one residue remaining
+    cs.hideColumns(1, 3);
+    cs.hideColumns(6, 11);
+    assertEquals("-D",
+            cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
+    assertEquals(
+            Arrays.toString(new int[] { 1, 1, 3, 3,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+    cs.revealAllHiddenColumns();
+
+    // hide whole sequence - should just get location of hidden region
+    // containing sequence
+    cs.hideColumns(1, 11);
+    assertEquals(
+            Arrays.toString(new int[] { 0, 1, 0, 0,
+                seq.findIndex(seq.getStart()) - 1,
+                seq.findIndex(seq.getEnd()) - 1 }),
+            Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
+
+  }
+
+  @Test(groups={"Functional"})
+  public void testLocateVisibleBoundsPathologicals()
+  {
+    // test some pathological cases we missed
+    AlignmentI al = new Alignment(new SequenceI[] { new Sequence("refseqGaptest","KTDVTI----------NFI-----G----L")});
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideInsertionsFor(al.getSequenceAt(0));
+    assertEquals(
+            "G",
+            ""
+                    + al.getSequenceAt(0).getCharAt(
+                            cs.adjustForHiddenColumns(9)));
+
+
+  }
+  @Test(groups = { "Functional" })
+  public void testHideColumns()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideColumns(5);
+    List<int[]> hidden = cs.getHiddenColumns();
+    assertEquals(1, hidden.size());
+    assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
+
+    cs.hideColumns(3);
+    assertEquals(2, hidden.size());
+    // two hidden ranges, in order:
+    assertSame(hidden, cs.getHiddenColumns());
+    assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
+    assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
+
+    // hiding column 4 expands [3, 3] to [3, 4]
+    // not fancy enough to coalesce this into [3, 5] though
+    cs.hideColumns(4);
+    hidden = cs.getHiddenColumns();
+    assertEquals(2, hidden.size());
+    assertEquals("[3, 4]", Arrays.toString(hidden.get(0)));
+    assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
+
+    // clear hidden columns (note they are added to selected)
+    cs.revealAllHiddenColumns();
+    // it is now actually null but getter returns an empty list
+    assertTrue(cs.getHiddenColumns().isEmpty());
+
+    cs.hideColumns(3, 6);
+    hidden = cs.getHiddenColumns();
+    int[] firstHiddenRange = hidden.get(0);
+    assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
+
+    // adding a subrange of already hidden should do nothing
+    cs.hideColumns(4, 5);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
+    cs.hideColumns(3, 5);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
+    cs.hideColumns(4, 6);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
+    cs.hideColumns(3, 6);
+    assertEquals(1, hidden.size());
+    assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
+
+    cs.revealAllHiddenColumns();
+    cs.hideColumns(2, 4);
+    hidden = cs.getHiddenColumns();
+    assertEquals(1, hidden.size());
+    assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
+
+    // extend contiguous with 2 positions overlap
+    cs.hideColumns(3, 5);
+    assertEquals(1, hidden.size());
+    assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
+
+    // extend contiguous with 1 position overlap
+    cs.hideColumns(5, 6);
+    assertEquals(1, hidden.size());
+    assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
+
+    // extend contiguous with overlap both ends:
+    cs.hideColumns(1, 7);
+    assertEquals(1, hidden.size());
+    assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
+  }
+
+  /**
+   * Test the method that hides a specified column including any adjacent
+   * selected columns. This is a convenience method for the case where multiple
+   * column regions are selected and then hidden using menu option View | Hide |
+   * Selected Columns.
+   */
+  @Test(groups = { "Functional" })
+  public void testHideColumns_withSelection()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    // select columns 4-6
+    cs.addElement(4);
+    cs.addElement(5);
+    cs.addElement(6);
+    // hide column 5 (and adjacent):
+    cs.hideColumns(5);
+    // 4,5,6 now hidden:
+    List<int[]> hidden = cs.getHiddenColumns();
+    assertEquals(1, hidden.size());
+    assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+    // none now selected:
+    assertTrue(cs.getSelected().isEmpty());
+
+    // repeat, hiding column 4 (5 and 6)
+    cs = new ColumnSelection();
+    cs.addElement(4);
+    cs.addElement(5);
+    cs.addElement(6);
+    cs.hideColumns(4);
+    hidden = cs.getHiddenColumns();
+    assertEquals(1, hidden.size());
+    assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+    assertTrue(cs.getSelected().isEmpty());
+
+    // repeat, hiding column (4, 5 and) 6
+    cs = new ColumnSelection();
+    cs.addElement(4);
+    cs.addElement(5);
+    cs.addElement(6);
+    cs.hideColumns(6);
+    hidden = cs.getHiddenColumns();
+    assertEquals(1, hidden.size());
+    assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+    assertTrue(cs.getSelected().isEmpty());
+
+    // repeat, with _only_ adjacent columns selected
+    cs = new ColumnSelection();
+    cs.addElement(4);
+    cs.addElement(6);
+    cs.hideColumns(5);
+    hidden = cs.getHiddenColumns();
+    assertEquals(1, hidden.size());
+    assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
+    assertTrue(cs.getSelected().isEmpty());
+  }
+
+  /**
+   * Test the method that hides all (possibly disjoint) selected column ranges
+   */
+  @Test(groups = { "Functional" })
+  public void testHideSelectedColumns()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
+    for (int col : sel)
+    {
+      cs.addElement(col);
+    }
+    cs.hideColumns(15, 18);
+
+    cs.hideSelectedColumns();
+    assertTrue(cs.getSelected().isEmpty());
+    List<int[]> hidden = cs.getHiddenColumns();
+    assertEquals(4, hidden.size());
+    assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
+    assertEquals("[7, 9]", Arrays.toString(hidden.get(1)));
+    assertEquals("[15, 18]", Arrays.toString(hidden.get(2)));
+    assertEquals("[20, 22]", Arrays.toString(hidden.get(3)));
+  }
+
+  /**
+   * Test the method that gets runs of selected columns ordered by column. If
+   * this fails, HideSelectedColumns may also fail
+   */
+  @Test(groups = { "Functional" })
+  public void testGetSelectedRanges()
+  {
+    /*
+     * getSelectedRanges returns ordered columns regardless
+     * of the order in which they are added
+     */
+    ColumnSelection cs = new ColumnSelection();
+    int[] sel = { 4, 3, 7, 21, 9, 20, 8, 22, 2 };
+    for (int col : sel)
+    {
+      cs.addElement(col);
+    }
+    List<int[]> range;
+    range = cs.getSelectedRanges();
+    assertEquals(3, range.size());
+    assertEquals("[2, 4]", Arrays.toString(range.get(0)));
+    assertEquals("[7, 9]", Arrays.toString(range.get(1)));
+    assertEquals("[20, 22]", Arrays.toString(range.get(2)));
+    cs.addElement(0);
+    cs.addElement(1);
+    range = cs.getSelectedRanges();
+    assertEquals(3, range.size());
+    assertEquals("[0, 4]", Arrays.toString(range.get(0)));
+  }
+
+  /**
+   * Test the method that reveals a range of hidden columns given the start
+   * column of the range
+   */
+  @Test(groups = { "Functional" })
+  public void testRevealHiddenColumns()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideColumns(5, 8);
+    cs.addElement(10);
+    cs.revealHiddenColumns(5);
+    // hidden columns list now null but getter returns empty list:
+    assertTrue(cs.getHiddenColumns().isEmpty());
+    // revealed columns are marked as selected (added to selection):
+    assertEquals("[10, 5, 6, 7, 8]", cs.getSelected().toString());
+
+    // calling with a column other than the range start does nothing:
+    cs = new ColumnSelection();
+    cs.hideColumns(5, 8);
+    List<int[]> hidden = cs.getHiddenColumns();
+    cs.revealHiddenColumns(6);
+    assertSame(hidden, cs.getHiddenColumns());
+    assertTrue(cs.getSelected().isEmpty());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testRevealAllHiddenColumns()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideColumns(5, 8);
+    cs.hideColumns(2, 3);
+    cs.addElement(11);
+    cs.addElement(1);
+    cs.revealAllHiddenColumns();
+
+    /*
+     * revealing hidden columns adds them (in order) to the (unordered)
+     * selection list
+     */
+    assertTrue(cs.getHiddenColumns().isEmpty());
+    assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", cs.getSelected().toString());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testIsVisible()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideColumns(2, 4);
+    cs.hideColumns(6, 7);
+    assertTrue(cs.isVisible(0));
+    assertTrue(cs.isVisible(-99));
+    assertTrue(cs.isVisible(1));
+    assertFalse(cs.isVisible(2));
+    assertFalse(cs.isVisible(3));
+    assertFalse(cs.isVisible(4));
+    assertTrue(cs.isVisible(5));
+    assertFalse(cs.isVisible(6));
+    assertFalse(cs.isVisible(7));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testGetVisibleContigs()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.hideColumns(3, 6);
+    cs.hideColumns(8, 9);
+    cs.hideColumns(12, 12);
+
+    // start position is inclusive, end position exclusive:
+    int[] visible = cs.getVisibleContigs(1, 13);
+    assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
+
+    visible = cs.getVisibleContigs(4, 14);
+    assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
+
+    visible = cs.getVisibleContigs(3, 10);
+    assertEquals("[7, 7]", Arrays.toString(visible));
+
+    visible = cs.getVisibleContigs(4, 6);
+    assertEquals("[]", Arrays.toString(visible));
+  }
+
+  @Test(groups = { "Functional" })
+  public void testInvertColumnSelection()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(4);
+    cs.addElement(6);
+    cs.addElement(8);
+    cs.hideColumns(3, 3);
+    cs.hideColumns(6, 6);
+
+    // invert selection from start (inclusive) to end (exclusive)
+    // hidden columns are _not_ changed
+    cs.invertColumnSelection(2, 9);
+    assertEquals("[2, 5, 7]", cs.getSelected().toString());
+
+    cs.invertColumnSelection(1, 9);
+    assertEquals("[1, 4, 8]", cs.getSelected().toString());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testMaxColumnSelection()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(0);
+    cs.addElement(513);
+    cs.addElement(1);
+    assertEquals(513, cs.getMax());
+    cs.removeElement(513);
+    assertEquals(1, cs.getMax());
+    cs.removeElement(1);
+    assertEquals(0, cs.getMax());
+    cs.addElement(512);
+    cs.addElement(513);
+    assertEquals(513, cs.getMax());
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testMinColumnSelection()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(0);
+    cs.addElement(513);
+    cs.addElement(1);
+    assertEquals(0, cs.getMin());
+    cs.removeElement(0);
+    assertEquals(1, cs.getMin());
+    cs.addElement(0);
+    assertEquals(0, cs.getMin());
+  }
+
+  @Test(groups = { "Functional" })
+  public void testEquals()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    cs.addElement(0);
+    cs.addElement(513);
+    cs.addElement(1);
+    cs.hideColumns(3);
+    cs.hideColumns(7);
+    cs.hideColumns(5,9);
+
+    // same selections added in a different order
+    ColumnSelection cs2 = new ColumnSelection();
+    cs2.addElement(1);
+    cs2.addElement(513);
+    cs2.addElement(0);
+
+    // with no hidden columns
+    assertFalse(cs.equals(cs2));
+    assertFalse(cs2.equals(cs));
+
+    // with hidden columns added in a different order
+    cs2.hideColumns(6, 9);
+    cs2.hideColumns(5, 8);
+    cs2.hideColumns(3);
+    
+    assertTrue(cs.equals(cs2));
+    assertTrue(cs.equals(cs));
+    assertTrue(cs2.equals(cs));
+    assertTrue(cs2.equals(cs2));
+
+    cs2.addElement(12);
+    assertFalse(cs.equals(cs2));
+    assertFalse(cs2.equals(cs));
+
+    cs2.removeElement(12);
+    assertTrue(cs.equals(cs2));
+
+    cs2.hideColumns(88);
+    assertFalse(cs.equals(cs2));
+    /*
+     * unhiding a column adds it to selection!
+     */
+    cs2.revealHiddenColumns(88);
+    assertFalse(cs.equals(cs2));
+    cs.addElement(88);
+    assertTrue(cs.equals(cs2));
+  }
+
+  /**
+   * Test the method that returns selected columns, in the order in which they
+   * were added
+   */
+  @Test(groups = { "Functional" })
+  public void testGetSelection()
+  {
+    ColumnSelection cs = new ColumnSelection();
+    int[] sel = { 4, 3, 7, 21 };
+    for (int col : sel)
+    {
+      cs.addElement(col);
+    }
+    List<Integer> selected = cs.getSelected();
+    assertEquals(4, selected.size());
+    int i = 0;
+    for (int col : sel)
+    {
+      assertEquals(col, selected.get(i++).intValue());
+    }
+
+    cs.removeElement(7);
+    cs.addElement(1);
+    cs.removeElement(4);
+    selected = cs.getSelected();
+    assertEquals(3, selected.size());
+    assertEquals(3, selected.get(0).intValue());
+    assertEquals(21, selected.get(1).intValue());
+    assertEquals(1, selected.get(2).intValue());
+  }
 }