Merge branch 'develop' into features/JAL-845splitPaneMergeDevelop
[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 yet to be implemented, does nothing.
175    * 
176    * @throws IOException
177    */
178   @Test
179   public void testAlignAs_proteinAsCdna() throws IOException
180   {
181     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
182     AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA");
183     String before0 = al2.getSequenceAt(0).getSequenceAsString();
184     String before1 = al2.getSequenceAt(1).getSequenceAsString();
185
186     ((Alignment) al2).alignAs(al1, false, true);
187     assertEquals(before0, al2.getSequenceAt(0).getSequenceAsString());
188     assertEquals(before1, al2.getSequenceAt(1).getSequenceAsString());
189   }
190
191   /**
192    * Test aligning cdna as per protein alignment.
193    * 
194    * @throws IOException
195    */
196   @Test
197   public void testAlignAs_cdnaAsProtein() throws IOException
198   {
199     /*
200      * Load alignments and add mappings for cDNA to protein
201      */
202     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
203     AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA");
204     AlignedCodonFrame acf = new AlignedCodonFrame();
205     MapList ml = new MapList(new int[]
206     { 1, 12 }, new int[]
207     { 1, 4 }, 3, 1);
208     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml);
209     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml);
210     al2.addCodonFrame(acf);
211
212     /*
213      * Realign DNA; currently keeping existing gaps in introns only
214      */
215     ((Alignment) al1).alignAs(al2, false, true);
216     assertEquals("ACG---GCUCCA------ACT", al1.getSequenceAt(0)
217             .getSequenceAsString());
218     assertEquals("---CGT---TAACGA---AGT", al1.getSequenceAt(1)
219             .getSequenceAsString());
220   }
221
222   /**
223    * Test aligning dna as per protein alignment, for the case where there are
224    * introns (i.e. some dna sites have no mapping from a peptide).
225    * 
226    * @throws IOException
227    */
228   @Test
229   public void testAlignAs_dnaAsProtein_withIntrons() throws IOException
230   {
231     /*
232      * Load alignments and add mappings for cDNA to protein
233      */
234     String dna1 = "A-Aa-gG-GCC-cT-TT";
235     String dna2 = "c--CCGgg-TT--T-AA-A";
236     AlignmentI al1 = loadAlignment(">Seq1\n" + dna1 + "\n>Seq2\n" + dna2
237             + "\n", "FASTA");
238     AlignmentI al2 = loadAlignment(">Seq1\n-P--YK\n>Seq2\nG-T--F\n",
239             "FASTA");
240     AlignedCodonFrame acf = new AlignedCodonFrame();
241     // Seq1 has intron at dna positions 3,4,9 so splice is AAG GCC TTT
242     // Seq2 has intron at dna positions 1,5,6 so splice is CCG TTT AAA
243     MapList ml1 = new MapList(new int[]
244     { 1, 2, 5, 8, 10, 12 }, new int[]
245     { 1, 3 }, 3, 1);
246     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml1);
247     MapList ml2 = new MapList(new int[]
248     { 2, 4, 7, 12 }, new int[]
249     { 1, 3 }, 3, 1);
250     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml2);
251     al2.addCodonFrame(acf);
252
253     /*
254      * Align ignoring gaps in dna introns and exons
255      */
256     ((Alignment) al1).alignAs(al2, false, false);
257     assertEquals("---AAagG------GCCcTTT", al1.getSequenceAt(0)
258             .getSequenceAsString());
259     // note 1 gap in protein corresponds to 'gg-' in DNA (3 positions)
260     assertEquals("cCCGgg-TTT------AAA", al1.getSequenceAt(1)
261             .getSequenceAsString());
262
263     /*
264      * Reset and realign, preserving gaps in dna introns and exons
265      */
266     al1.getSequenceAt(0).setSequence(dna1);
267     al1.getSequenceAt(1).setSequence(dna2);
268     ((Alignment) al1).alignAs(al2, true, true);
269     // String dna1 = "A-Aa-gG-GCC-cT-TT";
270     // String dna2 = "c--CCGgg-TT--T-AA-A";
271     // assumption: we include 'the greater of' protein/dna gap lengths, not both
272     assertEquals("---A-Aa-gG------GCC-cT-TT", al1.getSequenceAt(0)
273             .getSequenceAsString());
274     assertEquals("c--CCGgg-TT--T------AA-A", al1.getSequenceAt(1)
275             .getSequenceAsString());
276   }
277 }