Merge branch 'develop' into trialMerge
[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.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertNull;
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.annotations.BeforeClass;
32 import org.testng.annotations.Test;
33
34 public class AlignmentAnnotationTests
35 {
36
37   @BeforeClass(alwaysRun = true)
38   public void setUpJvOptionPane()
39   {
40     JvOptionPane.setInteractiveMode(false);
41     JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
42   }
43
44   @Test(groups = { "Functional" })
45   public void testCopyConstructor()
46   {
47     SequenceI sq = new Sequence("Foo", "ARAARARARAWEAWEAWRAWEAWE");
48     createAnnotation(sq);
49     AlignmentAnnotation alc, alo = sq.getAnnotation()[0];
50     alc = new AlignmentAnnotation(alo);
51     for (String key : alo.getProperties())
52     {
53       assertEquals("Property mismatch", alo.getProperty(key),
54               alc.getProperty(key));
55     }
56   }
57
58   /**
59    * create some dummy annotation derived from the sequence
60    * 
61    * @param sq
62    */
63   public static void createAnnotation(SequenceI sq)
64   {
65     Annotation[] al = new Annotation[sq.getLength()];
66     for (int i = 0; i < al.length; i++)
67     {
68       al[i] = new Annotation(new Annotation("" + sq.getCharAt(i), "",
69               (char) 0, sq.findPosition(i)));
70     }
71     AlignmentAnnotation alan = new AlignmentAnnotation("For "
72             + sq.getName(), "Fake alignment annot", al);
73     // create a sequence mapping for the annotation vector in its current state
74     alan.createSequenceMapping(sq, sq.getStart(), false);
75     alan.setProperty("CreatedBy", "createAnnotation");
76     sq.addAlignmentAnnotation(alan);
77   }
78
79   /**
80    * use this to test annotation derived from method above as it is transferred
81    * across different sequences derived from same dataset coordinate frame
82    * 
83    * @param ala
84    */
85   public static void testAnnotTransfer(AlignmentAnnotation ala)
86   {
87     assertEquals(
88             "Failed - need annotation created by createAnnotation method",
89             ala.description, "Fake alignment annot");
90     ala.adjustForAlignment();
91     for (int p = 0; p < ala.annotations.length; p++)
92     {
93       if (ala.annotations[p] != null)
94       {
95         assertEquals("Mismatch at position " + p
96                 + " between annotation position value and sequence"
97                 + ala.annotations[p], (int) ala.annotations[p].value,
98                 ala.sequenceRef.findPosition(p));
99       }
100     }
101   }
102
103   /**
104    * Tests the liftOver method and also exercises the functions for remapping
105    * annotation across different reference sequences. Here, the test is between
106    * different dataset frames (annotation transferred by mapping between
107    * sequences)
108    */
109   @Test(groups = { "Functional" })
110   public void testLiftOver()
111   {
112     SequenceI sqFrom = new Sequence("fromLong", "QQQCDEWGH");
113     sqFrom.setStart(10);
114     sqFrom.setEnd(sqFrom.findPosition(sqFrom.getLength() - 1));
115     SequenceI sqTo = new Sequence("toShort", "RCDEW");
116     sqTo.setStart(20);
117     sqTo.setEnd(sqTo.findPosition(sqTo.getLength() - 1));
118     createAnnotation(sqTo);
119     AlignmentAnnotation origTo = sqTo.getAnnotation()[0];
120     createAnnotation(sqFrom);
121     AlignmentAnnotation origFrom = sqFrom.getAnnotation()[0];
122     AlignSeq align = AlignSeq.doGlobalNWAlignment(sqFrom, sqTo,
123             AlignSeq.PEP);
124     SequenceI alSeq1 = new Sequence(sqFrom.getName(), align.getAStr1());
125     alSeq1.setStart(sqFrom.getStart() + align.getSeq1Start() - 1);
126     alSeq1.setEnd(sqFrom.getStart() + align.getSeq1End() - 1);
127     alSeq1.setDatasetSequence(sqFrom);
128     SequenceI alSeq2 = new Sequence(sqTo.getName(), align.getAStr2());
129     alSeq2.setStart(sqTo.getStart() + align.getSeq2Start() - 1);
130     alSeq2.setEnd(sqTo.getStart() + align.getSeq2End() - 1);
131     alSeq2.setDatasetSequence(sqTo);
132     System.out.println(new AppletFormatAdapter()
133 .formatSequences(
134             FileFormat.Stockholm, new Alignment(new SequenceI[] { sqFrom,
135                 alSeq1, sqTo, alSeq2 }), true));
136
137     Mapping mp = align.getMappingFromS1(false);
138
139     AlignmentAnnotation almap1 = new AlignmentAnnotation(
140             sqTo.getAnnotation()[0]);
141     almap1.liftOver(sqFrom, mp);
142     assertEquals(almap1.sequenceRef, sqFrom);
143     alSeq1.addAlignmentAnnotation(almap1);
144     almap1.setSequenceRef(alSeq1);
145     almap1.adjustForAlignment();
146     AlignmentAnnotation almap2 = new AlignmentAnnotation(
147             sqFrom.getAnnotation()[0]);
148     almap2.liftOver(sqTo, mp);
149     assertEquals(almap2.sequenceRef, sqTo);
150
151     alSeq2.addAlignmentAnnotation(almap2);
152     almap2.setSequenceRef(alSeq2);
153     almap2.adjustForAlignment();
154
155     AlignmentI all = new Alignment(new SequenceI[] { alSeq1, alSeq2 });
156     all.addAnnotation(almap1);
157     all.addAnnotation(almap2);
158     System.out.println(new AppletFormatAdapter().formatSequences(
159             FileFormat.Stockholm,
160             all, true));
161
162     for (int p = 0; p < alSeq1.getLength(); p++)
163     {
164       Annotation orig1, trans1, orig2, trans2;
165       trans2 = almap2.annotations[p];
166       orig2 = origFrom.annotations[alSeq1.findPosition(p)
167               - sqFrom.getStart()];
168       orig1 = origTo.annotations[alSeq2.findPosition(p) - sqTo.getStart()];
169       trans1 = almap1.annotations[p];
170       if (trans1 == trans2)
171       {
172         System.out.println("Pos " + p + " mismatch");
173         continue;
174       }
175       assertEquals(
176               "Mismatch on Original From and transferred annotation on 2",
177               (orig2 != null) ? orig2.toString() : null,
178               (trans2 != null) ? trans2.toString() : null);
179       assertEquals(
180               "Mismatch on Original To and transferred annotation on 1",
181               (orig1 != null) ? orig1.toString() : null,
182               (trans1 != null) ? trans1.toString() : null);
183       String alm1 = ""
184               + (almap1.annotations.length > p ? almap1.annotations[p].displayCharacter
185                       : "Out of range");
186       String alm2 = ""
187               + (almap2.annotations.length > p ? almap2.annotations[p].displayCharacter
188                       : "Out of range");
189       assertEquals("Position " + p + " " + alm1 + " " + alm2, alm1, alm2);
190     }
191   }
192
193   @Test(groups = { "Functional" })
194   public void testAdjustForAlignment()
195   {
196     SequenceI seq = new Sequence("TestSeq", "ABCDEFG");
197     seq.createDatasetSequence();
198
199     /*
200      * Annotate positions 3/4/5 (CDE) with values 1/2/3
201      */
202     Annotation[] anns = new Annotation[] { null, null, new Annotation(1),
203         new Annotation(2), new Annotation(3) };
204     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
205             "secondary structure", anns);
206     seq.addAlignmentAnnotation(ann);
207
208     /*
209      * Check annotation map before modifying aligned sequence
210      */
211     assertNull(ann.getAnnotationForPosition(1));
212     assertNull(ann.getAnnotationForPosition(2));
213     assertNull(ann.getAnnotationForPosition(6));
214     assertNull(ann.getAnnotationForPosition(7));
215     assertEquals(1, ann.getAnnotationForPosition(3).value, 0.001d);
216     assertEquals(2, ann.getAnnotationForPosition(4).value, 0.001d);
217     assertEquals(3, ann.getAnnotationForPosition(5).value, 0.001d);
218
219     /*
220      * Trim the displayed sequence to BCD and adjust annotations
221      */
222     seq.setSequence("BCD");
223     seq.setStart(2);
224     seq.setEnd(4);
225     ann.adjustForAlignment();
226
227     /*
228      * Should now have annotations for aligned positions 2, 3Q (CD) only
229      */
230     assertEquals(3, ann.annotations.length);
231     assertNull(ann.annotations[0]);
232     assertEquals(1, ann.annotations[1].value, 0.001);
233     assertEquals(2, ann.annotations[2].value, 0.001);
234   }
235
236   /**
237    * Test the method that defaults rna symbol to the one matching the preceding
238    * unmatched opening bracket (if any)
239    */
240   @Test(groups = { "Functional" })
241   public void testGetDefaultRnaHelixSymbol()
242   {
243     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
244             "secondary structure", null);
245     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
246
247     Annotation[] anns = new Annotation[20];
248     ann.annotations = anns;
249     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
250
251     anns[1] = new Annotation("(", "S", '(', 0f);
252     assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
253     assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
254     assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
255     assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
256
257     /*
258      * .(.[.{.<.}.>.).].
259      */
260     anns[1] = new Annotation("(", "S", '(', 0f);
261     anns[3] = new Annotation("[", "S", '[', 0f);
262     anns[5] = new Annotation("{", "S", '{', 0f);
263     anns[7] = new Annotation("<", "S", '<', 0f);
264     anns[9] = new Annotation("}", "S", '}', 0f);
265     anns[11] = new Annotation(">", "S", '>', 0f);
266     anns[13] = new Annotation(")", "S", ')', 0f);
267     anns[15] = new Annotation("]", "S", ']', 0f);
268
269     String expected = "(())]]}}>>>>]]]](";
270     for (int i = 0; i < expected.length(); i++)
271     {
272       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
273               ann.getDefaultRnaHelixSymbol(i));
274     }
275
276     /*
277      * .(.[.(.).{.}.<.].D.
278      */
279     anns[1] = new Annotation("(", "S", '(', 0f);
280     anns[3] = new Annotation("[", "S", '[', 0f);
281     anns[5] = new Annotation("(", "S", '(', 0f);
282     anns[7] = new Annotation(")", "S", ')', 0f);
283     anns[9] = new Annotation("{", "S", '{', 0f);
284     anns[11] = new Annotation("}", "S", '}', 0f);
285     anns[13] = new Annotation("<", "S", '>', 0f);
286     anns[15] = new Annotation("]", "S", ']', 0f);
287     anns[17] = new Annotation("D", "S", 'D', 0f);
288
289     expected = "(())]]))]]}}]]>>>>dd";
290     for (int i = 0; i < expected.length(); i++)
291     {
292       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
293               ann.getDefaultRnaHelixSymbol(i));
294     }
295   }
296 }