JAL-3438 spotless for 2.11.2.0
[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 static org.testng.Assert.assertNull;
24 import static org.testng.AssertJUnit.assertEquals;
25
26 import jalview.analysis.AlignSeq;
27 import jalview.gui.JvOptionPane;
28 import jalview.io.AppletFormatAdapter;
29 import jalview.io.FileFormat;
30
31 import org.testng.Assert;
32 import org.testng.annotations.BeforeClass;
33 import org.testng.annotations.Test;
34
35 public class AlignmentAnnotationTests
36 {
37
38   @BeforeClass(alwaysRun = true)
39   public void setUpJvOptionPane()
40   {
41     JvOptionPane.setInteractiveMode(false);
42     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
43   }
44
45   @Test(groups = { "Functional" })
46   public void testCopyConstructor()
47   {
48     SequenceI sq = new Sequence("Foo", "ARAARARARAWEAWEAWRAWEAWE");
49     createAnnotation(sq);
50     AlignmentAnnotation alc, alo = sq.getAnnotation()[0];
51     alc = new AlignmentAnnotation(alo);
52     for (String key : alo.getProperties())
53     {
54       assertEquals("Property mismatch", alo.getProperty(key),
55               alc.getProperty(key));
56     }
57   }
58
59   /**
60    * create some dummy annotation derived from the sequence
61    * 
62    * @param sq
63    */
64   public static void createAnnotation(SequenceI sq)
65   {
66     Annotation[] al = new Annotation[sq.getLength()];
67     for (int i = 0; i < al.length; i++)
68     {
69       al[i] = new Annotation(new Annotation("" + sq.getCharAt(i), "",
70               (char) 0, sq.findPosition(i)));
71     }
72     AlignmentAnnotation alan = new AlignmentAnnotation(
73             "For " + sq.getName(), "Fake alignment annot", al);
74     // create a sequence mapping for the annotation vector in its current state
75     alan.createSequenceMapping(sq, sq.getStart(), false);
76     alan.setProperty("CreatedBy", "createAnnotation");
77     sq.addAlignmentAnnotation(alan);
78   }
79
80   /**
81    * use this to test annotation derived from method above as it is transferred
82    * across different sequences derived from same dataset coordinate frame
83    * 
84    * @param ala
85    */
86   public static void testAnnotTransfer(AlignmentAnnotation ala)
87   {
88     assertEquals(
89             "Failed - need annotation created by createAnnotation method",
90             ala.description, "Fake alignment annot");
91     ala.adjustForAlignment();
92     for (int p = 0; p < ala.annotations.length; p++)
93     {
94       if (ala.annotations[p] != null)
95       {
96         assertEquals(
97                 "Mismatch at position " + p
98                         + " between annotation position value and sequence"
99                         + ala.annotations[p],
100                 (int) ala.annotations[p].value,
101                 ala.sequenceRef.findPosition(p));
102       }
103     }
104   }
105
106   /**
107    * Tests the liftOver method and also exercises the functions for remapping
108    * annotation across different reference sequences. Here, the test is between
109    * different dataset frames (annotation transferred by mapping between
110    * sequences)
111    */
112   @Test(groups = { "Functional" })
113   public void testLiftOver()
114   {
115     SequenceI sqFrom = new Sequence("fromLong", "QQQCDEWGH");
116     sqFrom.setStart(10);
117     sqFrom.setEnd(sqFrom.findPosition(sqFrom.getLength() - 1));
118     SequenceI sqTo = new Sequence("toShort", "RCDEW");
119     sqTo.setStart(20);
120     sqTo.setEnd(sqTo.findPosition(sqTo.getLength() - 1));
121     createAnnotation(sqTo);
122     AlignmentAnnotation origTo = sqTo.getAnnotation()[0];
123     createAnnotation(sqFrom);
124     AlignmentAnnotation origFrom = sqFrom.getAnnotation()[0];
125     AlignSeq align = AlignSeq.doGlobalNWAlignment(sqFrom, sqTo,
126             AlignSeq.PEP);
127     SequenceI alSeq1 = new Sequence(sqFrom.getName(), align.getAStr1());
128     alSeq1.setStart(sqFrom.getStart() + align.getSeq1Start() - 1);
129     alSeq1.setEnd(sqFrom.getStart() + align.getSeq1End() - 1);
130     alSeq1.setDatasetSequence(sqFrom);
131     SequenceI alSeq2 = new Sequence(sqTo.getName(), align.getAStr2());
132     alSeq2.setStart(sqTo.getStart() + align.getSeq2Start() - 1);
133     alSeq2.setEnd(sqTo.getStart() + align.getSeq2End() - 1);
134     alSeq2.setDatasetSequence(sqTo);
135     System.out.println(new AppletFormatAdapter().formatSequences(
136             FileFormat.Stockholm, new Alignment(new SequenceI[]
137             { sqFrom, alSeq1, sqTo, alSeq2 }), true));
138
139     Mapping mp = align.getMappingFromS1(false);
140
141     AlignmentAnnotation almap1 = new AlignmentAnnotation(
142             sqTo.getAnnotation()[0]);
143     almap1.liftOver(sqFrom, mp);
144     assertEquals(almap1.sequenceRef, sqFrom);
145     alSeq1.addAlignmentAnnotation(almap1);
146     almap1.setSequenceRef(alSeq1);
147     almap1.adjustForAlignment();
148     AlignmentAnnotation almap2 = new AlignmentAnnotation(
149             sqFrom.getAnnotation()[0]);
150     almap2.liftOver(sqTo, mp);
151     assertEquals(almap2.sequenceRef, sqTo);
152
153     alSeq2.addAlignmentAnnotation(almap2);
154     almap2.setSequenceRef(alSeq2);
155     almap2.adjustForAlignment();
156
157     AlignmentI all = new Alignment(new SequenceI[] { alSeq1, alSeq2 });
158     all.addAnnotation(almap1);
159     all.addAnnotation(almap2);
160     System.out.println(new AppletFormatAdapter()
161             .formatSequences(FileFormat.Stockholm, all, true));
162
163     for (int p = 0; p < alSeq1.getLength(); p++)
164     {
165       Annotation orig1, trans1, orig2, trans2;
166       trans2 = almap2.annotations[p];
167       orig2 = origFrom.annotations[alSeq1.findPosition(p)
168               - sqFrom.getStart()];
169       orig1 = origTo.annotations[alSeq2.findPosition(p) - sqTo.getStart()];
170       trans1 = almap1.annotations[p];
171       if (trans1 == trans2)
172       {
173         System.out.println("Pos " + p + " mismatch");
174         continue;
175       }
176       assertEquals(
177               "Mismatch on Original From and transferred annotation on 2",
178               (orig2 != null) ? orig2.toString() : null,
179               (trans2 != null) ? trans2.toString() : null);
180       assertEquals(
181               "Mismatch on Original To and transferred annotation on 1",
182               (orig1 != null) ? orig1.toString() : null,
183               (trans1 != null) ? trans1.toString() : null);
184       String alm1 = "" + (almap1.annotations.length > p
185               ? almap1.annotations[p].displayCharacter
186               : "Out of range");
187       String alm2 = "" + (almap2.annotations.length > p
188               ? almap2.annotations[p].displayCharacter
189               : "Out of range");
190       assertEquals("Position " + p + " " + alm1 + " " + alm2, alm1, alm2);
191     }
192   }
193
194   @Test(groups = { "Functional" })
195   public void testAdjustForAlignment()
196   {
197     SequenceI seq = new Sequence("TestSeq", "ABCDEFG");
198     seq.createDatasetSequence();
199
200     /*
201      * Annotate positions 3/4/5 (CDE) with values 1/2/3
202      */
203     Annotation[] anns = new Annotation[] { null, null, new Annotation(1),
204         new Annotation(2), new Annotation(3) };
205     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
206             "secondary structure", anns);
207     seq.addAlignmentAnnotation(ann);
208
209     /*
210      * Check annotation map before modifying aligned sequence
211      */
212     assertNull(ann.getAnnotationForPosition(1));
213     assertNull(ann.getAnnotationForPosition(2));
214     assertNull(ann.getAnnotationForPosition(6));
215     assertNull(ann.getAnnotationForPosition(7));
216     assertEquals(1, ann.getAnnotationForPosition(3).value, 0.001d);
217     assertEquals(2, ann.getAnnotationForPosition(4).value, 0.001d);
218     assertEquals(3, ann.getAnnotationForPosition(5).value, 0.001d);
219
220     /*
221      * Trim the displayed sequence to BCD and adjust annotations
222      */
223     seq.setSequence("BCD");
224     seq.setStart(2);
225     seq.setEnd(4);
226     ann.adjustForAlignment();
227
228     /*
229      * Should now have annotations for aligned positions 2, 3Q (CD) only
230      */
231     assertEquals(3, ann.annotations.length);
232     assertNull(ann.annotations[0]);
233     assertEquals(1, ann.annotations[1].value, 0.001);
234     assertEquals(2, ann.annotations[2].value, 0.001);
235   }
236
237   /**
238    * Test the method that defaults rna symbol to the one matching the preceding
239    * unmatched opening bracket (if any)
240    */
241   @Test(groups = { "Functional" })
242   public void testGetDefaultRnaHelixSymbol()
243   {
244     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
245             "secondary structure", null);
246     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
247
248     Annotation[] anns = new Annotation[20];
249     ann.annotations = anns;
250     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
251
252     anns[1] = new Annotation("(", "S", '(', 0f);
253     assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
254     assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
255     assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
256     assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
257
258     /*
259      * .(.[.{.<.}.>.).].
260      */
261     anns[1] = new Annotation("(", "S", '(', 0f);
262     anns[3] = new Annotation("[", "S", '[', 0f);
263     anns[5] = new Annotation("{", "S", '{', 0f);
264     anns[7] = new Annotation("<", "S", '<', 0f);
265     anns[9] = new Annotation("}", "S", '}', 0f);
266     anns[11] = new Annotation(">", "S", '>', 0f);
267     anns[13] = new Annotation(")", "S", ')', 0f);
268     anns[15] = new Annotation("]", "S", ']', 0f);
269
270     String expected = "(())]]}}>>>>]]]](";
271     for (int i = 0; i < expected.length(); i++)
272     {
273       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
274               ann.getDefaultRnaHelixSymbol(i));
275     }
276
277     /*
278      * .(.[.(.).{.}.<.].D.
279      */
280     anns[1] = new Annotation("(", "S", '(', 0f);
281     anns[3] = new Annotation("[", "S", '[', 0f);
282     anns[5] = new Annotation("(", "S", '(', 0f);
283     anns[7] = new Annotation(")", "S", ')', 0f);
284     anns[9] = new Annotation("{", "S", '{', 0f);
285     anns[11] = new Annotation("}", "S", '}', 0f);
286     anns[13] = new Annotation("<", "S", '>', 0f);
287     anns[15] = new Annotation("]", "S", ']', 0f);
288     anns[17] = new Annotation("D", "S", 'D', 0f);
289
290     expected = "(())]]))]]}}]]>>>>dd";
291     for (int i = 0; i < expected.length(); i++)
292     {
293       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
294               ann.getDefaultRnaHelixSymbol(i));
295     }
296   }
297
298   public static Annotation newAnnotation(String ann)
299   {
300     float val = 0f;
301     try
302     {
303       val = Float.parseFloat(ann);
304     } catch (NumberFormatException q)
305     {
306     }
307     ;
308     return new Annotation(ann, ann, '\0', val);
309   }
310
311   @Test(groups = { "Functional" })
312   public void testIsQuantitative()
313   {
314     AlignmentAnnotation ann = null;
315
316     ann = new AlignmentAnnotation("an", "some an", null);
317     Assert.assertFalse(ann.isQuantitative(),
318             "Empty annotation set should not be quantitative.");
319
320     ann = new AlignmentAnnotation("an", "some an",
321             new Annotation[]
322             { newAnnotation("4"), newAnnotation("1"), newAnnotation("1"),
323                 newAnnotation("0.1"), newAnnotation("0.3") });
324     Assert.assertTrue(ann.isQuantitative(),
325             "All numbers annotation set should be quantitative.");
326
327     ann = new AlignmentAnnotation("an", "some an",
328             new Annotation[]
329             { newAnnotation("E"), newAnnotation("E"), newAnnotation("E"),
330                 newAnnotation("E"), newAnnotation("E") });
331     Assert.assertFalse(ann.isQuantitative(),
332             "All 'E' annotation set should not be quantitative.");
333
334     ann = new AlignmentAnnotation("an", "some an",
335             new Annotation[]
336             { newAnnotation("E"), newAnnotation("1"), newAnnotation("2"),
337                 newAnnotation("3"), newAnnotation("E") });
338     Assert.assertTrue(ann.isQuantitative(),
339             "Mixed 'E' annotation set should be quantitative.");
340   }
341
342   @Test(groups = "Functional")
343   public void testMakeVisibleAnnotation()
344   {
345     HiddenColumns h = new HiddenColumns();
346     Annotation[] anns = new Annotation[] { null, null, new Annotation(1),
347         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
348         new Annotation(5), new Annotation(6), new Annotation(7),
349         new Annotation(8) };
350     AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an",
351             anns);
352
353     // null annotations
354     AlignmentAnnotation emptyann = new AlignmentAnnotation("an", "some ann",
355             null);
356     emptyann.makeVisibleAnnotation(h);
357     assertNull(emptyann.annotations);
358
359     emptyann.makeVisibleAnnotation(3, 4, h);
360     assertNull(emptyann.annotations);
361
362     // without bounds, does everything
363     ann.makeVisibleAnnotation(h);
364     assertEquals(12, ann.annotations.length);
365     assertNull(ann.annotations[0]);
366     assertNull(ann.annotations[1]);
367     assertEquals(1.0f, ann.annotations[2].value);
368     assertEquals(2.0f, ann.annotations[3].value);
369     assertEquals(3.0f, ann.annotations[4].value);
370     assertNull(ann.annotations[5]);
371     assertNull(ann.annotations[6]);
372     assertEquals(4.0f, ann.annotations[7].value);
373     assertEquals(5.0f, ann.annotations[8].value);
374     assertEquals(6.0f, ann.annotations[9].value);
375     assertEquals(7.0f, ann.annotations[10].value);
376     assertEquals(8.0f, ann.annotations[11].value);
377
378     // without hidden cols, just truncates
379     ann.makeVisibleAnnotation(3, 5, h);
380     assertEquals(3, ann.annotations.length);
381     assertEquals(2.0f, ann.annotations[0].value);
382     assertEquals(3.0f, ann.annotations[1].value);
383     assertNull(ann.annotations[2]);
384
385     anns = new Annotation[] { null, null, new Annotation(1),
386         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
387         new Annotation(5), new Annotation(6), new Annotation(7),
388         new Annotation(8) };
389     ann = new AlignmentAnnotation("an", "some an", anns);
390     h.hideColumns(4, 7);
391     ann.makeVisibleAnnotation(1, 9, h);
392     assertEquals(5, ann.annotations.length);
393     assertNull(ann.annotations[0]);
394     assertEquals(1.0f, ann.annotations[1].value);
395     assertEquals(2.0f, ann.annotations[2].value);
396     assertEquals(5.0f, ann.annotations[3].value);
397     assertEquals(6.0f, ann.annotations[4].value);
398
399     anns = new Annotation[] { null, null, new Annotation(1),
400         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
401         new Annotation(5), new Annotation(6), new Annotation(7),
402         new Annotation(8) };
403     ann = new AlignmentAnnotation("an", "some an", anns);
404     h.hideColumns(1, 2);
405     ann.makeVisibleAnnotation(1, 9, h);
406     assertEquals(3, ann.annotations.length);
407     assertEquals(2.0f, ann.annotations[0].value);
408     assertEquals(5.0f, ann.annotations[1].value);
409     assertEquals(6.0f, ann.annotations[2].value);
410
411     anns = new Annotation[] { null, null, new Annotation(1),
412         new Annotation(2), new Annotation(3), null, null, new Annotation(4),
413         new Annotation(5), new Annotation(6), new Annotation(7),
414         new Annotation(8), new Annotation(9), new Annotation(10),
415         new Annotation(11), new Annotation(12), new Annotation(13),
416         new Annotation(14), new Annotation(15) };
417     ann = new AlignmentAnnotation("an", "some an", anns);
418     h = new HiddenColumns();
419     h.hideColumns(5, 18);
420     h.hideColumns(20, 21);
421     ann.makeVisibleAnnotation(1, 21, h);
422     assertEquals(5, ann.annotations.length);
423     assertEquals(1.0f, ann.annotations[1].value);
424     assertEquals(2.0f, ann.annotations[2].value);
425     assertEquals(3.0f, ann.annotations[3].value);
426     assertNull(ann.annotations[0]);
427     assertNull(ann.annotations[4]);
428   }
429 }