X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=test%2Fjalview%2Fdatamodel%2FColumnSelectionTest.java;h=4faa482755472640c20c223773f2418178f74344;hb=b4be31307e3a1e6d3dbb43bd14dfd012be6a3dfd;hp=1a7ae327fc6ac3be1c1d6d0b8bbc953d8c3088a1;hpb=528191d2feb45cd42c5b4f48420687346705119d;p=jalview.git diff --git a/test/jalview/datamodel/ColumnSelectionTest.java b/test/jalview/datamodel/ColumnSelectionTest.java index 1a7ae32..4faa482 100644 --- a/test/jalview/datamodel/ColumnSelectionTest.java +++ b/test/jalview/datamodel/ColumnSelectionTest.java @@ -24,15 +24,29 @@ 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 static org.testng.AssertJUnit.fail; + +import jalview.gui.JvOptionPane; import java.util.Arrays; +import java.util.BitSet; +import java.util.Collections; +import java.util.ConcurrentModificationException; import java.util.List; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class ColumnSelectionTest { + @BeforeClass(alwaysRun = true) + public void setUpJvOptionPane() + { + JvOptionPane.setInteractiveMode(false); + JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); + } + @Test(groups = { "Functional" }) public void testAddElement() { @@ -66,6 +80,9 @@ public class ColumnSelectionTest // removing an element in the list removes it cs.removeElement(2); + // ...and also from the read-only view + assertEquals(1, sel.size()); + sel = cs.getSelected(); assertEquals(1, sel.size()); assertEquals(new Integer(5), sel.get(0)); } @@ -155,11 +172,12 @@ public class ColumnSelectionTest } - @Test(groups={"Functional"}) + @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")}); + AlignmentI al = new Alignment(new SequenceI[] { new Sequence( + "refseqGaptest", "KTDVTI----------NFI-----G----L") }); ColumnSelection cs = new ColumnSelection(); cs.hideInsertionsFor(al.getSequenceAt(0)); assertEquals( @@ -168,8 +186,8 @@ public class ColumnSelectionTest + al.getSequenceAt(0).getCharAt( cs.adjustForHiddenColumns(9))); - } + @Test(groups = { "Functional" }) public void testHideColumns() { @@ -187,12 +205,11 @@ public class ColumnSelectionTest 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 + // and merges to [5, 5] to make [3, 5] 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))); + assertEquals(1, hidden.size()); + assertEquals("[3, 5]", Arrays.toString(hidden.get(0))); // clear hidden columns (note they are added to selected) cs.revealAllHiddenColumns(); @@ -325,10 +342,14 @@ public class ColumnSelectionTest * this fails, HideSelectedColumns may also fail */ @Test(groups = { "Functional" }) - public void testgetSelectedRanges() + public void testGetSelectedRanges() { + /* + * getSelectedRanges returns ordered columns regardless + * of the order in which they are added + */ ColumnSelection cs = new ColumnSelection(); - int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 }; + int[] sel = { 4, 3, 7, 21, 9, 20, 8, 22, 2 }; for (int col : sel) { cs.addElement(col); @@ -488,7 +509,7 @@ public class ColumnSelectionTest cs.addElement(1); cs.hideColumns(3); cs.hideColumns(7); - cs.hideColumns(5,9); + cs.hideColumns(5, 9); // same selections added in a different order ColumnSelection cs2 = new ColumnSelection(); @@ -504,7 +525,7 @@ public class ColumnSelectionTest cs2.hideColumns(6, 9); cs2.hideColumns(5, 8); cs2.hideColumns(3); - + assertTrue(cs.equals(cs2)); assertTrue(cs.equals(cs)); assertTrue(cs2.equals(cs)); @@ -527,4 +548,271 @@ public class ColumnSelectionTest 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 testGetSelected() + { + ColumnSelection cs = new ColumnSelection(); + int[] sel = { 4, 3, 7, 21 }; + for (int col : sel) + { + cs.addElement(col); + } + + List selected = cs.getSelected(); + assertEquals(4, selected.size()); + assertEquals("[4, 3, 7, 21]", selected.toString()); + + /* + * getSelected returns a read-only view of the list + * verify the view follows any changes in it + */ + cs.removeElement(7); + cs.addElement(1); + cs.removeElement(4); + assertEquals("[3, 21, 1]", selected.toString()); + } + + /** + * Test to verify that the list returned by getSelection cannot be modified + */ + @Test(groups = { "Functional" }) + public void testGetSelected_isReadOnly() + { + ColumnSelection cs = new ColumnSelection(); + cs.addElement(3); + + List selected = cs.getSelected(); + try + { + selected.clear(); + fail("expected exception"); + } catch (UnsupportedOperationException e) + { + // expected + } + try + { + selected.add(1); + fail("expected exception"); + } catch (UnsupportedOperationException e) + { + // expected + } + try + { + selected.remove(3); + fail("expected exception"); + } catch (UnsupportedOperationException e) + { + // expected + } + try + { + Collections.sort(selected); + fail("expected exception"); + } catch (UnsupportedOperationException e) + { + // expected + } + } + + /** + * Test that demonstrates a ConcurrentModificationException is thrown if you + * change the selection while iterating over it + */ + @Test( + groups = "Functional", + expectedExceptions = { ConcurrentModificationException.class }) + public void testGetSelected_concurrentModification() + { + ColumnSelection cs = new ColumnSelection(); + cs.addElement(0); + cs.addElement(1); + cs.addElement(2); + + /* + * simulate changing the list under us (e.g. in a separate + * thread) while iterating over it -> ConcurrentModificationException + */ + List selected = cs.getSelected(); + for (Integer col : selected) + { + if (col.intValue() == 0) + { + cs.removeElement(1); + } + } + } + + @Test(groups = "Functional") + public void testMarkColumns() + { + ColumnSelection cs = new ColumnSelection(); + cs.addElement(5); // this will be cleared + BitSet toMark = new BitSet(); + toMark.set(1); + toMark.set(3); + toMark.set(6); + toMark.set(9); + + assertTrue(cs.markColumns(toMark, 3, 8, false, false, false)); + List selected = cs.getSelected(); + assertEquals(2, selected.size()); + assertTrue(selected.contains(3)); + assertTrue(selected.contains(6)); + } + + @Test(groups = "Functional") + public void testMarkColumns_extend() + { + ColumnSelection cs = new ColumnSelection(); + cs.addElement(1); + cs.addElement(5); + BitSet toMark = new BitSet(); + toMark.set(1); + toMark.set(3); + toMark.set(6); + toMark.set(9); + + /* + * extending selection of {3, 6} should leave {1, 3, 5, 6} selected + */ + assertTrue(cs.markColumns(toMark, 3, 8, false, true, false)); + List selected = cs.getSelected(); + assertEquals(4, selected.size()); + assertTrue(selected.contains(1)); + assertTrue(selected.contains(3)); + assertTrue(selected.contains(5)); + assertTrue(selected.contains(6)); + } + + @Test(groups = "Functional") + public void testMarkColumns_invert() + { + ColumnSelection cs = new ColumnSelection(); + cs.addElement(5); // this will be cleared + BitSet toMark = new BitSet(); + toMark.set(1); + toMark.set(3); + toMark.set(6); + toMark.set(9); + + /* + * inverted selection of {3, 6} should select {4, 5, 7, 8} + */ + assertTrue(cs.markColumns(toMark, 3, 8, true, false, false)); + List selected = cs.getSelected(); + assertEquals(4, selected.size()); + assertTrue(selected.contains(4)); + assertTrue(selected.contains(5)); + assertTrue(selected.contains(7)); + assertTrue(selected.contains(8)); + } + + @Test(groups = "Functional") + public void testMarkColumns_toggle() + { + ColumnSelection cs = new ColumnSelection(); + cs.addElement(1); // outside change range + cs.addElement(3); + cs.addElement(4); + cs.addElement(10); // outside change range + BitSet toMark = new BitSet(); + toMark.set(1); + toMark.set(3); + toMark.set(6); + toMark.set(9); + + /* + * toggling state of {3, 6} should leave {1, 4, 6, 10} selected + */ + assertTrue(cs.markColumns(toMark, 3, 8, false, false, true)); + List selected = cs.getSelected(); + assertEquals(4, selected.size()); + assertTrue(selected.contains(1)); + assertTrue(selected.contains(4)); + assertTrue(selected.contains(6)); + assertTrue(selected.contains(10)); + } + + @Test(groups = "Functional") + public void testCopyConstructor() + { + ColumnSelection cs = new ColumnSelection(); + cs.addElement(3); + cs.addElement(1); + cs.hideColumns(10, 11); + cs.hideColumns(5, 7); + assertEquals("[5, 7]", Arrays.toString(cs.getHiddenColumns().get(0))); + + ColumnSelection cs2 = new ColumnSelection(cs); + assertTrue(cs2.hasSelectedColumns()); + assertTrue(cs2.hasHiddenColumns()); + // order of column selection is preserved + assertEquals("[3, 1]", cs2.getSelected().toString()); + assertEquals(2, cs2.getHiddenColumns().size()); + // hidden columns are held in column order + assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenColumns().get(0))); + assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenColumns().get(1))); + } + + /** + * Test for the case when a hidden range encloses more one already hidden + * range + */ + @Test(groups = { "Functional" }) + public void testHideColumns_subsumingHidden() + { + /* + * JAL-2370 bug scenario: + * two hidden ranges subsumed by a third + */ + ColumnSelection cs = new ColumnSelection(); + cs.hideColumns(49, 59); + cs.hideColumns(69, 79); + List hidden = cs.getHiddenColumns(); + assertEquals(2, hidden.size()); + assertEquals("[49, 59]", Arrays.toString(hidden.get(0))); + assertEquals("[69, 79]", Arrays.toString(hidden.get(1))); + + cs.hideColumns(48, 80); + hidden = cs.getHiddenColumns(); + assertEquals(1, hidden.size()); + assertEquals("[48, 80]", Arrays.toString(hidden.get(0))); + + /* + * another...joining hidden ranges + */ + cs = new ColumnSelection(); + cs.hideColumns(10, 20); + cs.hideColumns(30, 40); + cs.hideColumns(50, 60); + // hiding 21-49 should merge to one range + cs.hideColumns(21, 49); + hidden = cs.getHiddenColumns(); + assertEquals(1, hidden.size()); + assertEquals("[10, 60]", Arrays.toString(hidden.get(0))); + + /* + * another...lef overlap, subsumption, right overlap, + * no overlap of existing hidden ranges + */ + cs = new ColumnSelection(); + cs.hideColumns(10, 20); + cs.hideColumns(10, 20); + cs.hideColumns(30, 35); + cs.hideColumns(40, 50); + cs.hideColumns(60, 70); + + cs.hideColumns(15, 45); + hidden = cs.getHiddenColumns(); + assertEquals(2, hidden.size()); + assertEquals("[10, 50]", Arrays.toString(hidden.get(0))); + assertEquals("[60, 70]", Arrays.toString(hidden.get(1))); + } }