63f80b2126e1fe15b08101c80864489052089af9
[jalview.git] / test / jalview / datamodel / ColumnSelectionTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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.
11  *  
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.
16  * 
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.
20  */
21 package jalview.datamodel;
22
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
28 import java.util.Arrays;
29 import java.util.List;
30
31 import org.testng.annotations.Test;
32
33 public class ColumnSelectionTest
34 {
35
36   @Test(groups = { "Functional" })
37   public void testAddElement()
38   {
39     ColumnSelection cs = new ColumnSelection();
40     cs.addElement(2);
41     cs.addElement(5);
42     cs.addElement(3);
43     cs.addElement(5); // ignored
44     List<Integer> sel = cs.getSelected();
45     assertEquals("[2, 5, 3]", sel.toString());
46   }
47
48   /**
49    * Test the remove method - in particular to verify that remove(int i) removes
50    * the element whose value is i, _NOT_ the i'th element.
51    */
52   @Test(groups = { "Functional" })
53   public void testRemoveElement()
54   {
55     ColumnSelection cs = new ColumnSelection();
56     cs.addElement(2);
57     cs.addElement(5);
58
59     // removing elements not in the list has no effect
60     cs.removeElement(0);
61     cs.removeElement(1);
62     List<Integer> sel = cs.getSelected();
63     assertEquals(2, sel.size());
64     assertEquals(new Integer(2), sel.get(0));
65     assertEquals(new Integer(5), sel.get(1));
66
67     // removing an element in the list removes it
68     cs.removeElement(2);
69     assertEquals(1, sel.size());
70     assertEquals(new Integer(5), sel.get(0));
71   }
72
73   /**
74    * Test the method that finds the visible column position of an alignment
75    * column, allowing for hidden columns.
76    */
77   @Test(groups = { "Functional" })
78   public void testFindColumnPosition()
79   {
80     ColumnSelection cs = new ColumnSelection();
81     assertEquals(5, cs.findColumnPosition(5));
82
83     // hiding column 6 makes no difference
84     cs.hideColumns(6, 6);
85     assertEquals(5, cs.findColumnPosition(5));
86
87     // hiding column 4 moves column 5 to column 4
88     cs.hideColumns(4, 4);
89     assertEquals(4, cs.findColumnPosition(5));
90
91     // hiding columns 1 and 2 moves column 5 to column 2
92     cs.hideColumns(1, 2);
93     assertEquals(2, cs.findColumnPosition(5));
94   }
95
96   /**
97    * Test the code used to locate the reference sequence ruler origin
98    */
99   @Test(groups = { "Functional" })
100   public void testLocateVisibleBoundsofSequence()
101   {
102     ColumnSelection cs = new ColumnSelection();
103     SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---");
104     assertEquals(2, seq.findIndex(seq.getStart()));
105
106     // no hidden columns
107     assertEquals(
108             Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
109                 seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
110                 seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
111                 seq.findIndex(seq.getEnd()) - 1 }),
112             Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
113
114     // hidden column on gap after end of sequence - should not affect bounds
115     cs.hideColumns(13);
116     assertEquals(
117             Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1,
118                 seq.findIndex(seq.getEnd()) - 1, seq.getStart(),
119                 seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
120                 seq.findIndex(seq.getEnd()) - 1 }),
121             Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
122
123     cs.revealAllHiddenColumns();
124     // hidden column on gap before beginning of sequence - should vis bounds by
125     // one
126     cs.hideColumns(0);
127     assertEquals(
128             Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2,
129                 seq.findIndex(seq.getEnd()) - 2, seq.getStart(),
130                 seq.getEnd(), seq.findIndex(seq.getStart()) - 1,
131                 seq.findIndex(seq.getEnd()) - 1 }),
132             Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
133
134     cs.revealAllHiddenColumns();
135     // hide columns around most of sequence - leave one residue remaining
136     cs.hideColumns(1, 3);
137     cs.hideColumns(6, 11);
138     assertEquals("-D",
139             cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]);
140     assertEquals(
141             Arrays.toString(new int[] { 1, 1, 3, 3,
142                 seq.findIndex(seq.getStart()) - 1,
143                 seq.findIndex(seq.getEnd()) - 1 }),
144             Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
145     cs.revealAllHiddenColumns();
146
147     // hide whole sequence - should just get location of hidden region
148     // containing sequence
149     cs.hideColumns(1, 11);
150     assertEquals(
151             Arrays.toString(new int[] { 0, 1, 0, 0,
152                 seq.findIndex(seq.getStart()) - 1,
153                 seq.findIndex(seq.getEnd()) - 1 }),
154             Arrays.toString(cs.locateVisibleBoundsOfSequence(seq)));
155
156   }
157
158   @Test(groups = { "Functional" })
159   public void testHideColumns()
160   {
161     ColumnSelection cs = new ColumnSelection();
162     cs.hideColumns(5);
163     List<int[]> hidden = cs.getHiddenColumns();
164     assertEquals(1, hidden.size());
165     assertEquals("[5, 5]", Arrays.toString(hidden.get(0)));
166
167     cs.hideColumns(3);
168     assertEquals(2, hidden.size());
169     // two hidden ranges, in order:
170     assertSame(hidden, cs.getHiddenColumns());
171     assertEquals("[3, 3]", Arrays.toString(hidden.get(0)));
172     assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
173
174     // hiding column 4 expands [3, 3] to [3, 4]
175     // not fancy enough to coalesce this into [3, 5] though
176     cs.hideColumns(4);
177     hidden = cs.getHiddenColumns();
178     assertEquals(2, hidden.size());
179     assertEquals("[3, 4]", Arrays.toString(hidden.get(0)));
180     assertEquals("[5, 5]", Arrays.toString(hidden.get(1)));
181
182     // clear hidden columns (note they are added to selected)
183     cs.revealAllHiddenColumns();
184     // it is now actually null but getter returns an empty list
185     assertTrue(cs.getHiddenColumns().isEmpty());
186
187     cs.hideColumns(3, 6);
188     hidden = cs.getHiddenColumns();
189     int[] firstHiddenRange = hidden.get(0);
190     assertEquals("[3, 6]", Arrays.toString(firstHiddenRange));
191
192     // adding a subrange of already hidden should do nothing
193     cs.hideColumns(4, 5);
194     assertEquals(1, hidden.size());
195     assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
196     cs.hideColumns(3, 5);
197     assertEquals(1, hidden.size());
198     assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
199     cs.hideColumns(4, 6);
200     assertEquals(1, hidden.size());
201     assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
202     cs.hideColumns(3, 6);
203     assertEquals(1, hidden.size());
204     assertSame(firstHiddenRange, cs.getHiddenColumns().get(0));
205
206     cs.revealAllHiddenColumns();
207     cs.hideColumns(2, 4);
208     hidden = cs.getHiddenColumns();
209     assertEquals(1, hidden.size());
210     assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
211
212     // extend contiguous with 2 positions overlap
213     cs.hideColumns(3, 5);
214     assertEquals(1, hidden.size());
215     assertEquals("[2, 5]", Arrays.toString(hidden.get(0)));
216
217     // extend contiguous with 1 position overlap
218     cs.hideColumns(5, 6);
219     assertEquals(1, hidden.size());
220     assertEquals("[2, 6]", Arrays.toString(hidden.get(0)));
221
222     // extend contiguous with overlap both ends:
223     cs.hideColumns(1, 7);
224     assertEquals(1, hidden.size());
225     assertEquals("[1, 7]", Arrays.toString(hidden.get(0)));
226   }
227
228   /**
229    * Test the method that hides a specified column including any adjacent
230    * selected columns. This is a convenience method for the case where multiple
231    * column regions are selected and then hidden using menu option View | Hide |
232    * Selected Columns.
233    */
234   @Test(groups = { "Functional" })
235   public void testHideColumns_withSelection()
236   {
237     ColumnSelection cs = new ColumnSelection();
238     // select columns 4-6
239     cs.addElement(4);
240     cs.addElement(5);
241     cs.addElement(6);
242     // hide column 5 (and adjacent):
243     cs.hideColumns(5);
244     // 4,5,6 now hidden:
245     List<int[]> hidden = cs.getHiddenColumns();
246     assertEquals(1, hidden.size());
247     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
248     // none now selected:
249     assertTrue(cs.getSelected().isEmpty());
250
251     // repeat, hiding column 4 (5 and 6)
252     cs = new ColumnSelection();
253     cs.addElement(4);
254     cs.addElement(5);
255     cs.addElement(6);
256     cs.hideColumns(4);
257     hidden = cs.getHiddenColumns();
258     assertEquals(1, hidden.size());
259     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
260     assertTrue(cs.getSelected().isEmpty());
261
262     // repeat, hiding column (4, 5 and) 6
263     cs = new ColumnSelection();
264     cs.addElement(4);
265     cs.addElement(5);
266     cs.addElement(6);
267     cs.hideColumns(6);
268     hidden = cs.getHiddenColumns();
269     assertEquals(1, hidden.size());
270     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
271     assertTrue(cs.getSelected().isEmpty());
272
273     // repeat, with _only_ adjacent columns selected
274     cs = new ColumnSelection();
275     cs.addElement(4);
276     cs.addElement(6);
277     cs.hideColumns(5);
278     hidden = cs.getHiddenColumns();
279     assertEquals(1, hidden.size());
280     assertEquals("[4, 6]", Arrays.toString(hidden.get(0)));
281     assertTrue(cs.getSelected().isEmpty());
282   }
283
284   /**
285    * Test the method that hides all (possibly disjoint) selected column ranges
286    */
287   @Test(groups = { "Functional" })
288   public void testHideSelectedColumns()
289   {
290     ColumnSelection cs = new ColumnSelection();
291     int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
292     for (int col : sel)
293     {
294       cs.addElement(col);
295     }
296     cs.hideColumns(15, 18);
297
298     cs.hideSelectedColumns();
299     assertTrue(cs.getSelected().isEmpty());
300     List<int[]> hidden = cs.getHiddenColumns();
301     assertEquals(4, hidden.size());
302     assertEquals("[2, 4]", Arrays.toString(hidden.get(0)));
303     assertEquals("[7, 9]", Arrays.toString(hidden.get(1)));
304     assertEquals("[15, 18]", Arrays.toString(hidden.get(2)));
305     assertEquals("[20, 22]", Arrays.toString(hidden.get(3)));
306   }
307
308   /**
309    * Test the method that gets runs of selected columns ordered by column. If
310    * this fails, HideSelectedColumns may also fail
311    */
312   @Test(groups = { "Functional" })
313   public void testgetSelectedRanges()
314   {
315     ColumnSelection cs = new ColumnSelection();
316     int[] sel = { 2, 3, 4, 7, 8, 9, 20, 21, 22 };
317     for (int col : sel)
318     {
319       cs.addElement(col);
320     }
321     List<int[]> range;
322     range = cs.getSelectedRanges();
323     assertEquals(3, range.size());
324     assertEquals("[2, 4]", Arrays.toString(range.get(0)));
325     assertEquals("[7, 9]", Arrays.toString(range.get(1)));
326     assertEquals("[20, 22]", Arrays.toString(range.get(2)));
327     cs.addElement(0);
328     cs.addElement(1);
329     range = cs.getSelectedRanges();
330     assertEquals(3, range.size());
331     assertEquals("[0, 4]", Arrays.toString(range.get(0)));
332   }
333
334   /**
335    * Test the method that reveals a range of hidden columns given the start
336    * column of the range
337    */
338   @Test(groups = { "Functional" })
339   public void testRevealHiddenColumns()
340   {
341     ColumnSelection cs = new ColumnSelection();
342     cs.hideColumns(5, 8);
343     cs.addElement(10);
344     cs.revealHiddenColumns(5);
345     // hidden columns list now null but getter returns empty list:
346     assertTrue(cs.getHiddenColumns().isEmpty());
347     // revealed columns are marked as selected (added to selection):
348     assertEquals("[10, 5, 6, 7, 8]", cs.getSelected().toString());
349
350     // calling with a column other than the range start does nothing:
351     cs = new ColumnSelection();
352     cs.hideColumns(5, 8);
353     List<int[]> hidden = cs.getHiddenColumns();
354     cs.revealHiddenColumns(6);
355     assertSame(hidden, cs.getHiddenColumns());
356     assertTrue(cs.getSelected().isEmpty());
357   }
358
359   @Test(groups = { "Functional" })
360   public void testRevealAllHiddenColumns()
361   {
362     ColumnSelection cs = new ColumnSelection();
363     cs.hideColumns(5, 8);
364     cs.hideColumns(2, 3);
365     cs.addElement(11);
366     cs.addElement(1);
367     cs.revealAllHiddenColumns();
368
369     /*
370      * revealing hidden columns adds them (in order) to the (unordered)
371      * selection list
372      */
373     assertTrue(cs.getHiddenColumns().isEmpty());
374     assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", cs.getSelected().toString());
375   }
376
377   @Test(groups = { "Functional" })
378   public void testIsVisible()
379   {
380     ColumnSelection cs = new ColumnSelection();
381     cs.hideColumns(2, 4);
382     cs.hideColumns(6, 7);
383     assertTrue(cs.isVisible(0));
384     assertTrue(cs.isVisible(-99));
385     assertTrue(cs.isVisible(1));
386     assertFalse(cs.isVisible(2));
387     assertFalse(cs.isVisible(3));
388     assertFalse(cs.isVisible(4));
389     assertTrue(cs.isVisible(5));
390     assertFalse(cs.isVisible(6));
391     assertFalse(cs.isVisible(7));
392   }
393
394   @Test(groups = { "Functional" })
395   public void testGetVisibleContigs()
396   {
397     ColumnSelection cs = new ColumnSelection();
398     cs.hideColumns(3, 6);
399     cs.hideColumns(8, 9);
400     cs.hideColumns(12, 12);
401
402     // start position is inclusive, end position exclusive:
403     int[] visible = cs.getVisibleContigs(1, 13);
404     assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible));
405
406     visible = cs.getVisibleContigs(4, 14);
407     assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible));
408
409     visible = cs.getVisibleContigs(3, 10);
410     assertEquals("[7, 7]", Arrays.toString(visible));
411
412     visible = cs.getVisibleContigs(4, 6);
413     assertEquals("[]", Arrays.toString(visible));
414   }
415
416   @Test(groups = { "Functional" })
417   public void testInvertColumnSelection()
418   {
419     ColumnSelection cs = new ColumnSelection();
420     cs.addElement(4);
421     cs.addElement(6);
422     cs.addElement(8);
423     cs.hideColumns(3, 3);
424     cs.hideColumns(6, 6);
425
426     // invert selection from start (inclusive) to end (exclusive)
427     // hidden columns are _not_ changed
428     cs.invertColumnSelection(2, 9);
429     assertEquals("[2, 5, 7]", cs.getSelected().toString());
430
431     cs.invertColumnSelection(1, 9);
432     assertEquals("[1, 4, 8]", cs.getSelected().toString());
433   }
434
435   @Test(groups = { "Functional" })
436   public void testMaxColumnSelection()
437   {
438     ColumnSelection cs = new ColumnSelection();
439     cs.addElement(0);
440     cs.addElement(513);
441     cs.addElement(1);
442     assertEquals(513, cs.getMax());
443     cs.removeElement(513);
444     assertEquals(1, cs.getMax());
445     cs.removeElement(1);
446     assertEquals(0, cs.getMax());
447     cs.addElement(512);
448     cs.addElement(513);
449     assertEquals(513, cs.getMax());
450
451   }
452
453   @Test(groups = { "Functional" })
454   public void testMinColumnSelection()
455   {
456     ColumnSelection cs = new ColumnSelection();
457     cs.addElement(0);
458     cs.addElement(513);
459     cs.addElement(1);
460     assertEquals(0, cs.getMin());
461     cs.removeElement(0);
462     assertEquals(1, cs.getMin());
463     cs.addElement(0);
464     assertEquals(0, cs.getMin());
465   }
466 }