Merge develop to Release_2_8_3_Branch
[jalview.git] / test / jalview / datamodel / AlignmentTest.java
1 package jalview.datamodel;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertFalse;
5 import static org.junit.Assert.assertTrue;
6 import jalview.io.AppletFormatAdapter;
7 import jalview.io.FormatAdapter;
8 import jalview.util.MapList;
9
10 import java.io.IOException;
11 import java.util.Iterator;
12
13 import org.junit.Before;
14 import org.junit.Test;
15
16 /**
17  * Unit tests for Alignment datamodel.
18  * 
19  * @author gmcarstairs
20  *
21  */
22 public class AlignmentTest
23 {
24   // @formatter:off
25   private static final String TEST_DATA = 
26           "# STOCKHOLM 1.0\n" +
27           "#=GS D.melanogaster.1 AC AY119185.1/838-902\n" +
28           "#=GS D.melanogaster.2 AC AC092237.1/57223-57161\n" +
29           "#=GS D.melanogaster.3 AC AY060611.1/560-627\n" +
30           "D.melanogaster.1          G.AGCC.CU...AUGAUCGA\n" +
31           "#=GR D.melanogaster.1 SS  ................((((\n" +
32           "D.melanogaster.2          C.AUUCAACU.UAUGAGGAU\n" +
33           "#=GR D.melanogaster.2 SS  ................((((\n" +
34           "D.melanogaster.3          G.UGGCGCU..UAUGACGCA\n" +
35           "#=GR D.melanogaster.3 SS  (.(((...(....(((((((\n" +
36           "//";
37
38   private static final String AA_SEQS_1 = 
39           ">Seq1Name\n" +
40           "K-QY--L\n" +
41           ">Seq2Name\n" +
42           "-R-FP-W-\n";
43
44   private static final String CDNA_SEQS_1 = 
45           ">Seq1Name\n" +
46           "AC-GG--CUC-CAA-CT\n" +
47           ">Seq2Name\n" +
48           "-CG-TTA--ACG---AAGT\n";
49
50   private static final String CDNA_SEQS_2 = 
51           ">Seq1Name\n" +
52           "GCTCGUCGTACT\n" +
53           ">Seq2Name\n" +
54           "GGGTCAGGCAGT\n";
55   // @formatter:on
56
57   private AlignmentI al;
58
59   /**
60    * Helper method to load an alignment and ensure dataset sequences are set up.
61    * 
62    * @param data
63    * @param format
64    *          TODO
65    * @return
66    * @throws IOException
67    */
68   protected AlignmentI loadAlignment(final String data, String format)
69           throws IOException
70   {
71     Alignment a = new FormatAdapter().readFile(data,
72             AppletFormatAdapter.PASTE, format);
73     a.setDataset(null);
74     return a;
75   }
76
77   /*
78    * Read in Stockholm format test data including secondary structure
79    * annotations.
80    */
81   @Before
82   public void setUp() throws IOException
83   {
84     al = loadAlignment(TEST_DATA, "STH");
85     int i = 0;
86     for (AlignmentAnnotation ann : al.getAlignmentAnnotation())
87     {
88       ann.setCalcId("CalcIdFor" + al.getSequenceAt(i).getName());
89       i++;
90     }
91   }
92
93   /**
94    * Test method that returns annotations that match on calcId.
95    */
96   @Test
97   public void testFindAnnotation_byCalcId()
98   {
99     Iterable<AlignmentAnnotation> anns = al
100             .findAnnotation("CalcIdForD.melanogaster.2");
101     Iterator<AlignmentAnnotation> iter = anns.iterator();
102     assertTrue(iter.hasNext());
103     AlignmentAnnotation ann = iter.next();
104     assertEquals("D.melanogaster.2", ann.sequenceRef.getName());
105     assertFalse(iter.hasNext());
106   }
107
108   @Test
109   public void testDeleteAllAnnotations_includingAutocalculated()
110   {
111     AlignmentAnnotation aa = new AlignmentAnnotation("Consensus",
112             "Consensus", 0.5);
113     aa.autoCalculated = true;
114     al.addAnnotation(aa);
115     AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
116     assertEquals("Wrong number of annotations before deleting", 4,
117             anns.length);
118     al.deleteAllAnnotations(true);
119     assertEquals("Not all deleted", 0, al.getAlignmentAnnotation().length);
120   }
121
122   @Test
123   public void testDeleteAllAnnotations_excludingAutocalculated()
124   {
125     AlignmentAnnotation aa = new AlignmentAnnotation("Consensus",
126             "Consensus", 0.5);
127     aa.autoCalculated = true;
128     al.addAnnotation(aa);
129     AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
130     assertEquals("Wrong number of annotations before deleting", 4,
131             anns.length);
132     al.deleteAllAnnotations(false);
133     assertEquals("Not just one annotation left", 1,
134             al.getAlignmentAnnotation().length);
135   }
136
137   /**
138    * Tests for realigning as per a supplied alignment: Dna as Dna.
139    * 
140    * Note: AlignedCodonFrame's state variables are named for protein-to-cDNA
141    * mapping, but can be exploited for a general 'sequence-to-sequence' mapping
142    * as here.
143    * 
144    * @throws IOException
145    */
146   @Test
147   public void testAlignAs_dnaAsDna() throws IOException
148   {
149     // aligned cDNA:
150     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
151     // unaligned cDNA:
152     AlignmentI al2 = loadAlignment(CDNA_SEQS_2, "FASTA");
153
154     /*
155      * Make mappings between sequences. The 'aligned cDNA' is playing the role
156      * of what would normally be protein here.
157      */
158     AlignedCodonFrame acf = new AlignedCodonFrame();
159     MapList ml = new MapList(new int[]
160     { 1, 12 }, new int[]
161     { 1, 12 }, 1, 1);
162     acf.addMap(al2.getSequenceAt(0), al1.getSequenceAt(0), ml);
163     acf.addMap(al2.getSequenceAt(1), al1.getSequenceAt(1), ml);
164     al1.addCodonFrame(acf);
165
166     ((Alignment) al2).alignAs(al1, false, true);
167     assertEquals("GC-TC--GUC-GTA-CT", al2.getSequenceAt(0)
168             .getSequenceAsString());
169     assertEquals("-GG-GTC--AGG---CAGT", al2.getSequenceAt(1)
170             .getSequenceAsString());
171   }
172
173   /**
174    * Aligning protein from cDNA.
175    * 
176    * @throws IOException
177    */
178   @Test
179   public void testAlignAs_proteinAsCdna() throws IOException
180   {
181     // see also AlignmentUtilsTests
182     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
183     AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA");
184     AlignedCodonFrame acf = new AlignedCodonFrame();
185     MapList ml = new MapList(new int[]
186     { 1, 12 }, new int[]
187     { 1, 4 }, 3, 1);
188     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml);
189     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml);
190     al2.addCodonFrame(acf);
191
192     ((Alignment) al2).alignAs(al1, false, true);
193     assertEquals("K-Q-Y-L-", al2.getSequenceAt(0).getSequenceAsString());
194     assertEquals("-R-F-P-W", al2.getSequenceAt(1).getSequenceAsString());
195   }
196
197   /**
198    * Test aligning cdna as per protein alignment.
199    * 
200    * @throws IOException
201    */
202   @Test
203   public void testAlignAs_cdnaAsProtein() throws IOException
204   {
205     /*
206      * Load alignments and add mappings for cDNA to protein
207      */
208     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
209     AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA");
210     AlignedCodonFrame acf = new AlignedCodonFrame();
211     MapList ml = new MapList(new int[]
212     { 1, 12 }, new int[]
213     { 1, 4 }, 3, 1);
214     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml);
215     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml);
216     al2.addCodonFrame(acf);
217
218     /*
219      * Realign DNA; currently keeping existing gaps in introns only
220      */
221     ((Alignment) al1).alignAs(al2, false, true);
222     assertEquals("ACG---GCUCCA------ACT", al1.getSequenceAt(0)
223             .getSequenceAsString());
224     assertEquals("---CGT---TAACGA---AGT", al1.getSequenceAt(1)
225             .getSequenceAsString());
226   }
227
228   /**
229    * Test aligning dna as per protein alignment, for the case where there are
230    * introns (i.e. some dna sites have no mapping from a peptide).
231    * 
232    * @throws IOException
233    */
234   @Test
235   public void testAlignAs_dnaAsProtein_withIntrons() throws IOException
236   {
237     /*
238      * Load alignments and add mappings for cDNA to protein
239      */
240     String dna1 = "A-Aa-gG-GCC-cT-TT";
241     String dna2 = "c--CCGgg-TT--T-AA-A";
242     AlignmentI al1 = loadAlignment(">Seq1\n" + dna1 + "\n>Seq2\n" + dna2
243             + "\n", "FASTA");
244     AlignmentI al2 = loadAlignment(">Seq1\n-P--YK\n>Seq2\nG-T--F\n",
245             "FASTA");
246     AlignedCodonFrame acf = new AlignedCodonFrame();
247     // Seq1 has intron at dna positions 3,4,9 so splice is AAG GCC TTT
248     // Seq2 has intron at dna positions 1,5,6 so splice is CCG TTT AAA
249     MapList ml1 = new MapList(new int[]
250     { 1, 2, 5, 8, 10, 12 }, new int[]
251     { 1, 3 }, 3, 1);
252     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml1);
253     MapList ml2 = new MapList(new int[]
254     { 2, 4, 7, 12 }, new int[]
255     { 1, 3 }, 3, 1);
256     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml2);
257     al2.addCodonFrame(acf);
258
259     /*
260      * Align ignoring gaps in dna introns and exons
261      */
262     ((Alignment) al1).alignAs(al2, false, false);
263     assertEquals("---AAagG------GCCcTTT", al1.getSequenceAt(0)
264             .getSequenceAsString());
265     // note 1 gap in protein corresponds to 'gg-' in DNA (3 positions)
266     assertEquals("cCCGgg-TTT------AAA", al1.getSequenceAt(1)
267             .getSequenceAsString());
268
269     /*
270      * Reset and realign, preserving gaps in dna introns and exons
271      */
272     al1.getSequenceAt(0).setSequence(dna1);
273     al1.getSequenceAt(1).setSequence(dna2);
274     ((Alignment) al1).alignAs(al2, true, true);
275     // String dna1 = "A-Aa-gG-GCC-cT-TT";
276     // String dna2 = "c--CCGgg-TT--T-AA-A";
277     // assumption: we include 'the greater of' protein/dna gap lengths, not both
278     assertEquals("---A-Aa-gG------GCC-cT-TT", al1.getSequenceAt(0)
279             .getSequenceAsString());
280     assertEquals("c--CCGgg-TT--T------AA-A", al1.getSequenceAt(1)
281             .getSequenceAsString());
282   }
283 }