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