JAL-845 applet colour by tree; translate as cDNA; pull up history list
[jalview.git] / test / jalview / util / MappingUtilsTest.java
1 package jalview.util;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertSame;
5 import static org.junit.Assert.assertTrue;
6 import static org.junit.Assert.fail;
7 import jalview.api.AlignViewportI;
8 import jalview.datamodel.AlignedCodonFrame;
9 import jalview.datamodel.Alignment;
10 import jalview.datamodel.AlignmentI;
11 import jalview.datamodel.ColumnSelection;
12 import jalview.datamodel.SearchResults;
13 import jalview.datamodel.SearchResults.Match;
14 import jalview.datamodel.Sequence;
15 import jalview.datamodel.SequenceGroup;
16 import jalview.gui.AlignViewport;
17 import jalview.io.AppletFormatAdapter;
18 import jalview.io.FormatAdapter;
19
20 import java.awt.Color;
21 import java.io.IOException;
22 import java.util.Collections;
23 import java.util.Set;
24
25 import org.junit.Test;
26
27 public class MappingUtilsTest
28 {
29   private AlignViewportI dnaView;
30   private AlignViewportI proteinView;
31
32   /**
33    * Simple test of mapping with no intron involved.
34    */
35   @Test
36   public void testBuildSearchResults()
37   {
38     final Sequence seq1 = new Sequence("Seq1", "C-G-TA-GC");
39     seq1.createDatasetSequence();
40
41     final Sequence aseq1 = new Sequence("Seq1", "-P-R");
42     aseq1.createDatasetSequence();
43
44     /*
45      * Map dna bases 1-6 to protein residues 1-2
46      */
47     AlignedCodonFrame acf = new AlignedCodonFrame();
48     MapList map = new MapList(new int[]
49     { 1, 6 }, new int[]
50     { 1, 2 }, 3, 1);
51     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
52     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
53
54     /*
55      * Check protein residue 1 maps to codon 1-3, 2 to codon 4-6
56      */
57     SearchResults sr = MappingUtils.buildSearchResults(aseq1, 1, acfList);
58     assertEquals(1, sr.getResults().size());
59     Match m = sr.getResults().get(0);
60     assertEquals(seq1.getDatasetSequence(), m.getSequence());
61     assertEquals(1, m.getStart());
62     assertEquals(3, m.getEnd());
63     sr = MappingUtils.buildSearchResults(aseq1, 2, acfList);
64     assertEquals(1, sr.getResults().size());
65     m = sr.getResults().get(0);
66     assertEquals(seq1.getDatasetSequence(), m.getSequence());
67     assertEquals(4, m.getStart());
68     assertEquals(6, m.getEnd());
69
70     /*
71      * Check inverse mappings, from codons 1-3, 4-6 to protein 1, 2
72      */
73     for (int i = 1; i < 7; i++)
74     {
75       sr = MappingUtils.buildSearchResults(seq1, i, acfList);
76       assertEquals(1, sr.getResults().size());
77       m = sr.getResults().get(0);
78       assertEquals(aseq1.getDatasetSequence(), m.getSequence());
79       int residue = i > 3 ? 2 : 1;
80       assertEquals(residue, m.getStart());
81       assertEquals(residue, m.getEnd());
82     }
83   }
84
85   /**
86    * Simple test of mapping with introns involved.
87    */
88   @Test
89   public void testBuildSearchResults_withIntro()
90   {
91     final Sequence seq1 = new Sequence("Seq1", "C-G-TAGA-GCAGCTT");
92     seq1.createDatasetSequence();
93   
94     final Sequence aseq1 = new Sequence("Seq1", "-P-R");
95     aseq1.createDatasetSequence();
96   
97     /*
98      * Map dna bases [2, 4, 5], [7, 9, 11] to protein residues 1 and 2
99      */
100     AlignedCodonFrame acf = new AlignedCodonFrame();
101     MapList map = new MapList(new int[]
102     { 2, 2, 4, 5, 7, 7, 9, 9, 11, 11 }, new int[]
103     { 1, 2 }, 3, 1);
104     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
105     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
106   
107     /*
108      * Check protein residue 1 maps to [2, 4, 5]
109      */
110     SearchResults sr = MappingUtils.buildSearchResults(aseq1, 1, acfList);
111     assertEquals(2, sr.getResults().size());
112     Match m = sr.getResults().get(0);
113     assertEquals(seq1.getDatasetSequence(), m.getSequence());
114     assertEquals(2, m.getStart());
115     assertEquals(2, m.getEnd());
116     m = sr.getResults().get(1);
117     assertEquals(seq1.getDatasetSequence(), m.getSequence());
118     assertEquals(4, m.getStart());
119     assertEquals(5, m.getEnd());
120
121     /*
122      * Check protein residue 2 maps to [7, 9, 11]
123      */
124     sr = MappingUtils.buildSearchResults(aseq1, 2, acfList);
125     assertEquals(3, sr.getResults().size());
126     m = sr.getResults().get(0);
127     assertEquals(seq1.getDatasetSequence(), m.getSequence());
128     assertEquals(7, m.getStart());
129     assertEquals(7, m.getEnd());
130     m = sr.getResults().get(1);
131     assertEquals(seq1.getDatasetSequence(), m.getSequence());
132     assertEquals(9, m.getStart());
133     assertEquals(9, m.getEnd());
134     m = sr.getResults().get(2);
135     assertEquals(seq1.getDatasetSequence(), m.getSequence());
136     assertEquals(11, m.getStart());
137     assertEquals(11, m.getEnd());
138   
139     /*
140      * Check inverse mappings, from codons to protein
141      */
142     for (int i = 1; i < 14; i++)
143     {
144       sr = MappingUtils.buildSearchResults(seq1, i, acfList);
145       int residue = (i == 2 || i == 4 || i == 5) ? 1 : (i == 7 || i == 9
146               || i == 11 ? 2 : 0);
147       if (residue == 0)
148       {
149         assertEquals(0, sr.getResults().size());
150         continue;
151       }
152       assertEquals(1, sr.getResults().size());
153       m = sr.getResults().get(0);
154       assertEquals(aseq1.getDatasetSequence(), m.getSequence());
155       assertEquals(residue, m.getStart());
156       assertEquals(residue, m.getEnd());
157     }
158   }
159
160   /**
161    * Test mapping a sequence group.
162    * 
163    * @throws IOException
164    */
165   @Test
166   public void testMapSequenceGroup() throws IOException
167   {
168     /*
169      * Set up dna and protein Seq1/2/3 with mappings (held on the protein
170      * viewport).
171      */
172     AlignmentI cdna = loadAlignment(">Seq1\nACG\n>Seq2\nTGA\n>Seq3\nTAC\n",
173             "FASTA");
174     cdna.setDataset(null);
175     AlignmentI protein = loadAlignment(">Seq1\nK\n>Seq2\nL\n>Seq3\nQ\n",
176             "FASTA");
177     protein.setDataset(null);
178     AlignedCodonFrame acf = new AlignedCodonFrame();
179     MapList map = new MapList(new int[]
180     { 1, 3 }, new int[]
181     { 1, 1 }, 3, 1);
182     for (int seq = 0; seq < 3; seq++)
183     {
184       acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
185               .getSequenceAt(seq).getDatasetSequence(), map);
186     }
187     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
188
189     AlignViewportI dnaView = new AlignViewport(cdna);
190     AlignViewportI proteinView = new AlignViewport(protein);
191     protein.setCodonFrames(acfList);
192
193     /*
194      * Select Seq1 and Seq3 in the protein
195      */
196     SequenceGroup sg = new SequenceGroup();
197     sg.setColourText(true);
198     sg.setIdColour(Color.GREEN);
199     sg.setOutlineColour(Color.LIGHT_GRAY);
200     sg.addSequence(protein.getSequenceAt(0), false);
201     sg.addSequence(protein.getSequenceAt(2), false);
202
203     /*
204      * Verify the mapped sequence group in dna
205      */
206     SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg, proteinView, dnaView);
207     assertTrue(mappedGroup.getColourText());
208     assertSame(sg.getIdColour(), mappedGroup.getIdColour());
209     assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
210     assertEquals(2, mappedGroup.getSequences().size());
211     assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
212     assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
213
214     /*
215      * Verify mapping sequence group from dna to protein
216      */
217     sg.clear();
218     sg.addSequence(cdna.getSequenceAt(1), false);
219     sg.addSequence(cdna.getSequenceAt(0), false);
220     mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
221     assertTrue(mappedGroup.getColourText());
222     assertSame(sg.getIdColour(), mappedGroup.getIdColour());
223     assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
224     assertEquals(2, mappedGroup.getSequences().size());
225     assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
226     assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
227   }
228
229   /**
230    * Helper method to load an alignment and ensure dataset sequences are set up.
231    * 
232    * @param data
233    * @param format
234    *          TODO
235    * @return
236    * @throws IOException
237    */
238   protected AlignmentI loadAlignment(final String data, String format)
239           throws IOException
240   {
241     Alignment a = new FormatAdapter().readFile(data,
242             AppletFormatAdapter.PASTE, format);
243     a.setDataset(null);
244     return a;
245   }
246
247   /**
248    * Test mapping a column selection in protein to its dna equivalent
249    * 
250    * @throws IOException
251    */
252   @Test
253   public void testMapColumnSelection_proteinToDna() throws IOException
254   {
255     setupMappedAlignments();
256   
257     ColumnSelection colsel = new ColumnSelection();
258
259     /*
260      * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
261      * in dna respectively, overall 0-4
262      */
263     colsel.addElement(0);
264     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel,
265             proteinView, dnaView);
266     assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
267
268     /*
269      * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
270      */
271     colsel.clear();
272     colsel.addElement(1);
273     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
274     assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
275
276     /*
277      * Column 2 in protein picks up gaps only - no mapping
278      */
279     colsel.clear();
280     colsel.addElement(2);
281     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
282     assertEquals("[]", cs.getSelected().toString());
283
284     /*
285      * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
286      * 6-9, 6-10, 5-8 respectively, overall to 5-10
287      */
288     colsel.clear();
289     colsel.addElement(3);
290     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
291     assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
292
293     /*
294      * Combine selection of columns 1 and 3 to get a discontiguous mapped
295      * selection
296      */
297     colsel.clear();
298     colsel.addElement(1);
299     colsel.addElement(3);
300     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
301     assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
302             .toString());
303   }
304
305   /**
306    * @throws IOException
307    */
308   protected void setupMappedAlignments() throws IOException
309   {
310     /*
311      * Set up dna and protein Seq1/2/3 with mappings (held on the protein
312      * viewport). Lower case for introns.
313      */
314     AlignmentI cdna = loadAlignment(">Seq1\nAC-GctGtC-T\n"
315             + ">Seq2\nTc-GA-G-T-Tc\n" + ">Seq3\nTtTT-AaCGg-\n",
316             "FASTA");
317     cdna.setDataset(null);
318     AlignmentI protein = loadAlignment(
319             ">Seq1\n-K-P\n>Seq2\nL--Q\n>Seq3\nG--S\n",
320             "FASTA");
321     protein.setDataset(null);
322     AlignedCodonFrame acf = new AlignedCodonFrame();
323     MapList map = new MapList(new int[]
324     { 1, 3, 6, 6, 8, 9 }, new int[]
325     { 1, 2 }, 3, 1);
326     acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(), protein
327             .getSequenceAt(0).getDatasetSequence(), map);
328     map = new MapList(new int[]
329     { 1, 1, 3, 4, 5, 7 }, new int[]
330     { 1, 2 }, 3, 1);
331     acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(), protein
332             .getSequenceAt(1).getDatasetSequence(), map);
333     map = new MapList(new int[]
334     { 1, 1, 3, 4, 5, 5, 7, 8 }, new int[]
335     { 1, 2 }, 3, 1);
336     acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(), protein
337             .getSequenceAt(2).getDatasetSequence(), map);
338     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
339   
340     dnaView = new AlignViewport(cdna);
341     proteinView = new AlignViewport(protein);
342     protein.setCodonFrames(acfList);
343   }
344
345   /**
346    * Test mapping a column selection including hidden columns
347    * 
348    * @throws IOException
349    */
350   @Test
351   public void testMapColumnSelection_hiddenColumns() throws IOException
352   {
353     setupMappedAlignments();
354
355     ColumnSelection colsel = new ColumnSelection();
356   
357     /*
358      * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
359      * in dna respectively, overall 0-4
360      */
361     colsel.addElement(0);
362     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel,
363             proteinView, dnaView);
364     assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
365
366     fail("write me");
367   }
368
369   /**
370    * Test mapping a column selection in dna to its protein equivalent
371    * 
372    * @throws IOException
373    */
374   @Test
375   public void testMapColumnSelection_dnaToProtein() throws IOException
376   {
377     setupMappedAlignments();
378   
379     ColumnSelection colsel = new ColumnSelection();
380   
381     /*
382      * Column 0 in dna picks up first bases which map to residue 1, columns 0-1
383      * in protein.
384      */
385     colsel.addElement(0);
386     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, dnaView,
387             proteinView);
388     assertEquals("[0, 1]", cs.getSelected().toString());
389
390     /*
391      * Columns 3-5 in dna map to the first residues in protein Seq1, Seq2, and
392      * the first two in Seq3. Overall to columns 0, 1, 3 (col2 is all gaps).
393      */
394     colsel.addElement(3);
395     colsel.addElement(4);
396     colsel.addElement(5);
397     cs = MappingUtils.mapColumnSelection(colsel, dnaView, proteinView);
398     assertEquals("[0, 1, 3]", cs.getSelected().toString());
399   }
400 }