JAL-1619 refactoring / tests to support 'align linked dna as protein'
[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   /**
109    * Tests for realigning as per a supplied alignment: Dna as Dna.
110    * 
111    * Note: AlignedCodonFrame's state variables are named for protein-to-cDNA
112    * mapping, but can be exploited for a general 'sequence-to-sequence' mapping
113    * as here.
114    * 
115    * @throws IOException
116    */
117   @Test
118   public void testAlignAs_dnaAsDna() throws IOException
119   {
120     // aligned cDNA:
121     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
122     // unaligned cDNA:
123     AlignmentI al2 = loadAlignment(CDNA_SEQS_2, "FASTA");
124
125     /*
126      * Make mappings between sequences. The 'aligned cDNA' is playing the role
127      * of what would normally be protein here.
128      */
129     AlignedCodonFrame acf = new AlignedCodonFrame();
130     MapList ml = new MapList(new int[]
131     { 1, 12 }, new int[]
132     { 1, 12 }, 1, 1);
133     acf.addMap(al2.getSequenceAt(0), al1.getSequenceAt(0), ml);
134     acf.addMap(al2.getSequenceAt(1), al1.getSequenceAt(1), ml);
135     al1.addCodonFrame(acf);
136
137     al2.alignAs(al1);
138     assertEquals("GC-TC--GUC-GTA-CT", al2.getSequenceAt(0)
139             .getSequenceAsString());
140     assertEquals("-GG-GTC--AGG---CAGT", al2.getSequenceAt(1)
141             .getSequenceAsString());
142   }
143
144   /**
145    * Aligning protein from cDNA yet to be implemented, does nothing.
146    * 
147    * @throws IOException
148    */
149   @Test
150   public void testAlignAs_proteinAsCdna() throws IOException
151   {
152     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
153     AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA");
154     String before0 = al2.getSequenceAt(0).getSequenceAsString();
155     String before1 = al2.getSequenceAt(1).getSequenceAsString();
156
157     al2.alignAs(al1);
158     assertEquals(before0, al2.getSequenceAt(0).getSequenceAsString());
159     assertEquals(before1, al2.getSequenceAt(1).getSequenceAsString());
160   }
161
162   /**
163    * Test aligning cdna as per protein alignment.
164    * 
165    * @throws IOException
166    */
167   @Test
168   public void testAlignAs_cdnaAsProtein() throws IOException
169   {
170     /*
171      * Load alignments and add mappings for cDNA to protein
172      */
173     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
174     AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA");
175     AlignedCodonFrame acf = new AlignedCodonFrame();
176     MapList ml = new MapList(new int[]
177     { 1, 12 }, new int[]
178     { 1, 4 }, 3, 1);
179     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml);
180     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml);
181     al2.addCodonFrame(acf);
182
183     al1.alignAs(al2);
184     assertEquals("AC-G---G--CUC-CA------A-CT", al1.getSequenceAt(0)
185             .getSequenceAsString());
186     assertEquals("---CG-T---TA--ACG---A---AGT", al1.getSequenceAt(1)
187             .getSequenceAsString());
188   }
189
190   /**
191    * Test aligning cdna (with introns) as per protein alignment.
192    * 
193    * @throws IOException
194    */
195   @Test
196   public void testAlignAs_cdnaAsProteinWithIntrons() throws IOException
197   {
198     /*
199      * Load alignments and add mappings for cDNA to protein
200      */
201     AlignmentI al1 = loadAlignment(CDNA_SEQS_1, "FASTA");
202     AlignmentI al2 = loadAlignment(AA_SEQS_1, "FASTA");
203     AlignedCodonFrame acf = new AlignedCodonFrame();
204     MapList ml = new MapList(new int[]
205     { 1, 12 }, new int[]
206     { 1, 4 }, 3, 1);
207     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml);
208     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml);
209     al2.addCodonFrame(acf);
210
211     al1.alignAs(al2);
212     assertEquals("AC-G---G--CUC-CA------A-CT", al1.getSequenceAt(0)
213             .getSequenceAsString());
214     assertEquals("---CG-T---TA--ACG---A---AGT", al1.getSequenceAt(1)
215             .getSequenceAsString());
216   }
217
218   /**
219    * Test aligning dna as per protein alignment, for the case where there are
220    * introns (i.e. some dna sites have no mapping from a peptide).
221    * 
222    * @throws IOException
223    */
224   @Test
225   public void testAlignAs_dnaAsProtein_withIntrons() throws IOException
226   {
227     /*
228      * Load alignments and add mappings for cDNA to protein
229      */
230     String dna1 = "A-Aa-gG-GCC-cT-TT";
231     String dna2 = "c--CCGgg-TT--T-AA-A";
232     AlignmentI al1 = loadAlignment(">Seq1\n" + dna1 + "\n>Seq2\n" + dna2
233             + "\n", "FASTA");
234     AlignmentI al2 = loadAlignment(">Seq1\n-P--YK\n>Seq2\nG-T--F\n",
235             "FASTA");
236     AlignedCodonFrame acf = new AlignedCodonFrame();
237     // Seq1 has intron at dna positions 3,4,9 so splice is AAG GCC TTT
238     // Seq2 has intron at dna positions 1,5,6 so splice is CCG TTT AAA
239     MapList ml1 = new MapList(new int[]
240     { 1, 2, 5, 8, 10, 12 }, new int[]
241     { 1, 3 }, 3, 1);
242     acf.addMap(al1.getSequenceAt(0), al2.getSequenceAt(0), ml1);
243     MapList ml2 = new MapList(new int[]
244     { 2, 4, 7, 12 }, new int[]
245     { 1, 3 }, 3, 1);
246     acf.addMap(al1.getSequenceAt(1), al2.getSequenceAt(1), ml2);
247     al2.addCodonFrame(acf);
248
249     /*
250      * Align ignoring gaps in dna introns and exons
251      */
252     ((Alignment) al1).alignAs(al2, false, false);
253     assertEquals("---AAagG------GCCcTTT", al1.getSequenceAt(0)
254             .getSequenceAsString());
255     assertEquals("cCCGgg---TTT------AAA", al1.getSequenceAt(1)
256             .getSequenceAsString());
257
258     /*
259      * Reset and realign, preserving gaps in dna introns and exons
260      */
261     al1.getSequenceAt(0).setSequence(dna1);
262     al1.getSequenceAt(1).setSequence(dna2);
263     ((Alignment) al1).alignAs(al2, true, true);
264     // String dna1 = "A-Aa-gG-GCC-cT-TT";
265     // String dna2 = "c--CCGgg-TT--T-AA-A";
266     // assumption: we include 'the greater of' protein/dna gap lengths, not both
267     assertEquals("---A-Aa-gG------GCC-cT-TT", al1.getSequenceAt(0)
268             .getSequenceAsString());
269     assertEquals("c--CCGgg---TT--T------AA-A", al1.getSequenceAt(1)
270             .getSequenceAsString());
271   }
272 }