2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.datamodel;
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertSame;
26 import static org.testng.AssertJUnit.assertTrue;
27 import static org.testng.AssertJUnit.fail;
29 import java.util.Arrays;
30 import java.util.BitSet;
31 import java.util.Collections;
32 import java.util.ConcurrentModificationException;
33 import java.util.List;
35 import org.testng.annotations.Test;
37 public class ColumnSelectionTest
40 @Test(groups = { "Functional" })
41 public void testAddElement()
43 ColumnSelection cs = new ColumnSelection();
47 cs.addElement(5); // ignored
48 List<Integer> sel = cs.getSelected();
49 assertEquals("[2, 5, 3]", sel.toString());
53 * Test the remove method - in particular to verify that remove(int i) removes
54 * the element whose value is i, _NOT_ the i'th element.
56 @Test(groups = { "Functional" })
57 public void testRemoveElement()
59 ColumnSelection cs = new ColumnSelection();
63 // removing elements not in the list has no effect
66 List<Integer> sel = cs.getSelected();
67 assertEquals(2, sel.size());
68 assertEquals(new Integer(2), sel.get(0));
69 assertEquals(new Integer(5), sel.get(1));
71 // removing an element in the list removes it
73 // ...and also from the read-only view
74 assertEquals(1, sel.size());
75 sel = cs.getSelected();
76 assertEquals(1, sel.size());
77 assertEquals(new Integer(5), sel.get(0));
81 * Test the method that finds the visible column position of an alignment
82 * column, allowing for hidden columns.
84 @Test(groups = { "Functional" })
85 public void testFindColumnPosition()
87 ColumnSelection cs = new ColumnSelection();
88 assertEquals(5, cs.findColumnPosition(5));
90 // hiding column 6 makes no difference
92 assertEquals(5, cs.findColumnPosition(5));
94 // hiding column 4 moves column 5 to column 4
96 assertEquals(4, cs.findColumnPosition(5));
98 // hiding columns 1 and 2 moves column 5 to column 2
100 assertEquals(2, cs.findColumnPosition(5));
104 * Test the code used to locate the reference sequence ruler origin
106 @Test(groups = { "Functional" })
107 public void testLocateVisibleBoundsofSequence()
109 ColumnSelection cs = new ColumnSelection();
110 SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
111 assertEquals(2, seq.findIndex(seq.getStart()));
115 Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
116 seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
117 seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
118 seq.findIndex(seq.getEnd()) - 1 }),
119 Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
121 // hidden column on gap after end of sequence - should not affect bounds
124 Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
125 seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
126 seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
127 seq.findIndex(seq.getEnd()) - 1 }),
128 Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
130 cs.revealAllHiddenColumns();
131 // hidden column on gap before beginning of sequence - should vis bounds by
135 Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
136 seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
137 seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
138 seq.findIndex(seq.getEnd()) - 1 }),
139 Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
141 cs.revealAllHiddenColumns();
142 // hide columns around most of sequence - leave one residue remaining
143 cs.hideColumns(1, 3);
144 cs.hideColumns(6, 11);
146 cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
148 Arrays.toString(new int[] { 1, 1, 3, 3,
149 seq.findIndex(seq.getStart()) - 1,
150 seq.findIndex(seq.getEnd()) - 1 }),
151 Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
152 cs.revealAllHiddenColumns();
154 // hide whole sequence - should just get location of hidden region
155 // containing sequence
156 cs.hideColumns(1, 11);
158 Arrays.toString(new int[] { 0, 1, 0, 0,
159 seq.findIndex(seq.getStart()) - 1,
160 seq.findIndex(seq.getEnd()) - 1 }),
161 Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
165 @Test(groups = { "Functional" })
166 public void testLocateVisibleBoundsPathologicals()
168 // test some pathological cases we missed
169 AlignmentI al = new Alignment(new SequenceI[] { new Sequence(
170 "refseqGaptest", "KTDVTI----------NFI-----G----L") });
171 ColumnSelection cs = new ColumnSelection();
172 cs.hideInsertionsFor(al.getSequenceAt(0));
176 + al.getSequenceAt(0).getCharAt(
177 cs.adjustForHiddenColumns(9)));
181 @Test(groups = { "Functional" })
182 public void testHideColumns()
184 ColumnSelection cs = new ColumnSelection();
186 List<int[]> hidden = cs.getHiddenColumns();
187 assertEquals(1, hidden.size());
188 assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
191 assertEquals(2, hidden.size());
192 // two hidden ranges, in order:
193 assertSame(hidden, cs.getHiddenColumns());
194 assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
195 assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
197 // hiding column 4 expands [3, 3] to [3, 4]
198 // not fancy enough to coalesce this into [3, 5] though
200 hidden = cs.getHiddenColumns();
201 assertEquals(2, hidden.size());
202 assertEquals("[3, 4]", Arrays.toString(hidden.get(0)));
203 assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
205 // clear hidden columns (note they are added to selected)
206 cs.revealAllHiddenColumns();
207 // it is now actually null but getter returns an empty list
208 assertTrue(cs.getHiddenColumns().isEmpty());
210 cs.hideColumns(3, 6);
211 hidden = cs.getHiddenColumns();
212 int[] firstHiddenRange = hidden.get(0);
213 assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
215 // adding a subrange of already hidden should do nothing
216 cs.hideColumns(4, 5);
217 assertEquals(1, hidden.size());
218 assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
219 cs.hideColumns(3, 5);
220 assertEquals(1, hidden.size());
221 assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
222 cs.hideColumns(4, 6);
223 assertEquals(1, hidden.size());
224 assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
225 cs.hideColumns(3, 6);
226 assertEquals(1, hidden.size());
227 assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
229 cs.revealAllHiddenColumns();
230 cs.hideColumns(2, 4);
231 hidden = cs.getHiddenColumns();
232 assertEquals(1, hidden.size());
233 assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
235 // extend contiguous with 2 positions overlap
236 cs.hideColumns(3, 5);
237 assertEquals(1, hidden.size());
238 assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
240 // extend contiguous with 1 position overlap
241 cs.hideColumns(5, 6);
242 assertEquals(1, hidden.size());
243 assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
245 // extend contiguous with overlap both ends:
246 cs.hideColumns(1, 7);
247 assertEquals(1, hidden.size());
248 assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
252 * Test the method that hides a specified column including any adjacent
253 * selected columns. This is a convenience method for the case where multiple
254 * column regions are selected and then hidden using menu option View | Hide |
257 @Test(groups = { "Functional" })
258 public void testHideColumns_withSelection()
260 ColumnSelection cs = new ColumnSelection();
261 // select columns 4-6
265 // hide column 5 (and adjacent):
268 List<int[]> hidden = cs.getHiddenColumns();
269 assertEquals(1, hidden.size());
270 assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
271 // none now selected:
272 assertTrue(cs.getSelected().isEmpty());
274 // repeat, hiding column 4 (5 and 6)
275 cs = new ColumnSelection();
280 hidden = cs.getHiddenColumns();
281 assertEquals(1, hidden.size());
282 assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
283 assertTrue(cs.getSelected().isEmpty());
285 // repeat, hiding column (4, 5 and) 6
286 cs = new ColumnSelection();
291 hidden = cs.getHiddenColumns();
292 assertEquals(1, hidden.size());
293 assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
294 assertTrue(cs.getSelected().isEmpty());
296 // repeat, with _only_ adjacent columns selected
297 cs = new ColumnSelection();
301 hidden = cs.getHiddenColumns();
302 assertEquals(1, hidden.size());
303 assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
304 assertTrue(cs.getSelected().isEmpty());
308 * Test the method that hides all (possibly disjoint) selected column ranges
310 @Test(groups = { "Functional" })
311 public void testHideSelectedColumns()
313 ColumnSelection cs = new ColumnSelection();
314 int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
319 cs.hideColumns(15, 18);
321 cs.hideSelectedColumns();
322 assertTrue(cs.getSelected().isEmpty());
323 List<int[]> hidden = cs.getHiddenColumns();
324 assertEquals(4, hidden.size());
325 assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
326 assertEquals("[7, 9]", Arrays.toString(hidden.get(1)));
327 assertEquals("[15, 18]", Arrays.toString(hidden.get(2)));
328 assertEquals("[20, 22]", Arrays.toString(hidden.get(3)));
332 * Test the method that gets runs of selected columns ordered by column. If
333 * this fails, HideSelectedColumns may also fail
335 @Test(groups = { "Functional" })
336 public void testGetSelectedRanges()
339 * getSelectedRanges returns ordered columns regardless
340 * of the order in which they are added
342 ColumnSelection cs = new ColumnSelection();
343 int[] sel = { 4, 3, 7, 21, 9, 20, 8, 22, 2 };
349 range = cs.getSelectedRanges();
350 assertEquals(3, range.size());
351 assertEquals("[2, 4]", Arrays.toString(range.get(0)));
352 assertEquals("[7, 9]", Arrays.toString(range.get(1)));
353 assertEquals("[20, 22]", Arrays.toString(range.get(2)));
356 range = cs.getSelectedRanges();
357 assertEquals(3, range.size());
358 assertEquals("[0, 4]", Arrays.toString(range.get(0)));
362 * Test the method that reveals a range of hidden columns given the start
363 * column of the range
365 @Test(groups = { "Functional" })
366 public void testRevealHiddenColumns()
368 ColumnSelection cs = new ColumnSelection();
369 cs.hideColumns(5, 8);
371 cs.revealHiddenColumns(5);
372 // hidden columns list now null but getter returns empty list:
373 assertTrue(cs.getHiddenColumns().isEmpty());
374 // revealed columns are marked as selected (added to selection):
375 assertEquals("[10, 5, 6, 7, 8]", cs.getSelected().toString());
377 // calling with a column other than the range start does nothing:
378 cs = new ColumnSelection();
379 cs.hideColumns(5, 8);
380 List<int[]> hidden = cs.getHiddenColumns();
381 cs.revealHiddenColumns(6);
382 assertSame(hidden, cs.getHiddenColumns());
383 assertTrue(cs.getSelected().isEmpty());
386 @Test(groups = { "Functional" })
387 public void testRevealAllHiddenColumns()
389 ColumnSelection cs = new ColumnSelection();
390 cs.hideColumns(5, 8);
391 cs.hideColumns(2, 3);
394 cs.revealAllHiddenColumns();
397 * revealing hidden columns adds them (in order) to the (unordered)
400 assertTrue(cs.getHiddenColumns().isEmpty());
401 assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", cs.getSelected().toString());
404 @Test(groups = { "Functional" })
405 public void testIsVisible()
407 ColumnSelection cs = new ColumnSelection();
408 cs.hideColumns(2, 4);
409 cs.hideColumns(6, 7);
410 assertTrue(cs.isVisible(0));
411 assertTrue(cs.isVisible(-99));
412 assertTrue(cs.isVisible(1));
413 assertFalse(cs.isVisible(2));
414 assertFalse(cs.isVisible(3));
415 assertFalse(cs.isVisible(4));
416 assertTrue(cs.isVisible(5));
417 assertFalse(cs.isVisible(6));
418 assertFalse(cs.isVisible(7));
421 @Test(groups = { "Functional" })
422 public void testGetVisibleContigs()
424 ColumnSelection cs = new ColumnSelection();
425 cs.hideColumns(3, 6);
426 cs.hideColumns(8, 9);
427 cs.hideColumns(12, 12);
429 // start position is inclusive, end position exclusive:
430 int[] visible = cs.getVisibleContigs(1, 13);
431 assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
433 visible = cs.getVisibleContigs(4, 14);
434 assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
436 visible = cs.getVisibleContigs(3, 10);
437 assertEquals("[7, 7]", Arrays.toString(visible));
439 visible = cs.getVisibleContigs(4, 6);
440 assertEquals("[]", Arrays.toString(visible));
443 @Test(groups = { "Functional" })
444 public void testInvertColumnSelection()
446 ColumnSelection cs = new ColumnSelection();
450 cs.hideColumns(3, 3);
451 cs.hideColumns(6, 6);
453 // invert selection from start (inclusive) to end (exclusive)
454 // hidden columns are _not_ changed
455 cs.invertColumnSelection(2, 9);
456 assertEquals("[2, 5, 7]", cs.getSelected().toString());
458 cs.invertColumnSelection(1, 9);
459 assertEquals("[1, 4, 8]", cs.getSelected().toString());
462 @Test(groups = { "Functional" })
463 public void testMaxColumnSelection()
465 ColumnSelection cs = new ColumnSelection();
469 assertEquals(513, cs.getMax());
470 cs.removeElement(513);
471 assertEquals(1, cs.getMax());
473 assertEquals(0, cs.getMax());
476 assertEquals(513, cs.getMax());
480 @Test(groups = { "Functional" })
481 public void testMinColumnSelection()
483 ColumnSelection cs = new ColumnSelection();
487 assertEquals(0, cs.getMin());
489 assertEquals(1, cs.getMin());
491 assertEquals(0, cs.getMin());
494 @Test(groups = { "Functional" })
495 public void testEquals()
497 ColumnSelection cs = new ColumnSelection();
503 cs.hideColumns(5, 9);
505 // same selections added in a different order
506 ColumnSelection cs2 = new ColumnSelection();
511 // with no hidden columns
512 assertFalse(cs.equals(cs2));
513 assertFalse(cs2.equals(cs));
515 // with hidden columns added in a different order
516 cs2.hideColumns(6, 9);
517 cs2.hideColumns(5, 8);
520 assertTrue(cs.equals(cs2));
521 assertTrue(cs.equals(cs));
522 assertTrue(cs2.equals(cs));
523 assertTrue(cs2.equals(cs2));
526 assertFalse(cs.equals(cs2));
527 assertFalse(cs2.equals(cs));
529 cs2.removeElement(12);
530 assertTrue(cs.equals(cs2));
533 assertFalse(cs.equals(cs2));
535 * unhiding a column adds it to selection!
537 cs2.revealHiddenColumns(88);
538 assertFalse(cs.equals(cs2));
540 assertTrue(cs.equals(cs2));
544 * Test the method that returns selected columns, in the order in which they
547 @Test(groups = { "Functional" })
548 public void testGetSelected()
550 ColumnSelection cs = new ColumnSelection();
551 int[] sel = { 4, 3, 7, 21 };
557 List<Integer> selected = cs.getSelected();
558 assertEquals(4, selected.size());
559 assertEquals("[4, 3, 7, 21]", selected.toString());
562 * getSelected returns a read-only view of the list
563 * verify the view follows any changes in it
568 assertEquals("[3, 21, 1]", selected.toString());
572 * Test to verify that the list returned by getSelection cannot be modified
574 @Test(groups = { "Functional" })
575 public void testGetSelected_isReadOnly()
577 ColumnSelection cs = new ColumnSelection();
580 List<Integer> selected = cs.getSelected();
584 fail("expected exception");
585 } catch (UnsupportedOperationException e)
592 fail("expected exception");
593 } catch (UnsupportedOperationException e)
600 fail("expected exception");
601 } catch (UnsupportedOperationException e)
607 Collections.sort(selected);
608 fail("expected exception");
609 } catch (UnsupportedOperationException e)
616 * Test that demonstrates a ConcurrentModificationException is thrown if you
617 * change the selection while iterating over it
620 groups = "Functional",
621 expectedExceptions = { ConcurrentModificationException.class })
622 public void testGetSelected_concurrentModification()
624 ColumnSelection cs = new ColumnSelection();
630 * simulate changing the list under us (e.g. in a separate
631 * thread) while iterating over it -> ConcurrentModificationException
633 List<Integer> selected = cs.getSelected();
634 for (Integer col : selected)
636 if (col.intValue() == 0)
643 @Test(groups = "Functional")
644 public void testMarkColumns()
646 ColumnSelection cs = new ColumnSelection();
647 cs.addElement(5); // this will be cleared
648 BitSet toMark = new BitSet();
654 assertTrue(cs.markColumns(toMark, 3, 8, false, false, false));
655 List<Integer> selected = cs.getSelected();
656 assertEquals(2, selected.size());
657 assertTrue(selected.contains(3));
658 assertTrue(selected.contains(6));
661 @Test(groups = "Functional")
662 public void testMarkColumns_extend()
664 ColumnSelection cs = new ColumnSelection();
667 BitSet toMark = new BitSet();
674 * extending selection of {3, 6} should leave {1, 3, 5, 6} selected
676 assertTrue(cs.markColumns(toMark, 3, 8, false, true, false));
677 List<Integer> selected = cs.getSelected();
678 assertEquals(4, selected.size());
679 assertTrue(selected.contains(1));
680 assertTrue(selected.contains(3));
681 assertTrue(selected.contains(5));
682 assertTrue(selected.contains(6));
685 @Test(groups = "Functional")
686 public void testMarkColumns_invert()
688 ColumnSelection cs = new ColumnSelection();
689 cs.addElement(5); // this will be cleared
690 BitSet toMark = new BitSet();
697 * inverted selection of {3, 6} should select {4, 5, 7, 8}
699 assertTrue(cs.markColumns(toMark, 3, 8, true, false, false));
700 List<Integer> selected = cs.getSelected();
701 assertEquals(4, selected.size());
702 assertTrue(selected.contains(4));
703 assertTrue(selected.contains(5));
704 assertTrue(selected.contains(7));
705 assertTrue(selected.contains(8));
708 @Test(groups = "Functional")
709 public void testMarkColumns_toggle()
711 ColumnSelection cs = new ColumnSelection();
712 cs.addElement(1); // outside change range
715 cs.addElement(10); // outside change range
716 BitSet toMark = new BitSet();
723 * toggling state of {3, 6} should leave {1, 4, 6, 10} selected
725 assertTrue(cs.markColumns(toMark, 3, 8, false, false, true));
726 List<Integer> selected = cs.getSelected();
727 assertEquals(4, selected.size());
728 assertTrue(selected.contains(1));
729 assertTrue(selected.contains(4));
730 assertTrue(selected.contains(6));
731 assertTrue(selected.contains(10));
734 @Test(groups = "Functional")
735 public void testCopyConstructor()
737 ColumnSelection cs = new ColumnSelection();
740 cs.hideColumns(10, 11);
741 cs.hideColumns(5, 7);
742 assertEquals("[5, 7]", Arrays.toString(cs.getHiddenColumns().get(0)));
744 ColumnSelection cs2 = new ColumnSelection(cs);
745 assertTrue(cs2.hasSelectedColumns());
746 assertTrue(cs2.hasHiddenColumns());
747 // order of column selection is preserved
748 assertEquals("[3, 1]", cs2.getSelected().toString());
749 assertEquals(2, cs2.getHiddenColumns().size());
750 // hidden columns are held in column order
751 assertEquals("[5, 7]", Arrays.toString(cs2.getHiddenColumns().get(0)));
752 assertEquals("[10, 11]", Arrays.toString(cs2.getHiddenColumns().get(1)));