JAL-1645 Version-Rel Version 2.9 Year-Rel 2015 Licensing glob
[jalview.git] / test / jalview / util / MappingUtilsTest.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
3  * Copyright (C) 2015 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.util;
22
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertSame;
25 import static org.testng.AssertJUnit.assertTrue;
26
27 import jalview.api.AlignViewportI;
28 import jalview.datamodel.AlignedCodonFrame;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.ColumnSelection;
31 import jalview.datamodel.SearchResults;
32 import jalview.datamodel.SearchResults.Match;
33 import jalview.datamodel.Sequence;
34 import jalview.datamodel.SequenceGroup;
35 import jalview.datamodel.SequenceI;
36 import jalview.gui.AlignViewport;
37 import jalview.io.AppletFormatAdapter;
38 import jalview.io.FormatAdapter;
39
40 import java.awt.Color;
41 import java.io.IOException;
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.HashSet;
45 import java.util.List;
46 import java.util.Set;
47
48 import org.testng.annotations.Test;
49
50 public class MappingUtilsTest
51 {
52   private AlignViewportI dnaView;
53
54   private AlignViewportI proteinView;
55
56   /**
57    * Simple test of mapping with no intron involved.
58    */
59   @Test(groups = { "Functional" })
60   public void testBuildSearchResults()
61   {
62     final Sequence seq1 = new Sequence("Seq1", "C-G-TA-GC");
63     seq1.createDatasetSequence();
64
65     final Sequence aseq1 = new Sequence("Seq1", "-P-R");
66     aseq1.createDatasetSequence();
67
68     /*
69      * Map dna bases 1-6 to protein residues 1-2
70      */
71     AlignedCodonFrame acf = new AlignedCodonFrame();
72     MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
73     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
74     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
75
76     /*
77      * Check protein residue 1 maps to codon 1-3, 2 to codon 4-6
78      */
79     SearchResults sr = MappingUtils.buildSearchResults(aseq1, 1, acfList);
80     assertEquals(1, sr.getResults().size());
81     Match m = sr.getResults().get(0);
82     assertEquals(seq1.getDatasetSequence(), m.getSequence());
83     assertEquals(1, m.getStart());
84     assertEquals(3, m.getEnd());
85     sr = MappingUtils.buildSearchResults(aseq1, 2, acfList);
86     assertEquals(1, sr.getResults().size());
87     m = sr.getResults().get(0);
88     assertEquals(seq1.getDatasetSequence(), m.getSequence());
89     assertEquals(4, m.getStart());
90     assertEquals(6, m.getEnd());
91
92     /*
93      * Check inverse mappings, from codons 1-3, 4-6 to protein 1, 2
94      */
95     for (int i = 1; i < 7; i++)
96     {
97       sr = MappingUtils.buildSearchResults(seq1, i, acfList);
98       assertEquals(1, sr.getResults().size());
99       m = sr.getResults().get(0);
100       assertEquals(aseq1.getDatasetSequence(), m.getSequence());
101       int residue = i > 3 ? 2 : 1;
102       assertEquals(residue, m.getStart());
103       assertEquals(residue, m.getEnd());
104     }
105   }
106
107   /**
108    * Simple test of mapping with introns involved.
109    */
110   @Test(groups = { "Functional" })
111   public void testBuildSearchResults_withIntron()
112   {
113     final Sequence seq1 = new Sequence("Seq1", "C-G-TAGA-GCAGCTT");
114     seq1.createDatasetSequence();
115
116     final Sequence aseq1 = new Sequence("Seq1", "-P-R");
117     aseq1.createDatasetSequence();
118
119     /*
120      * Map dna bases [2, 4, 5], [7, 9, 11] to protein residues 1 and 2
121      */
122     AlignedCodonFrame acf = new AlignedCodonFrame();
123     MapList map = new MapList(new int[] { 2, 2, 4, 5, 7, 7, 9, 9, 11, 11 },
124             new int[] { 1, 2 }, 3, 1);
125     acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
126     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
127
128     /*
129      * Check protein residue 1 maps to [2, 4, 5]
130      */
131     SearchResults sr = MappingUtils.buildSearchResults(aseq1, 1, acfList);
132     assertEquals(2, sr.getResults().size());
133     Match m = sr.getResults().get(0);
134     assertEquals(seq1.getDatasetSequence(), m.getSequence());
135     assertEquals(2, m.getStart());
136     assertEquals(2, m.getEnd());
137     m = sr.getResults().get(1);
138     assertEquals(seq1.getDatasetSequence(), m.getSequence());
139     assertEquals(4, m.getStart());
140     assertEquals(5, m.getEnd());
141
142     /*
143      * Check protein residue 2 maps to [7, 9, 11]
144      */
145     sr = MappingUtils.buildSearchResults(aseq1, 2, acfList);
146     assertEquals(3, sr.getResults().size());
147     m = sr.getResults().get(0);
148     assertEquals(seq1.getDatasetSequence(), m.getSequence());
149     assertEquals(7, m.getStart());
150     assertEquals(7, m.getEnd());
151     m = sr.getResults().get(1);
152     assertEquals(seq1.getDatasetSequence(), m.getSequence());
153     assertEquals(9, m.getStart());
154     assertEquals(9, m.getEnd());
155     m = sr.getResults().get(2);
156     assertEquals(seq1.getDatasetSequence(), m.getSequence());
157     assertEquals(11, m.getStart());
158     assertEquals(11, m.getEnd());
159
160     /*
161      * Check inverse mappings, from codons to protein
162      */
163     for (int i = 1; i < 14; i++)
164     {
165       sr = MappingUtils.buildSearchResults(seq1, i, acfList);
166       int residue = (i == 2 || i == 4 || i == 5) ? 1 : (i == 7 || i == 9
167               || i == 11 ? 2 : 0);
168       if (residue == 0)
169       {
170         assertEquals(0, sr.getResults().size());
171         continue;
172       }
173       assertEquals(1, sr.getResults().size());
174       m = sr.getResults().get(0);
175       assertEquals(aseq1.getDatasetSequence(), m.getSequence());
176       assertEquals(residue, m.getStart());
177       assertEquals(residue, m.getEnd());
178     }
179   }
180
181   /**
182    * Test mapping a sequence group made of entire sequences.
183    * 
184    * @throws IOException
185    */
186   @Test(groups = { "Functional" })
187   public void testMapSequenceGroup_sequences() throws IOException
188   {
189     /*
190      * Set up dna and protein Seq1/2/3 with mappings (held on the protein
191      * viewport).
192      */
193     AlignmentI cdna = loadAlignment(">Seq1\nACG\n>Seq2\nTGA\n>Seq3\nTAC\n",
194             "FASTA");
195     cdna.setDataset(null);
196     AlignmentI protein = loadAlignment(">Seq1\nK\n>Seq2\nL\n>Seq3\nQ\n",
197             "FASTA");
198     protein.setDataset(null);
199     AlignedCodonFrame acf = new AlignedCodonFrame();
200     MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 3, 1);
201     for (int seq = 0; seq < 3; seq++)
202     {
203       acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
204               .getSequenceAt(seq).getDatasetSequence(), map);
205     }
206     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
207
208     AlignViewportI dnaView = new AlignViewport(cdna);
209     AlignViewportI proteinView = new AlignViewport(protein);
210     protein.setCodonFrames(acfList);
211
212     /*
213      * Select Seq1 and Seq3 in the protein (startRes=endRes=0)
214      */
215     SequenceGroup sg = new SequenceGroup();
216     sg.setColourText(true);
217     sg.setIdColour(Color.GREEN);
218     sg.setOutlineColour(Color.LIGHT_GRAY);
219     sg.addSequence(protein.getSequenceAt(0), false);
220     sg.addSequence(protein.getSequenceAt(2), false);
221
222     /*
223      * Verify the mapped sequence group in dna
224      */
225     SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
226             proteinView, dnaView);
227     assertTrue(mappedGroup.getColourText());
228     assertSame(sg.getIdColour(), mappedGroup.getIdColour());
229     assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
230     assertEquals(2, mappedGroup.getSequences().size());
231     assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
232     assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
233     assertEquals(0, mappedGroup.getStartRes());
234     assertEquals(2, mappedGroup.getEndRes());
235
236     /*
237      * Verify mapping sequence group from dna to protein
238      */
239     sg.clear();
240     sg.addSequence(cdna.getSequenceAt(1), false);
241     sg.addSequence(cdna.getSequenceAt(0), false);
242     sg.setStartRes(0);
243     sg.setEndRes(2);
244     mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
245     assertTrue(mappedGroup.getColourText());
246     assertSame(sg.getIdColour(), mappedGroup.getIdColour());
247     assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
248     assertEquals(2, mappedGroup.getSequences().size());
249     assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
250     assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
251     assertEquals(0, mappedGroup.getStartRes());
252     assertEquals(0, mappedGroup.getEndRes());
253   }
254
255   /**
256    * Helper method to load an alignment and ensure dataset sequences are set up.
257    * 
258    * @param data
259    * @param format
260    *          TODO
261    * @return
262    * @throws IOException
263    */
264   protected AlignmentI loadAlignment(final String data, String format)
265           throws IOException
266   {
267     AlignmentI a = new FormatAdapter().readFile(data,
268             AppletFormatAdapter.PASTE, format);
269     a.setDataset(null);
270     return a;
271   }
272
273   /**
274    * Test mapping a column selection in protein to its dna equivalent
275    * 
276    * @throws IOException
277    */
278   @Test(groups = { "Functional" })
279   public void testMapColumnSelection_proteinToDna() throws IOException
280   {
281     setupMappedAlignments();
282
283     ColumnSelection colsel = new ColumnSelection();
284
285     /*
286      * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
287      * in dna respectively, overall 0-4
288      */
289     colsel.addElement(0);
290     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel,
291             proteinView, dnaView);
292     assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
293
294     /*
295      * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
296      */
297     colsel.clear();
298     colsel.addElement(1);
299     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
300     assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
301
302     /*
303      * Column 2 in protein picks up gaps only - no mapping
304      */
305     colsel.clear();
306     colsel.addElement(2);
307     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
308     assertEquals("[]", cs.getSelected().toString());
309
310     /*
311      * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
312      * 6-9, 6-10, 5-8 respectively, overall to 5-10
313      */
314     colsel.clear();
315     colsel.addElement(3);
316     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
317     assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
318
319     /*
320      * Combine selection of columns 1 and 3 to get a discontiguous mapped
321      * selection
322      */
323     colsel.clear();
324     colsel.addElement(1);
325     colsel.addElement(3);
326     cs = MappingUtils.mapColumnSelection(colsel, proteinView, dnaView);
327     assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
328             .toString());
329   }
330
331   /**
332    * @throws IOException
333    */
334   protected void setupMappedAlignments() throws IOException
335   {
336     /*
337      * Set up dna and protein Seq1/2/3 with mappings (held on the protein
338      * viewport). Lower case for introns.
339      */
340     AlignmentI cdna = loadAlignment(">Seq1\nAC-GctGtC-T\n"
341             + ">Seq2\nTc-GA-G-T-Tc\n" + ">Seq3\nTtTT-AaCGg-\n", "FASTA");
342     cdna.setDataset(null);
343     AlignmentI protein = loadAlignment(
344             ">Seq1\n-K-P\n>Seq2\nL--Q\n>Seq3\nG--S\n", "FASTA");
345     protein.setDataset(null);
346     AlignedCodonFrame acf = new AlignedCodonFrame();
347     MapList map = new MapList(new int[] { 1, 3, 6, 6, 8, 9 }, new int[] {
348         1, 2 }, 3, 1);
349     acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(), protein
350             .getSequenceAt(0).getDatasetSequence(), map);
351     map = new MapList(new int[] { 1, 1, 3, 4, 5, 7 }, new int[] { 1, 2 },
352             3, 1);
353     acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(), protein
354             .getSequenceAt(1).getDatasetSequence(), map);
355     map = new MapList(new int[] { 1, 1, 3, 4, 5, 5, 7, 8 }, new int[] { 1,
356         2 }, 3, 1);
357     acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(), protein
358             .getSequenceAt(2).getDatasetSequence(), map);
359     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
360
361     dnaView = new AlignViewport(cdna);
362     proteinView = new AlignViewport(protein);
363     protein.setCodonFrames(acfList);
364   }
365
366   /**
367    * Test mapping a column selection in dna to its protein equivalent
368    * 
369    * @throws IOException
370    */
371   @Test(groups = { "Functional" })
372   public void testMapColumnSelection_dnaToProtein() throws IOException
373   {
374     setupMappedAlignments();
375
376     ColumnSelection colsel = new ColumnSelection();
377
378     /*
379      * Column 0 in dna picks up first bases which map to residue 1, columns 0-1
380      * in protein.
381      */
382     colsel.addElement(0);
383     ColumnSelection cs = MappingUtils.mapColumnSelection(colsel, dnaView,
384             proteinView);
385     assertEquals("[0, 1]", cs.getSelected().toString());
386
387     /*
388      * Columns 3-5 in dna map to the first residues in protein Seq1, Seq2, and
389      * the first two in Seq3. Overall to columns 0, 1, 3 (col2 is all gaps).
390      */
391     colsel.addElement(3);
392     colsel.addElement(4);
393     colsel.addElement(5);
394     cs = MappingUtils.mapColumnSelection(colsel, dnaView, proteinView);
395     assertEquals("[0, 1, 3]", cs.getSelected().toString());
396   }
397
398   @Test(groups = { "Functional" })
399   public void testMapColumnSelection_null() throws IOException
400   {
401     setupMappedAlignments();
402     ColumnSelection cs = MappingUtils.mapColumnSelection(null, dnaView,
403             proteinView);
404     assertTrue("mapped selection not empty", cs.getSelected().isEmpty());
405   }
406
407   /**
408    * Tests for the method that converts a series of [start, end] ranges to
409    * single positions
410    */
411   @Test(groups = { "Functional" })
412   public void testFlattenRanges()
413   {
414     assertEquals("[1, 2, 3, 4]",
415             Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4 })));
416     assertEquals(
417             "[1, 2, 3, 4]",
418             Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 2, 3,
419                 4 })));
420     assertEquals(
421             "[1, 2, 3, 4]",
422             Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 1, 2,
423                 2, 3, 3, 4, 4 })));
424     assertEquals(
425             "[1, 2, 3, 4, 7, 8, 9, 12]",
426             Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
427                 9, 12, 12 })));
428     // unpaired start position is ignored:
429     assertEquals(
430             "[1, 2, 3, 4, 7, 8, 9, 12]",
431             Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
432                 9, 12, 12, 15 })));
433   }
434
435   /**
436    * Test mapping a sequence group made of entire columns.
437    * 
438    * @throws IOException
439    */
440   @Test(groups = { "Functional" })
441   public void testMapSequenceGroup_columns() throws IOException
442   {
443     /*
444      * Set up dna and protein Seq1/2/3 with mappings (held on the protein
445      * viewport).
446      */
447     AlignmentI cdna = loadAlignment(
448             ">Seq1\nACGGCA\n>Seq2\nTGACAG\n>Seq3\nTACGTA\n", "FASTA");
449     cdna.setDataset(null);
450     AlignmentI protein = loadAlignment(">Seq1\nKA\n>Seq2\nLQ\n>Seq3\nQV\n",
451             "FASTA");
452     protein.setDataset(null);
453     AlignedCodonFrame acf = new AlignedCodonFrame();
454     MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
455     for (int seq = 0; seq < 3; seq++)
456     {
457       acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
458               .getSequenceAt(seq).getDatasetSequence(), map);
459     }
460     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
461
462     AlignViewportI dnaView = new AlignViewport(cdna);
463     AlignViewportI proteinView = new AlignViewport(protein);
464     protein.setCodonFrames(acfList);
465
466     /*
467      * Select all sequences, column 2 in the protein
468      */
469     SequenceGroup sg = new SequenceGroup();
470     sg.setColourText(true);
471     sg.setIdColour(Color.GREEN);
472     sg.setOutlineColour(Color.LIGHT_GRAY);
473     sg.addSequence(protein.getSequenceAt(0), false);
474     sg.addSequence(protein.getSequenceAt(1), false);
475     sg.addSequence(protein.getSequenceAt(2), false);
476     sg.setStartRes(1);
477     sg.setEndRes(1);
478
479     /*
480      * Verify the mapped sequence group in dna
481      */
482     SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
483             proteinView, dnaView);
484     assertTrue(mappedGroup.getColourText());
485     assertSame(sg.getIdColour(), mappedGroup.getIdColour());
486     assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
487     assertEquals(3, mappedGroup.getSequences().size());
488     assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
489     assertSame(cdna.getSequenceAt(1), mappedGroup.getSequences().get(1));
490     assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(2));
491     assertEquals(3, mappedGroup.getStartRes());
492     assertEquals(5, mappedGroup.getEndRes());
493
494     /*
495      * Verify mapping sequence group from dna to protein
496      */
497     sg.clear();
498     sg.addSequence(cdna.getSequenceAt(0), false);
499     sg.addSequence(cdna.getSequenceAt(1), false);
500     sg.addSequence(cdna.getSequenceAt(2), false);
501     // select columns 2 and 3 in DNA which span protein columns 0 and 1
502     sg.setStartRes(2);
503     sg.setEndRes(3);
504     mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
505     assertTrue(mappedGroup.getColourText());
506     assertSame(sg.getIdColour(), mappedGroup.getIdColour());
507     assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
508     assertEquals(3, mappedGroup.getSequences().size());
509     assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(0));
510     assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(1));
511     assertSame(protein.getSequenceAt(2), mappedGroup.getSequences().get(2));
512     assertEquals(0, mappedGroup.getStartRes());
513     assertEquals(1, mappedGroup.getEndRes());
514   }
515
516   /**
517    * Test mapping a sequence group made of a sequences/columns region.
518    * 
519    * @throws IOException
520    */
521   @Test(groups = { "Functional" })
522   public void testMapSequenceGroup_region() throws IOException
523   {
524     /*
525      * Set up gapped dna and protein Seq1/2/3 with mappings (held on the protein
526      * viewport).
527      */
528     AlignmentI cdna = loadAlignment(
529             ">Seq1\nA-CG-GC--AT-CA\n>Seq2\n-TG-AC-AG-T-AT\n>Seq3\n-T--ACG-TAAT-G\n",
530             "FASTA");
531     cdna.setDataset(null);
532     AlignmentI protein = loadAlignment(
533             ">Seq1\n-KA-S\n>Seq2\n--L-QY\n>Seq3\nQ-V-M\n", "FASTA");
534     protein.setDataset(null);
535     AlignedCodonFrame acf = new AlignedCodonFrame();
536     MapList map = new MapList(new int[] { 1, 9 }, new int[] { 1, 3 }, 3, 1);
537     for (int seq = 0; seq < 3; seq++)
538     {
539       acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
540               .getSequenceAt(seq).getDatasetSequence(), map);
541     }
542     Set<AlignedCodonFrame> acfList = Collections.singleton(acf);
543
544     AlignViewportI dnaView = new AlignViewport(cdna);
545     AlignViewportI proteinView = new AlignViewport(protein);
546     protein.setCodonFrames(acfList);
547
548     /*
549      * Select Seq1 and Seq2 in the protein, column 1 (K/-). Expect mapped
550      * sequence group to cover Seq1, columns 0-3 (ACG). Because the selection
551      * only includes a gap in Seq2 there is no mappable selection region in the
552      * corresponding DNA.
553      */
554     SequenceGroup sg = new SequenceGroup();
555     sg.setColourText(true);
556     sg.setIdColour(Color.GREEN);
557     sg.setOutlineColour(Color.LIGHT_GRAY);
558     sg.addSequence(protein.getSequenceAt(0), false);
559     sg.addSequence(protein.getSequenceAt(1), false);
560     sg.setStartRes(1);
561     sg.setEndRes(1);
562
563     /*
564      * Verify the mapped sequence group in dna
565      */
566     SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
567             proteinView, dnaView);
568     assertTrue(mappedGroup.getColourText());
569     assertSame(sg.getIdColour(), mappedGroup.getIdColour());
570     assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
571     assertEquals(1, mappedGroup.getSequences().size());
572     assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
573     // Seq2 in protein has a gap in column 1 - ignored
574     // Seq1 has K which should map to columns 0-3 in Seq1
575     assertEquals(0, mappedGroup.getStartRes());
576     assertEquals(3, mappedGroup.getEndRes());
577
578     /*
579      * Now select cols 2-4 in protein. These cover Seq1:AS Seq2:LQ Seq3:VM which
580      * extend over DNA columns 3-12, 1-7, 6-13 respectively, or 1-13 overall.
581      */
582     sg.setStartRes(2);
583     sg.setEndRes(4);
584     mappedGroup = MappingUtils.mapSequenceGroup(sg, proteinView, dnaView);
585     assertEquals(1, mappedGroup.getStartRes());
586     assertEquals(13, mappedGroup.getEndRes());
587
588     /*
589      * Verify mapping sequence group from dna to protein
590      */
591     sg.clear();
592     sg.addSequence(cdna.getSequenceAt(0), false);
593
594     // select columns 4,5 - includes Seq1:codon2 (A) only
595     sg.setStartRes(4);
596     sg.setEndRes(5);
597     mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
598     assertEquals(2, mappedGroup.getStartRes());
599     assertEquals(2, mappedGroup.getEndRes());
600
601     // add Seq2 to dna selection cols 4-5 include codons 1 and 2 (LQ)
602     sg.addSequence(cdna.getSequenceAt(1), false);
603     mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
604     assertEquals(2, mappedGroup.getStartRes());
605     assertEquals(4, mappedGroup.getEndRes());
606
607     // add Seq3 to dna selection cols 4-5 include codon 1 (Q)
608     sg.addSequence(cdna.getSequenceAt(2), false);
609     mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
610     assertEquals(0, mappedGroup.getStartRes());
611     assertEquals(4, mappedGroup.getEndRes());
612   }
613
614   @Test(groups = { "Functional" })
615   public void testFindMappingsForSequence()
616   {
617     SequenceI seq1 = new Sequence("Seq1", "ABC");
618     SequenceI seq2 = new Sequence("Seq2", "ABC");
619     SequenceI seq3 = new Sequence("Seq3", "ABC");
620     SequenceI seq4 = new Sequence("Seq4", "ABC");
621     seq1.createDatasetSequence();
622     seq2.createDatasetSequence();
623     seq3.createDatasetSequence();
624     seq4.createDatasetSequence();
625
626     /*
627      * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1
628      */
629     AlignedCodonFrame acf1 = new AlignedCodonFrame();
630     MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
631     acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
632     AlignedCodonFrame acf2 = new AlignedCodonFrame();
633     acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
634     AlignedCodonFrame acf3 = new AlignedCodonFrame();
635     acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
636
637     Set<AlignedCodonFrame> mappings = new HashSet<AlignedCodonFrame>();
638     mappings.add(acf1);
639     mappings.add(acf2);
640     mappings.add(acf3);
641
642     /*
643      * Seq1 has three mappings
644      */
645     List<AlignedCodonFrame> result = MappingUtils.findMappingsForSequence(
646             seq1, mappings);
647     assertEquals(3, result.size());
648     assertTrue(result.contains(acf1));
649     assertTrue(result.contains(acf2));
650     assertTrue(result.contains(acf3));
651
652     /*
653      * Seq2 has two mappings
654      */
655     result = MappingUtils.findMappingsForSequence(seq2, mappings);
656     assertEquals(2, result.size());
657     assertTrue(result.contains(acf1));
658     assertTrue(result.contains(acf2));
659
660     /*
661      * Seq3 has one mapping
662      */
663     result = MappingUtils.findMappingsForSequence(seq3, mappings);
664     assertEquals(1, result.size());
665     assertTrue(result.contains(acf3));
666
667     /*
668      * Seq4 has no mappings
669      */
670     result = MappingUtils.findMappingsForSequence(seq4, mappings);
671     assertEquals(0, result.size());
672
673     result = MappingUtils.findMappingsForSequence(null, mappings);
674     assertEquals(0, result.size());
675
676     result = MappingUtils.findMappingsForSequence(seq1, null);
677     assertEquals(0, result.size());
678
679     result = MappingUtils.findMappingsForSequence(null, null);
680     assertEquals(0, result.size());
681   }
682 }