Merge branch 'develop' into JAL-1705_trialMerge
[jalview.git] / test / jalview / datamodel / AlignedCodonFrameTest.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.assertFalse;
25 import static org.testng.AssertJUnit.assertNull;
26 import static org.testng.AssertJUnit.assertSame;
27 import static org.testng.AssertJUnit.assertTrue;
28 import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;
29
30 import jalview.util.MapList;
31
32 import java.util.Arrays;
33 import java.util.List;
34
35 import org.testng.annotations.Test;
36
37 public class AlignedCodonFrameTest
38 {
39
40   /**
41    * Test the method that locates the first aligned sequence that has a mapping.
42    */
43   @Test(groups = { "Functional" })
44   public void testFindAlignedSequence()
45   {
46     AlignmentI cdna = new Alignment(new SequenceI[] {});
47     final Sequence seq1 = new Sequence("Seq1", "C-G-TA-GC");
48     seq1.createDatasetSequence();
49     cdna.addSequence(seq1);
50     final Sequence seq2 = new Sequence("Seq2", "-TA-GG-GG");
51     seq2.createDatasetSequence();
52     cdna.addSequence(seq2);
53
54     AlignmentI aa = new Alignment(new SequenceI[] {});
55     final Sequence aseq1 = new Sequence("Seq1", "-P-R");
56     aseq1.createDatasetSequence();
57     aa.addSequence(aseq1);
58     final Sequence aseq2 = new Sequence("Seq2", "-LY-");
59     aseq2.createDatasetSequence();
60     aa.addSequence(aseq2);
61
62     /*
63      * Mapping from first DNA sequence to second AA sequence.
64      */
65     AlignedCodonFrame acf = new AlignedCodonFrame();
66
67     assertNull(acf.findAlignedSequence(seq1, aa));
68
69     MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
70     acf.addMap(seq1.getDatasetSequence(), aseq2.getDatasetSequence(), map);
71
72     /*
73      * DNA seq1 maps to AA seq2
74      */
75     assertEquals(aa.getSequenceAt(1), acf.findAlignedSequence(cdna
76             .getSequenceAt(0).getDatasetSequence(), aa));
77
78     assertEquals(cdna.getSequenceAt(0), acf.findAlignedSequence(aa
79             .getSequenceAt(1).getDatasetSequence(), cdna));
80   }
81
82   /**
83    * Test the method that locates the mapped codon for a protein position.
84    */
85   @Test(groups = { "Functional" })
86   public void testGetMappedRegion()
87   {
88     // introns lower case, exons upper case
89     final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T");
90     seq1.createDatasetSequence();
91     final Sequence seq2 = new Sequence("Seq2", "-TA-gG-Gg-CG-a");
92     seq2.createDatasetSequence();
93
94     final Sequence aseq1 = new Sequence("Seq1", "-P-R");
95     aseq1.createDatasetSequence();
96     final Sequence aseq2 = new Sequence("Seq2", "-LY-Q");
97     aseq2.createDatasetSequence();
98
99     /*
100      * First with no mappings
101      */
102     AlignedCodonFrame acf = new AlignedCodonFrame();
103
104     assertNull(acf.getMappedRegion(seq1, aseq1, 1));
105
106     /*
107      * Set up the mappings for the exons (upper-case bases)
108      * Note residue Q is unmapped
109      */
110     MapList map = new MapList(new int[] { 2, 4, 6, 6, 8, 9 }, new int[] {
111         1, 2 }, 3, 1);
112     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
113     map = new MapList(new int[] { 1, 2, 4, 5, 7, 8 }, new int[] { 1, 2 },
114             3, 1);
115     acf.addMap(seq2.getDatasetSequence(), aseq2.getDatasetSequence(), map);
116
117     assertArrayEquals(new int[] { 2, 4 },
118             acf.getMappedRegion(seq1, aseq1, 1));
119     assertArrayEquals(new int[] { 6, 6, 8, 9 },
120             acf.getMappedRegion(seq1, aseq1, 2));
121     assertArrayEquals(new int[] { 1, 2, 4, 4 },
122             acf.getMappedRegion(seq2, aseq2, 1));
123     assertArrayEquals(new int[] { 5, 5, 7, 8 },
124             acf.getMappedRegion(seq2, aseq2, 2));
125
126     /*
127      * No mapping from seq2 to Q
128      */
129     assertNull(acf.getMappedRegion(seq2, aseq2, 3));
130
131     /*
132      * No mapping from sequence 1 to sequence 2
133      */
134     assertNull(acf.getMappedRegion(seq1, aseq2, 1));
135   }
136
137   @Test(groups = { "Functional" })
138   public void testGetMappedCodons()
139   {
140     final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T");
141     seq1.createDatasetSequence();
142     final Sequence aseq1 = new Sequence("Seq1", "-V-L");
143     aseq1.createDatasetSequence();
144
145     /*
146      * First with no mappings
147      */
148     AlignedCodonFrame acf = new AlignedCodonFrame();
149
150     assertNull(acf.getMappedCodons(seq1.getDatasetSequence(), 0));
151
152     /*
153      * Set up the mappings for the exons (upper-case bases)
154      */
155     MapList map = new MapList(new int[] { 2, 4, 6, 6, 8, 9 }, new int[] {
156         1, 2 }, 3, 1);
157     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
158
159     assertEquals(1, acf.getMappedCodons(aseq1.getDatasetSequence(), 1)
160             .size());
161     assertEquals(
162             "[G, T, A]",
163             Arrays.toString(acf.getMappedCodons(aseq1.getDatasetSequence(),
164                     1).get(0)));
165     assertEquals(
166             "[C, T, T]",
167             Arrays.toString(acf.getMappedCodons(aseq1.getDatasetSequence(),
168                     2).get(0)));
169   }
170
171   /**
172    * Test for the case where there is more than one variant of the DNA mapping
173    * to a protein sequence
174    */
175   @Test(groups = { "Functional" })
176   public void testGetMappedCodons_dnaVariants()
177   {
178     final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T");
179     seq1.createDatasetSequence();
180     final Sequence seq2 = new Sequence("Seq2", "c-G-TT-gT-gT-A");
181     seq2.createDatasetSequence();
182     final Sequence aseq1 = new Sequence("Seq1", "-V-L");
183     aseq1.createDatasetSequence();
184
185     AlignedCodonFrame acf = new AlignedCodonFrame();
186
187     /*
188      * Set up the mappings for the exons (upper-case bases)
189      */
190     MapList map = new MapList(new int[] { 2, 4, 6, 6, 8, 9 }, new int[] {
191         1, 2 }, 3, 1);
192     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
193     acf.addMap(seq2.getDatasetSequence(), aseq1.getDatasetSequence(), map);
194
195     assertEquals(2, acf.getMappedCodons(aseq1.getDatasetSequence(), 1)
196             .size());
197     List<char[]> codonsForV = acf.getMappedCodons(
198             aseq1.getDatasetSequence(), 1);
199     assertEquals("[G, T, A]", Arrays.toString(codonsForV.get(0)));
200     assertEquals("[G, T, T]", Arrays.toString(codonsForV.get(1)));
201     List<char[]> codonsForL = acf.getMappedCodons(
202             aseq1.getDatasetSequence(), 2);
203     assertEquals("[C, T, T]", Arrays.toString(codonsForL.get(0)));
204     assertEquals("[T, T, A]", Arrays.toString(codonsForL.get(1)));
205   }
206
207   /**
208    * Test for the case where sequences have start > 1
209    */
210   @Test(groups = { "Functional" })
211   public void testGetMappedCodons_forSubSequences()
212   {
213     final Sequence seq1 = new Sequence("Seq1", "c-G-TA-gC-gT-T", 27, 35);
214     seq1.createDatasetSequence();
215
216     final Sequence aseq1 = new Sequence("Seq1", "-V-L", 12, 13);
217     aseq1.createDatasetSequence();
218
219     /*
220      * Set up the mappings for the exons (upper-case bases)
221      */
222     AlignedCodonFrame acf = new AlignedCodonFrame();
223     MapList map = new MapList(new int[] { 28, 30, 32, 32, 34, 35 },
224             new int[] { 12, 13 }, 3, 1);
225     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
226
227     assertEquals(
228             "[G, T, A]",
229             Arrays.toString(acf.getMappedCodons(aseq1.getDatasetSequence(),
230                     12).get(0)));
231     assertEquals(
232             "[C, T, T]",
233             Arrays.toString(acf.getMappedCodons(aseq1.getDatasetSequence(),
234                     13).get(0)));
235   }
236
237   @Test(groups = { "Functional" })
238   public void testCouldReplaceSequence()
239   {
240     SequenceI seq1 = new Sequence("Seq1/10-21", "aaacccgggttt");
241     SequenceI seq1proxy = new SequenceDummy("Seq1");
242
243     // map to region within sequence is ok
244     assertTrue(AlignedCodonFrame.couldRealiseSequence(seq1proxy, seq1, 12,
245             17));
246     // map to region overlapping sequence is ok
247     assertTrue(AlignedCodonFrame.couldRealiseSequence(seq1proxy, seq1, 5,
248             10));
249     assertTrue(AlignedCodonFrame.couldRealiseSequence(seq1proxy, seq1, 21,
250             26));
251     // map to region before sequence is not ok
252     assertFalse(AlignedCodonFrame.couldRealiseSequence(seq1proxy, seq1, 4,
253             9));
254     // map to region after sequence is not ok
255     assertFalse(AlignedCodonFrame.couldRealiseSequence(seq1proxy, seq1, 22,
256             27));
257
258     /*
259      * test should fail if name doesn't match
260      */
261     seq1proxy.setName("Seq1a");
262     assertFalse(AlignedCodonFrame.couldRealiseSequence(seq1proxy, seq1, 12,
263             17));
264     seq1proxy.setName("Seq1");
265     seq1.setName("Seq1a");
266     assertFalse(AlignedCodonFrame.couldRealiseSequence(seq1proxy, seq1, 12,
267             17));
268
269     /*
270      * a dummy sequence can't replace a real one
271      */
272     assertFalse(AlignedCodonFrame.couldRealiseSequence(seq1, seq1proxy, 12,
273             17));
274
275     /*
276      * a dummy sequence can't replace a dummy sequence
277      */
278     SequenceI seq1proxy2 = new SequenceDummy("Seq1");
279     assertFalse(AlignedCodonFrame.couldRealiseSequence(seq1proxy,
280             seq1proxy2, 12, 17));
281
282     /*
283      * a real sequence can't replace a real one
284      */
285     SequenceI seq1a = new Sequence("Seq1/10-21", "aaacccgggttt");
286     assertFalse(AlignedCodonFrame.couldRealiseSequence(seq1, seq1a, 12, 17));
287   }
288
289   /**
290    * Tests for the method that tests whether any mapping to a dummy sequence can
291    * be 'realised' to a given real sequence
292    */
293   @Test(groups = { "Functional" })
294   public void testIsRealisableWith()
295   {
296     SequenceI seq1 = new Sequence("Seq1", "tttaaaCCCGGGtttaaa");
297     SequenceI seq2 = new Sequence("Seq2", "PG");
298     SequenceI seq1proxy = new SequenceDummy("Seq1");
299     seq1.createDatasetSequence();
300     seq2.createDatasetSequence();
301     MapList mapList = new MapList(new int[] { 7, 12 }, new int[] { 2, 3 },
302             3, 1);
303     AlignedCodonFrame acf = new AlignedCodonFrame();
304     acf.addMap(seq1proxy, seq2, mapList);
305
306     /*
307      * Seq2 is mapped to SequenceDummy seq1proxy bases 4-9
308      * This is 'realisable' from real sequence Seq1
309      */
310     assertTrue(acf.isRealisableWith(seq1));
311
312     /*
313      * test should fail if name doesn't match
314      */
315     seq1proxy.setName("Seq1a");
316     assertFalse(acf.isRealisableWith(seq1));
317     seq1proxy.setName("Seq1");
318
319     SequenceI seq1ds = seq1.getDatasetSequence();
320     seq1ds.setName("Seq1a");
321     assertFalse(acf.isRealisableWith(seq1));
322     seq1ds.setName("Seq1");
323
324     /*
325      * test should fail if no sequence overlap with mapping of bases 7-12
326      * use artificial start/end values to test this
327      */
328     seq1ds.setStart(1);
329     seq1ds.setEnd(6);
330     // seq1 precedes mapped region:
331     assertFalse(acf.isRealisableWith(seq1));
332     seq1ds.setEnd(7);
333     // seq1 includes first mapped base:
334     assertTrue(acf.isRealisableWith(seq1));
335     seq1ds.setStart(13);
336     seq1ds.setEnd(18);
337     // seq1 follows mapped region:
338     assertFalse(acf.isRealisableWith(seq1));
339     seq1ds.setStart(12);
340     // seq1 includes last mapped base:
341     assertTrue(acf.isRealisableWith(seq1));
342   }
343
344   /**
345    * Tests for the method that converts mappings to a dummy sequence to mappings
346    * to a compatible real sequence
347    */
348   @Test(groups = { "Functional" })
349   public void testRealiseWith()
350   {
351     SequenceI seq1 = new Sequence("Seq1", "tttCAACCCGGGtttaaa");
352     SequenceI seq2 = new Sequence("Seq2", "QPG");
353     SequenceI seq2a = new Sequence("Seq2a", "QPG");
354     SequenceI seq1proxy = new SequenceDummy("Seq1");
355     seq1.createDatasetSequence();
356     seq2.createDatasetSequence();
357     seq2a.createDatasetSequence();
358
359     /*
360      * Make mappings from Seq2 and Seq2a peptides to dummy sequence Seq1
361      */
362     AlignedCodonFrame acf = new AlignedCodonFrame();
363
364     // map PG to codons 7-12 (CCCGGG)
365     MapList mapping1 = new MapList(new int[] { 7, 12 }, new int[] { 2, 3 },
366             3, 1);
367     acf.addMap(seq1proxy, seq2, mapping1);
368     acf.addMap(seq1proxy, seq2a, mapping1);
369
370     // map QP to codons 4-9 (CAACCC)
371     MapList mapping2 = new MapList(new int[] { 4, 9 }, new int[] { 1, 2 },
372             3, 1);
373     acf.addMap(seq1proxy, seq2, mapping2);
374     acf.addMap(seq1proxy, seq2a, mapping2);
375
376     /*
377      * acf now has two mappings one from Seq1 to Seq2, one from Seq1 to Seq2a
378      */
379     assertEquals(2, acf.getdnaSeqs().length);
380     assertSame(seq1proxy, acf.getdnaSeqs()[0]);
381     assertSame(seq1proxy, acf.getdnaSeqs()[1]);
382     assertEquals(2, acf.getProtMappings().length);
383
384     // 'realise' these mappings with the compatible sequence seq1
385     // two mappings should be updated:
386     assertEquals(2, acf.realiseWith(seq1));
387     assertSame(seq1.getDatasetSequence(), acf.getdnaSeqs()[0]);
388     assertSame(seq1.getDatasetSequence(), acf.getdnaSeqs()[1]);
389   }
390
391   /**
392    * Test the method that locates the mapped codon for a protein position.
393    */
394   @Test(groups = { "Functional" })
395   public void testGetMappedRegion_eitherWay()
396   {
397     final Sequence seq1 = new Sequence("Seq1", "AAACCCGGGTTT");
398     seq1.createDatasetSequence();
399     final Sequence seq2 = new Sequence("Seq2", "KPGF");
400     seq2.createDatasetSequence();
401     final Sequence seq3 = new Sequence("Seq3", "QYKPGFSW");
402     seq3.createDatasetSequence();
403
404     /*
405      * map Seq1 to all of Seq2 and part of Seq3
406      */
407     AlignedCodonFrame acf = new AlignedCodonFrame();
408     MapList map = new MapList(new int[] { 1, 12 }, new int[] { 1, 4 }, 3, 1);
409     acf.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
410     map = new MapList(new int[] { 1, 12 }, new int[] { 3, 6 }, 3, 1);
411     acf.addMap(seq1.getDatasetSequence(), seq3.getDatasetSequence(), map);
412
413     /*
414      * map part of Seq3 to Seq2
415      */
416     map = new MapList(new int[] { 3, 6 }, new int[] { 1, 4 }, 1, 1);
417     acf.addMap(seq3.getDatasetSequence(), seq2.getDatasetSequence(), map);
418
419     /*
420      * original case - locate mapped codon for protein position
421      */
422     assertArrayEquals(new int[] { 4, 6 },
423             acf.getMappedRegion(seq1, seq2, 2));
424     assertArrayEquals(new int[] { 7, 9 },
425             acf.getMappedRegion(seq1, seq3, 5));
426     assertNull(acf.getMappedRegion(seq1, seq3, 1));
427
428     /*
429      * locate mapped protein for protein position
430      */
431     assertArrayEquals(new int[] { 4, 4 },
432             acf.getMappedRegion(seq3, seq2, 2));
433
434     /*
435      * reverse location protein-to-protein
436      */
437     assertArrayEquals(new int[] { 2, 2 },
438             acf.getMappedRegion(seq2, seq3, 4));
439
440     /*
441      * reverse location protein-from-nucleotide
442      * any of codon [4, 5, 6] positions map to seq2/2
443      */
444     assertArrayEquals(new int[] { 2, 2 },
445             acf.getMappedRegion(seq2, seq1, 4));
446     assertArrayEquals(new int[] { 2, 2 },
447             acf.getMappedRegion(seq2, seq1, 5));
448     assertArrayEquals(new int[] { 2, 2 },
449             acf.getMappedRegion(seq2, seq1, 6));
450   }
451 }