74c2b63cb923d58ce4b3df6cccd3e5992845ebee
[jalview.git] / test / jalview / datamodel / AlignmentAnnotationTests.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 jalview.analysis.AlignSeq;
24 import jalview.gui.JvOptionPane;
25 import jalview.io.AppletFormatAdapter;
26 import jalview.io.FileFormat;
27 import org.testng.Assert;
28 import org.testng.annotations.BeforeClass;
29 import org.testng.annotations.Test;
30
31 import static jalview.datamodel.Annotation.EMPTY_ANNOTATION;
32 import static jalview.testutils.Matchers.matchesAnnotations;
33 import static org.hamcrest.MatcherAssert.assertThat;
34 import static org.hamcrest.Matchers.*;
35 import static org.testng.Assert.assertNull;
36 import static org.testng.AssertJUnit.assertEquals;
37
38 public class AlignmentAnnotationTests
39 {
40
41   @BeforeClass(alwaysRun = true)
42   public void setUpJvOptionPane()
43   {
44     JvOptionPane.setInteractiveMode(false);
45     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
46   }
47
48   @Test(groups = { "Functional" })
49   public void testCopyConstructor()
50   {
51     SequenceI sq = new Sequence("Foo", "ARAARARARAWEAWEAWRAWEAWE");
52     createAnnotation(sq);
53     AlignmentAnnotation alc, alo = sq.getAnnotation()[0];
54     alc = new AlignmentAnnotation(alo);
55
56     // TODO: this only tests string equals (which is unreliable), should use
57     // refactored tests from StockholmFileTest
58     Assert.assertEquals(alc.toString(), alo.toString());
59
60     for (String key : alo.getProperties())
61     {
62       assertEquals("Property mismatch", alo.getProperty(key),
63           alc.getProperty(key));
64     }
65   }
66
67   /**
68    * create some dummy annotation derived from the sequence
69    * 
70    * @param sq
71    */
72   public static void createAnnotation(SequenceI sq)
73   {
74     Annotation[] al = new Annotation[sq.getLength()];
75     for (int i = 0; i < al.length; i++)
76     {
77       al[i] = new Annotation(new Annotation("" + sq.getCharAt(i), "", (char) 0,
78           sq.findPosition(i)));
79     }
80     AlignmentAnnotation alan = new AlignmentAnnotation("For " + sq.getName(),
81         "Fake alignment annot", al);
82     // create a sequence mapping for the annotation vector in its current state
83     alan.createSequenceMapping(sq, sq.getStart(), false);
84     alan.setProperty("CreatedBy", "createAnnotation");
85     sq.addAlignmentAnnotation(alan);
86   }
87
88   /**
89    * use this to test annotation derived from method above as it is transferred
90    * across different sequences derived from same dataset coordinate frame
91    * 
92    * @param ala
93    */
94   public static void testAnnotTransfer(AlignmentAnnotation ala)
95   {
96     assertEquals("Failed - need annotation created by createAnnotation method",
97         ala.description, "Fake alignment annot");
98     ala.adjustForAlignment();
99     for (int p = 0; p < ala.annotations.length; p++)
100     {
101       if (ala.annotations[p] != null)
102       {
103         assertEquals(
104             "Mismatch at position " + p
105                 + " between annotation position value and sequence"
106                 + ala.annotations[p],
107             (int) ala.annotations[p].value, ala.sequenceRef.findPosition(p));
108       }
109     }
110   }
111
112   /**
113    * Tests the liftOver method and also exercises the functions for remapping
114    * annotation across different reference sequences. Here, the test is between
115    * different dataset frames (annotation transferred by mapping between
116    * sequences)
117    */
118   @Test(groups = { "Functional" })
119   public void testLiftOver()
120   {
121     SequenceI sqFrom = new Sequence("fromLong", "QQQCDEWGH");
122     sqFrom.setStart(10);
123     sqFrom.setEnd(sqFrom.findPosition(sqFrom.getLength() - 1));
124     SequenceI sqTo = new Sequence("toShort", "RCDEW");
125     sqTo.setStart(20);
126     sqTo.setEnd(sqTo.findPosition(sqTo.getLength() - 1));
127     createAnnotation(sqTo);
128     AlignmentAnnotation origTo = sqTo.getAnnotation()[0];
129     createAnnotation(sqFrom);
130     AlignmentAnnotation origFrom = sqFrom.getAnnotation()[0];
131     AlignSeq align = AlignSeq.doGlobalNWAlignment(sqFrom, sqTo, AlignSeq.PEP);
132     SequenceI alSeq1 = new Sequence(sqFrom.getName(), align.getAStr1());
133     alSeq1.setStart(sqFrom.getStart() + align.getSeq1Start() - 1);
134     alSeq1.setEnd(sqFrom.getStart() + align.getSeq1End() - 1);
135     alSeq1.setDatasetSequence(sqFrom);
136     SequenceI alSeq2 = new Sequence(sqTo.getName(), align.getAStr2());
137     alSeq2.setStart(sqTo.getStart() + align.getSeq2Start() - 1);
138     alSeq2.setEnd(sqTo.getStart() + align.getSeq2End() - 1);
139     alSeq2.setDatasetSequence(sqTo);
140     System.out
141         .println(new AppletFormatAdapter()
142             .formatSequences(FileFormat.Stockholm,
143                 new Alignment(new SequenceI[] { sqFrom, alSeq1, sqTo, alSeq2 }),
144                 true));
145
146     Mapping mp = align.getMappingFromS1(false);
147
148     AlignmentAnnotation almap1 = new AlignmentAnnotation(
149         sqTo.getAnnotation()[0]);
150     almap1.liftOver(sqFrom, mp);
151     assertEquals(almap1.sequenceRef, sqFrom);
152     alSeq1.addAlignmentAnnotation(almap1);
153     almap1.setSequenceRef(alSeq1);
154     almap1.adjustForAlignment();
155     AlignmentAnnotation almap2 = new AlignmentAnnotation(
156         sqFrom.getAnnotation()[0]);
157     almap2.liftOver(sqTo, mp);
158     assertEquals(almap2.sequenceRef, sqTo);
159
160     alSeq2.addAlignmentAnnotation(almap2);
161     almap2.setSequenceRef(alSeq2);
162     almap2.adjustForAlignment();
163
164     AlignmentI all = new Alignment(new SequenceI[] { alSeq1, alSeq2 });
165     all.addAnnotation(almap1);
166     all.addAnnotation(almap2);
167     System.out
168         .println(new AppletFormatAdapter()
169             .formatSequences(FileFormat.Stockholm, all, true));
170
171     for (int p = 0; p < alSeq1.getLength(); p++)
172     {
173       Annotation orig1, trans1, orig2, trans2;
174       trans2 = almap2.annotations[p];
175       orig2 = origFrom.annotations[alSeq1.findPosition(p) - sqFrom.getStart()];
176       orig1 = origTo.annotations[alSeq2.findPosition(p) - sqTo.getStart()];
177       trans1 = almap1.annotations[p];
178       if (trans1 == trans2)
179       {
180         System.out.println("Pos " + p + " mismatch");
181         continue;
182       }
183       assertEquals("Mismatch on Original From and transferred annotation on 2",
184           (orig2 != null) ? orig2.toString() : null,
185           (trans2 != null) ? trans2.toString() : null);
186       assertEquals("Mismatch on Original To and transferred annotation on 1",
187           (orig1 != null) ? orig1.toString() : null,
188           (trans1 != null) ? trans1.toString() : null);
189       String alm1 = "" + (almap1.annotations.length > p
190           ? almap1.annotations[p].displayCharacter
191           : "Out of range");
192       String alm2 = "" + (almap2.annotations.length > p
193           ? almap2.annotations[p].displayCharacter
194           : "Out of range");
195       assertEquals("Position " + p + " " + alm1 + " " + alm2, alm1, alm2);
196     }
197   }
198
199   @Test(groups = { "Functional" })
200   public void testAdjustForAlignment()
201   {
202     SequenceI seq = new Sequence("TestSeq", "ABCDEFG");
203     seq.createDatasetSequence();
204
205     /*
206      * Annotate positions 3/4/5 (CDE) with values 1/2/3
207      */
208     Annotation[] anns = new Annotation[] {
209         null, null, new Annotation(1), new Annotation(2), new Annotation(3) };
210     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
211         "secondary structure", anns);
212     seq.addAlignmentAnnotation(ann);
213
214     /*
215      * Check annotation map before modifying aligned sequence
216      */
217     assertNull(ann.getAnnotationForPosition(1));
218     assertNull(ann.getAnnotationForPosition(2));
219     assertNull(ann.getAnnotationForPosition(6));
220     assertNull(ann.getAnnotationForPosition(7));
221     assertEquals(1, ann.getAnnotationForPosition(3).value, 0.001d);
222     assertEquals(2, ann.getAnnotationForPosition(4).value, 0.001d);
223     assertEquals(3, ann.getAnnotationForPosition(5).value, 0.001d);
224
225     /*
226      * Trim the displayed sequence to BCD and adjust annotations
227      */
228     seq.setSequence("BCD");
229     seq.setStart(2);
230     seq.setEnd(4);
231     ann.adjustForAlignment();
232
233     /*
234      * Should now have annotations for aligned positions 2, 3Q (CD) only
235      */
236     assertEquals(3, ann.annotations.length);
237     assertNull(ann.annotations[0]);
238     assertEquals(1, ann.annotations[1].value, 0.001);
239     assertEquals(2, ann.annotations[2].value, 0.001);
240   }
241
242   /**
243    * Test the method that defaults rna symbol to the one matching the preceding
244    * unmatched opening bracket (if any)
245    */
246   @Test(groups = { "Functional" })
247   public void testGetDefaultRnaHelixSymbol()
248   {
249     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
250         "secondary structure", null);
251     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
252
253     Annotation[] anns = new Annotation[20];
254     ann.annotations = anns;
255     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
256
257     anns[1] = new Annotation("(", "S", '(', 0f);
258     assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
259     assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
260     assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
261     assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
262
263     /*
264      * .(.[.{.<.}.>.).].
265      */
266     anns[1] = new Annotation("(", "S", '(', 0f);
267     anns[3] = new Annotation("[", "S", '[', 0f);
268     anns[5] = new Annotation("{", "S", '{', 0f);
269     anns[7] = new Annotation("<", "S", '<', 0f);
270     anns[9] = new Annotation("}", "S", '}', 0f);
271     anns[11] = new Annotation(">", "S", '>', 0f);
272     anns[13] = new Annotation(")", "S", ')', 0f);
273     anns[15] = new Annotation("]", "S", ']', 0f);
274
275     String expected = "(())]]}}>>>>]]]](";
276     for (int i = 0; i < expected.length(); i++)
277     {
278       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
279           ann.getDefaultRnaHelixSymbol(i));
280     }
281
282     /*
283      * .(.[.(.).{.}.<.].D.
284      */
285     anns[1] = new Annotation("(", "S", '(', 0f);
286     anns[3] = new Annotation("[", "S", '[', 0f);
287     anns[5] = new Annotation("(", "S", '(', 0f);
288     anns[7] = new Annotation(")", "S", ')', 0f);
289     anns[9] = new Annotation("{", "S", '{', 0f);
290     anns[11] = new Annotation("}", "S", '}', 0f);
291     anns[13] = new Annotation("<", "S", '>', 0f);
292     anns[15] = new Annotation("]", "S", ']', 0f);
293     anns[17] = new Annotation("D", "S", 'D', 0f);
294
295     expected = "(())]]))]]}}]]>>>>dd";
296     for (int i = 0; i < expected.length(); i++)
297     {
298       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
299           ann.getDefaultRnaHelixSymbol(i));
300     }
301   }
302
303   public static Annotation newAnnotation(String ann)
304   {
305     float val = 0f;
306     try
307     {
308       val = Float.parseFloat(ann);
309     } catch (NumberFormatException q)
310     {
311     }
312     ;
313     return new Annotation(ann, ann, '\0', val);
314   }
315
316   @Test(groups = { "Functional" })
317   public void testIsQuantitative()
318   {
319     AlignmentAnnotation ann = null;
320
321     ann = new AlignmentAnnotation("an", "some an", null);
322     Assert
323         .assertFalse(ann.isQuantitative(),
324             "Empty annotation set should not be quantitative.");
325
326     ann = new AlignmentAnnotation("an", "some an",
327         new Annotation[] {
328             newAnnotation("4"), newAnnotation("1"), newAnnotation("1"),
329             newAnnotation("0.1"), newAnnotation("0.3") });
330     Assert
331         .assertTrue(ann.isQuantitative(),
332             "All numbers annotation set should be quantitative.");
333
334     ann = new AlignmentAnnotation("an", "some an",
335         new Annotation[] {
336             newAnnotation("E"), newAnnotation("E"), newAnnotation("E"),
337             newAnnotation("E"), newAnnotation("E") });
338     Assert
339         .assertFalse(ann.isQuantitative(),
340             "All 'E' annotation set should not be quantitative.");
341
342     ann = new AlignmentAnnotation("an", "some an",
343         new Annotation[] {
344             newAnnotation("E"), newAnnotation("1"), newAnnotation("2"),
345             newAnnotation("3"), newAnnotation("E") });
346     Assert
347         .assertTrue(ann.isQuantitative(),
348             "Mixed 'E' annotation set should be quantitative.");
349   }
350
351   @Test(groups = "Functional")
352   public void testMakeVisibleAnnotation()
353   {
354     HiddenColumns h = new HiddenColumns();
355     Annotation[] anns = new Annotation[] {
356         null, null, new Annotation(1), new Annotation(2), new Annotation(3),
357         null, null, new Annotation(4), new Annotation(5), new Annotation(6),
358         new Annotation(7), new Annotation(8) };
359     AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an", anns);
360
361     // null annotations
362     AlignmentAnnotation emptyann = new AlignmentAnnotation("an", "some ann",
363         null);
364     emptyann.makeVisibleAnnotation(h);
365     assertNull(emptyann.annotations);
366
367     emptyann.makeVisibleAnnotation(3, 4, h);
368     assertNull(emptyann.annotations);
369
370     // without bounds, does everything
371     ann.makeVisibleAnnotation(h);
372     assertEquals(12, ann.annotations.length);
373     assertNull(ann.annotations[0]);
374     assertNull(ann.annotations[1]);
375     assertEquals(1.0f, ann.annotations[2].value);
376     assertEquals(2.0f, ann.annotations[3].value);
377     assertEquals(3.0f, ann.annotations[4].value);
378     assertNull(ann.annotations[5]);
379     assertNull(ann.annotations[6]);
380     assertEquals(4.0f, ann.annotations[7].value);
381     assertEquals(5.0f, ann.annotations[8].value);
382     assertEquals(6.0f, ann.annotations[9].value);
383     assertEquals(7.0f, ann.annotations[10].value);
384     assertEquals(8.0f, ann.annotations[11].value);
385
386     // without hidden cols, just truncates
387     ann.makeVisibleAnnotation(3, 5, h);
388     assertEquals(3, ann.annotations.length);
389     assertEquals(2.0f, ann.annotations[0].value);
390     assertEquals(3.0f, ann.annotations[1].value);
391     assertNull(ann.annotations[2]);
392
393     anns = new Annotation[] {
394         null, null, new Annotation(1), new Annotation(2), new Annotation(3),
395         null, null, new Annotation(4), new Annotation(5), new Annotation(6),
396         new Annotation(7), new Annotation(8) };
397     ann = new AlignmentAnnotation("an", "some an", anns);
398     h.hideColumns(4, 7);
399     ann.makeVisibleAnnotation(1, 9, h);
400     assertEquals(5, ann.annotations.length);
401     assertNull(ann.annotations[0]);
402     assertEquals(1.0f, ann.annotations[1].value);
403     assertEquals(2.0f, ann.annotations[2].value);
404     assertEquals(5.0f, ann.annotations[3].value);
405     assertEquals(6.0f, ann.annotations[4].value);
406
407     anns = new Annotation[] {
408         null, null, new Annotation(1), new Annotation(2), new Annotation(3),
409         null, null, new Annotation(4), new Annotation(5), new Annotation(6),
410         new Annotation(7), new Annotation(8) };
411     ann = new AlignmentAnnotation("an", "some an", anns);
412     h.hideColumns(1, 2);
413     ann.makeVisibleAnnotation(1, 9, h);
414     assertEquals(3, ann.annotations.length);
415     assertEquals(2.0f, ann.annotations[0].value);
416     assertEquals(5.0f, ann.annotations[1].value);
417     assertEquals(6.0f, ann.annotations[2].value);
418
419     anns = new Annotation[] {
420         null, null, new Annotation(1), new Annotation(2), new Annotation(3),
421         null, null, new Annotation(4), new Annotation(5), new Annotation(6),
422         new Annotation(7), new Annotation(8), new Annotation(9),
423         new Annotation(10), new Annotation(11), new Annotation(12),
424         new Annotation(13), new Annotation(14), new Annotation(15) };
425     ann = new AlignmentAnnotation("an", "some an", anns);
426     h = new HiddenColumns();
427     h.hideColumns(5, 18);
428     h.hideColumns(20, 21);
429     ann.makeVisibleAnnotation(1, 21, h);
430     assertEquals(5, ann.annotations.length);
431     assertEquals(1.0f, ann.annotations[1].value);
432     assertEquals(2.0f, ann.annotations[2].value);
433     assertEquals(3.0f, ann.annotations[3].value);
434     assertNull(ann.annotations[0]);
435     assertNull(ann.annotations[4]);
436   }
437
438   @Test(groups = "Functional")
439   public void testMakeVisibleAnnotation_NullAnnotationsAndNoColsHidden()
440   {
441     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", null);
442     HiddenColumns hc = new HiddenColumns();
443     ann.makeVisibleAnnotation(hc);
444     assertThat(ann.annotations, is(nullValue()));
445   }
446
447   @Test(groups = "Functional")
448   public void testMakeVisibleAnnotation_NullAnnotationsAndTrim()
449   {
450     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", null);
451     HiddenColumns hc = new HiddenColumns();
452     ann.makeVisibleAnnotation(3, 5, hc);
453     assertThat(ann.annotations, is(nullValue()));
454   }
455
456   @Test(groups = "Functional")
457   public void testMakeVisibleAnnotation_NoColsHidden()
458   {
459     Annotation[] annots = new Annotation[] {
460         EMPTY_ANNOTATION, EMPTY_ANNOTATION, new Annotation(1),
461         new Annotation(2), new Annotation(3), EMPTY_ANNOTATION,
462         EMPTY_ANNOTATION, new Annotation(4), new Annotation(5),
463         EMPTY_ANNOTATION, new Annotation(6), new Annotation(7),
464         new Annotation(8) };
465     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
466     HiddenColumns hc = new HiddenColumns();
467     ann.makeVisibleAnnotation(hc);
468     assertThat(ann.annotations, matchesAnnotations(annots));
469   }
470
471   @Test(groups = "Functional")
472   public void testMakeVisibleAnnotation_HideCols()
473   {
474     Annotation[] annots = new Annotation[] {
475         new Annotation(0), new Annotation(1), new Annotation(2),
476         new Annotation(3), new Annotation(4), new Annotation(5),
477         new Annotation(6), new Annotation(7), new Annotation(8) };
478     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
479     HiddenColumns hc = new HiddenColumns();
480     hc.hideColumns(2, 6);
481     ann.makeVisibleAnnotation(hc);
482     var expected = new Annotation[] {
483         new Annotation(0), new Annotation(1), new Annotation(7),
484         new Annotation(8) };
485     assertThat(ann.annotations, matchesAnnotations(expected));
486   }
487
488   @Test(groups = "Functional")
489   public void testMakeVisibleAnnotation_ExplicitFullWidthAndHideCols()
490   {
491     Annotation[] annots = new Annotation[] {
492         new Annotation(0), new Annotation(1), new Annotation(2),
493         new Annotation(3), new Annotation(4), new Annotation(5),
494         new Annotation(6), new Annotation(7), new Annotation(8),
495         new Annotation(9), new Annotation(10), new Annotation(11) };
496     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
497     HiddenColumns hc = new HiddenColumns();
498     hc.hideColumns(4, 7);
499     ann.makeVisibleAnnotation(0, 11, hc);
500     assertThat(ann.annotations,
501         matchesAnnotations(new Annotation(0), new Annotation(1),
502             new Annotation(2), new Annotation(3), new Annotation(8),
503             new Annotation(9), new Annotation(10), new Annotation(11)));
504   }
505
506   @Test(groups = "Functional")
507   public void testMakeVisibleAnnotation_ExplicitFullWidthAndHideCols2()
508   {
509     Annotation[] annots = new Annotation[] {
510         new Annotation(0), new Annotation(1), new Annotation(2),
511         new Annotation(3), new Annotation(4), new Annotation(5),
512         new Annotation(6), new Annotation(7), new Annotation(8), };
513     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
514     HiddenColumns hc = new HiddenColumns();
515     hc.hideColumns(4, 7);
516     ann.makeVisibleAnnotation(0, 8, hc);
517     assertThat(ann.annotations,
518         matchesAnnotations(new Annotation(0), new Annotation(1),
519             new Annotation(2), new Annotation(3), new Annotation(8)));
520   }
521
522   @Test(groups = "Functional")
523   public void testMakeVisibleAnnotation_HideColsWithEmptyAnnots()
524   {
525     Annotation[] annots = new Annotation[] {
526         EMPTY_ANNOTATION, EMPTY_ANNOTATION, new Annotation(1),
527         new Annotation(2), new Annotation(3), EMPTY_ANNOTATION,
528         EMPTY_ANNOTATION, new Annotation(4), new Annotation(5),
529         EMPTY_ANNOTATION, new Annotation(6), new Annotation(7),
530         new Annotation(8) };
531     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
532     HiddenColumns hc = new HiddenColumns();
533     hc.hideColumns(1, 3);
534     hc.hideColumns(8, 9);
535     ann.makeVisibleAnnotation(hc);
536     var expected = new Annotation[] {
537         EMPTY_ANNOTATION, new Annotation(3), EMPTY_ANNOTATION, EMPTY_ANNOTATION,
538         new Annotation(4), new Annotation(6), new Annotation(7),
539         new Annotation(8) };
540     assertThat(ann.annotations, matchesAnnotations(expected));
541   }
542
543   @Test(groups = "Functional")
544   public void testMakeVisibleAnnotation_HideColsWithNullAnnots()
545   {
546     Annotation[] annots = new Annotation[] {
547         null, null, new Annotation(2), null, new Annotation(4),
548         new Annotation(5), null, null };
549     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
550     HiddenColumns hc = new HiddenColumns();
551     hc.hideColumns(2, 4);
552     ann.makeVisibleAnnotation(hc);
553     var expected = new Annotation[] {
554         null, null, new Annotation(5), null, null };
555     assertThat(ann.annotations, matchesAnnotations(expected));
556   }
557
558   @Test(groups = "Functional")
559   public void testMakeVisibleAnnotation_Truncate()
560   {
561     Annotation[] annots = new Annotation[] {
562         new Annotation(0), new Annotation(1), new Annotation(2),
563         new Annotation(3), new Annotation(4), new Annotation(5),
564         new Annotation(6), new Annotation(7) };
565     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
566     ann.makeVisibleAnnotation(3, 6, new HiddenColumns());
567     assertThat(ann.annotations, matchesAnnotations(new Annotation(3),
568         new Annotation(4), new Annotation(5), new Annotation(6)));
569   }
570
571   @Test(groups = "Functional")
572   public void testMakeVisibleAnnotation_TruncateAndHideColumns()
573   {
574     Annotation[] annots = new Annotation[] {
575         new Annotation(0), new Annotation(1), new Annotation(2),
576         new Annotation(3), new Annotation(4), new Annotation(5),
577         new Annotation(6), new Annotation(7), new Annotation(8),
578         new Annotation(9), new Annotation(10), new Annotation(11) };
579     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
580     HiddenColumns hc = new HiddenColumns();
581     hc.hideColumns(4, 7);
582     ann.makeVisibleAnnotation(1, 9, hc);
583     assertThat(ann.annotations,
584         matchesAnnotations(new Annotation(1), new Annotation(2),
585             new Annotation(3), new Annotation(8), new Annotation(9)));
586   }
587
588   @Test(groups = "Functional")
589   public void testMakeVisibleAnnotation_TruncateNegativeStart()
590   {
591     Annotation[] annots = annotsRange(8);
592     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
593     HiddenColumns hc = new HiddenColumns();
594     ann.makeVisibleAnnotation(-5, 1, hc);
595     assertThat(ann.annotations,
596         matchesAnnotations(new Annotation(0), new Annotation(1)));
597   }
598
599   @Test(groups = "Functional")
600   public void testMakeVisibleAnnotation_TruncateNegativeStartAndEnd()
601   {
602     Annotation[] annots = annotsRange(8);
603     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
604     HiddenColumns hc = new HiddenColumns();
605     ann.makeVisibleAnnotation(-5, -2, hc);
606     assertThat(ann.annotations, is(emptyArray()));
607   }
608
609   @Test(groups = "Functional")
610   public void testMakeVisibleAnnotation_TruncateEndBeyondSize()
611   {
612     Annotation[] annots = annotsRange(8);
613     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
614     HiddenColumns hc = new HiddenColumns();
615     ann.makeVisibleAnnotation(6, 10, hc);
616     assertThat(ann.annotations, matchesAnnotations(new Annotation(6), new Annotation(7)));
617   }
618
619   @Test(groups = "Functional")
620   public void testMakeVisibleAnnotation_TruncateStartAndEndBeyondSize()
621   {
622     Annotation[] annots = annotsRange(4);
623     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
624     HiddenColumns hc = new HiddenColumns();
625     ann.makeVisibleAnnotation(6, 10, hc);
626     assertThat(ann.annotations, is(emptyArray()));
627   }
628
629   @Test(groups = "Functional")
630   public void testMakeVisibleAnnotation_HiddenRegionBeyondSize()
631   {
632     Annotation[] annots = annotsRange(4);
633     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
634     HiddenColumns hc = new HiddenColumns();
635     hc.hideColumns(6, 7);
636     ann.makeVisibleAnnotation(hc);
637     assertThat(ann.annotations, matchesAnnotations(annots));
638   }
639
640   @Test(groups = "Functional")
641   public void testMakeVisibleAnnotation_HiddenRegionAndTrimEndBeyondSize()
642   {
643     Annotation[] annots = annotsRange(4);
644     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
645     HiddenColumns hc = new HiddenColumns();
646     hc.hideColumns(6, 7);
647     ann.makeVisibleAnnotation(0, 10, hc);
648     assertThat(ann.annotations, matchesAnnotations(annots));
649   }
650
651   @Test(groups = "Functional")
652   public void testMakeVisibleAnnotation_HiddenRegionBeforeStart()
653   {
654     Annotation[] annots = annotsRange(4);
655     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
656     HiddenColumns hc = new HiddenColumns();
657     hc.hideColumns(-3, -2);
658     ann.makeVisibleAnnotation(hc);
659     assertThat(ann.annotations, matchesAnnotations(annots));
660   }
661
662   @Test(groups = "Functional")
663   public void testMakeVisibleAnnotation_HiddenRegionAndTrimStartBeforeStart()
664   {
665     Annotation[] annots = annotsRange(4);
666     AlignmentAnnotation ann = new AlignmentAnnotation("label", "desc", annots);
667     HiddenColumns hc = new HiddenColumns();
668     hc.hideColumns(-3, -2);
669     ann.makeVisibleAnnotation(-5, annots.length - 1, hc);
670     assertThat(ann.annotations, matchesAnnotations(annots));
671   }
672
673   static Annotation[] annotsRange(int stop)
674   {
675     Annotation[] annotations = new Annotation[stop];
676     for (int i = 0; i < stop; i++)
677       annotations[i] = new Annotation(i);
678     return annotations;
679   }
680 }