2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import static org.testng.AssertJUnit.assertEquals;
24 import static org.testng.AssertJUnit.assertFalse;
25 import static org.testng.AssertJUnit.assertSame;
26 import static org.testng.AssertJUnit.assertTrue;
28 import jalview.api.AlignViewportI;
29 import jalview.commands.EditCommand;
30 import jalview.commands.EditCommand.Action;
31 import jalview.commands.EditCommand.Edit;
32 import jalview.datamodel.AlignedCodonFrame;
33 import jalview.datamodel.Alignment;
34 import jalview.datamodel.AlignmentI;
35 import jalview.datamodel.ColumnSelection;
36 import jalview.datamodel.HiddenColumns;
37 import jalview.datamodel.SearchResultMatchI;
38 import jalview.datamodel.SearchResultsI;
39 import jalview.datamodel.Sequence;
40 import jalview.datamodel.SequenceGroup;
41 import jalview.datamodel.SequenceI;
42 import jalview.gui.AlignViewport;
43 import jalview.gui.JvOptionPane;
44 import jalview.io.DataSourceType;
45 import jalview.io.FileFormat;
46 import jalview.io.FileFormatI;
47 import jalview.io.FormatAdapter;
49 import java.awt.Color;
50 import java.io.IOException;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.List;
55 import org.testng.annotations.BeforeClass;
56 import org.testng.annotations.Test;
58 public class MappingUtilsTest
61 @BeforeClass(alwaysRun = true)
62 public void setUpJvOptionPane()
64 JvOptionPane.setInteractiveMode(false);
65 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
68 private AlignViewportI dnaView;
70 private AlignViewportI proteinView;
73 * Simple test of mapping with no intron involved.
75 @Test(groups = { "Functional" })
76 public void testBuildSearchResults()
78 final Sequence seq1 = new Sequence("Seq1/5-10", "C-G-TA-GC");
79 seq1.createDatasetSequence();
81 final Sequence aseq1 = new Sequence("Seq1/12-13", "-P-R");
82 aseq1.createDatasetSequence();
85 * Map dna bases 5-10 to protein residues 12-13
87 AlignedCodonFrame acf = new AlignedCodonFrame();
88 MapList map = new MapList(new int[] { 5, 10 }, new int[] { 12, 13 }, 3,
90 acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
91 List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
95 * Check protein residue 12 maps to codon 5-7, 13 to codon 8-10
97 SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 12, acfList);
98 assertEquals(1, sr.getResults().size());
99 SearchResultMatchI m = sr.getResults().get(0);
100 assertEquals(seq1.getDatasetSequence(), m.getSequence());
101 assertEquals(5, m.getStart());
102 assertEquals(7, m.getEnd());
103 sr = MappingUtils.buildSearchResults(aseq1, 13, acfList);
104 assertEquals(1, sr.getResults().size());
105 m = sr.getResults().get(0);
106 assertEquals(seq1.getDatasetSequence(), m.getSequence());
107 assertEquals(8, m.getStart());
108 assertEquals(10, m.getEnd());
111 * Check inverse mappings, from codons 5-7, 8-10 to protein 12, 13
113 for (int i = 5; i < 11; i++)
115 sr = MappingUtils.buildSearchResults(seq1, i, acfList);
116 assertEquals(1, sr.getResults().size());
117 m = sr.getResults().get(0);
118 assertEquals(aseq1.getDatasetSequence(), m.getSequence());
119 int residue = i > 7 ? 13 : 12;
120 assertEquals(residue, m.getStart());
121 assertEquals(residue, m.getEnd());
126 * Simple test of mapping with introns involved.
128 @Test(groups = { "Functional" })
129 public void testBuildSearchResults_withIntron()
131 final Sequence seq1 = new Sequence("Seq1/5-17", "c-G-tAGa-GcAgCtt");
132 seq1.createDatasetSequence();
134 final Sequence aseq1 = new Sequence("Seq1/8-9", "-E-D");
135 aseq1.createDatasetSequence();
138 * Map dna bases [6, 8, 9], [11, 13, 115] to protein residues 8 and 9
140 AlignedCodonFrame acf = new AlignedCodonFrame();
141 MapList map = new MapList(new int[] { 6, 6, 8, 9, 11, 11, 13, 13, 15,
142 15 }, new int[] { 8, 9 }, 3, 1);
143 acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
144 List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
148 * Check protein residue 8 maps to [6, 8, 9]
150 SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 8, acfList);
151 assertEquals(2, sr.getResults().size());
152 SearchResultMatchI m = sr.getResults().get(0);
153 assertEquals(seq1.getDatasetSequence(), m.getSequence());
154 assertEquals(6, m.getStart());
155 assertEquals(6, m.getEnd());
156 m = sr.getResults().get(1);
157 assertEquals(seq1.getDatasetSequence(), m.getSequence());
158 assertEquals(8, m.getStart());
159 assertEquals(9, m.getEnd());
162 * Check protein residue 9 maps to [11, 13, 15]
164 sr = MappingUtils.buildSearchResults(aseq1, 9, acfList);
165 assertEquals(3, sr.getResults().size());
166 m = sr.getResults().get(0);
167 assertEquals(seq1.getDatasetSequence(), m.getSequence());
168 assertEquals(11, m.getStart());
169 assertEquals(11, m.getEnd());
170 m = sr.getResults().get(1);
171 assertEquals(seq1.getDatasetSequence(), m.getSequence());
172 assertEquals(13, m.getStart());
173 assertEquals(13, m.getEnd());
174 m = sr.getResults().get(2);
175 assertEquals(seq1.getDatasetSequence(), m.getSequence());
176 assertEquals(15, m.getStart());
177 assertEquals(15, m.getEnd());
180 * Check inverse mappings, from codons to protein
182 for (int i = 5; i < 18; i++)
184 sr = MappingUtils.buildSearchResults(seq1, i, acfList);
185 int residue = (i == 6 || i == 8 || i == 9) ? 8 : (i == 11 || i == 13
189 assertEquals(0, sr.getResults().size());
192 assertEquals(1, sr.getResults().size());
193 m = sr.getResults().get(0);
194 assertEquals(aseq1.getDatasetSequence(), m.getSequence());
195 assertEquals(residue, m.getStart());
196 assertEquals(residue, m.getEnd());
201 * Test mapping a sequence group made of entire sequences.
203 * @throws IOException
205 @Test(groups = { "Functional" })
206 public void testMapSequenceGroup_sequences() throws IOException
209 * Set up dna and protein Seq1/2/3 with mappings (held on the protein
212 AlignmentI cdna = loadAlignment(">Seq1\nACG\n>Seq2\nTGA\n>Seq3\nTAC\n",
214 cdna.setDataset(null);
215 AlignmentI protein = loadAlignment(">Seq1\nK\n>Seq2\nL\n>Seq3\nQ\n",
217 protein.setDataset(null);
218 AlignedCodonFrame acf = new AlignedCodonFrame();
219 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 3, 1);
220 for (int seq = 0; seq < 3; seq++)
222 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
223 .getSequenceAt(seq).getDatasetSequence(), map);
225 List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
228 AlignViewportI dnaView = new AlignViewport(cdna);
229 AlignViewportI proteinView = new AlignViewport(protein);
230 protein.setCodonFrames(acfList);
233 * Select Seq1 and Seq3 in the protein (startRes=endRes=0)
235 SequenceGroup sg = new SequenceGroup();
236 sg.setColourText(true);
237 sg.setIdColour(Color.GREEN);
238 sg.setOutlineColour(Color.LIGHT_GRAY);
239 sg.addSequence(protein.getSequenceAt(0), false);
240 sg.addSequence(protein.getSequenceAt(2), false);
243 * Verify the mapped sequence group in dna
245 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
246 proteinView, dnaView);
247 assertTrue(mappedGroup.getColourText());
248 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
249 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
250 assertEquals(2, mappedGroup.getSequences().size());
251 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
252 assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
253 assertEquals(0, mappedGroup.getStartRes());
254 assertEquals(2, mappedGroup.getEndRes());
257 * Verify mapping sequence group from dna to protein
260 sg.addSequence(cdna.getSequenceAt(1), false);
261 sg.addSequence(cdna.getSequenceAt(0), false);
264 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
265 assertTrue(mappedGroup.getColourText());
266 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
267 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
268 assertEquals(2, mappedGroup.getSequences().size());
269 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
270 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
271 assertEquals(0, mappedGroup.getStartRes());
272 assertEquals(0, mappedGroup.getEndRes());
276 * Helper method to load an alignment and ensure dataset sequences are set up.
282 * @throws IOException
284 protected AlignmentI loadAlignment(final String data, FileFormatI format)
287 AlignmentI a = new FormatAdapter().readFile(data,
288 DataSourceType.PASTE, format);
294 * Test mapping a column selection in protein to its dna equivalent
296 * @throws IOException
298 @Test(groups = { "Functional" })
299 public void testMapColumnSelection_proteinToDna() throws IOException
301 setupMappedAlignments();
303 ColumnSelection colsel = new ColumnSelection();
304 HiddenColumns hidden = new HiddenColumns();
307 * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
308 * in dna respectively, overall 0-4
310 colsel.addElement(0);
311 ColumnSelection cs = new ColumnSelection();
312 HiddenColumns hs = new HiddenColumns();
313 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
315 assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
318 * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
322 colsel.addElement(1);
323 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
325 assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
328 * Column 2 in protein picks up gaps only - no mapping
332 colsel.addElement(2);
333 MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
335 assertEquals("[]", cs.getSelected().toString());
338 * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
339 * 6-9, 6-10, 5-8 respectively, overall to 5-10
343 colsel.addElement(3);
344 MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
346 assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
349 * Combine selection of columns 1 and 3 to get a discontiguous mapped
354 colsel.addElement(1);
355 colsel.addElement(3);
356 MappingUtils.mapColumnSelection(colsel, hidden, proteinView,
358 assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]", cs.getSelected()
363 * Set up mappings for tests from 3 dna to 3 protein sequences. Sequences have
364 * offset start positions for a more general test case.
366 * @throws IOException
368 protected void setupMappedAlignments() throws IOException
371 * Map (upper-case = coding):
372 * Seq1/10-18 AC-GctGtC-T to Seq1/40 -K-P
373 * Seq2/20-27 Tc-GA-G-T-T to Seq2/20-27 L--Q
374 * Seq3/30-38 TtTT-AaCGg- to Seq3/60-61\nG--S
376 AlignmentI cdna = loadAlignment(">Seq1/10-18\nAC-GctGtC-T\n"
377 + ">Seq2/20-27\nTc-GA-G-T-Tc\n" + ">Seq3/30-38\nTtTT-AaCGg-\n",
379 cdna.setDataset(null);
380 AlignmentI protein = loadAlignment(
381 ">Seq1/40-41\n-K-P\n>Seq2/50-51\nL--Q\n>Seq3/60-61\nG--S\n",
383 protein.setDataset(null);
385 // map first dna to first protein seq
386 AlignedCodonFrame acf = new AlignedCodonFrame();
387 MapList map = new MapList(new int[] { 10, 12, 15, 15, 17, 18 },
388 new int[] { 40, 41 }, 3, 1);
389 acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(), protein
390 .getSequenceAt(0).getDatasetSequence(), map);
392 // map second dna to second protein seq
393 map = new MapList(new int[] { 20, 20, 22, 23, 24, 26 }, new int[] { 50,
395 acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(), protein
396 .getSequenceAt(1).getDatasetSequence(), map);
398 // map third dna to third protein seq
399 map = new MapList(new int[] { 30, 30, 32, 34, 36, 37 }, new int[] { 60,
401 acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(), protein
402 .getSequenceAt(2).getDatasetSequence(), map);
403 List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
406 dnaView = new AlignViewport(cdna);
407 proteinView = new AlignViewport(protein);
408 protein.setCodonFrames(acfList);
412 * Test mapping a column selection in dna to its protein equivalent
414 * @throws IOException
416 @Test(groups = { "Functional" })
417 public void testMapColumnSelection_dnaToProtein() throws IOException
419 setupMappedAlignments();
421 ColumnSelection colsel = new ColumnSelection();
422 HiddenColumns hidden = new HiddenColumns();
425 * Column 0 in dna picks up first bases which map to residue 1, columns 0-1
428 ColumnSelection cs = new ColumnSelection();
429 HiddenColumns hs = new HiddenColumns();
430 colsel.addElement(0);
431 MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
433 assertEquals("[0, 1]", cs.getSelected().toString());
436 * Columns 3-5 in dna map to the first residues in protein Seq1, Seq2, and
437 * the first two in Seq3. Overall to columns 0, 1, 3 (col2 is all gaps).
439 colsel.addElement(3);
440 colsel.addElement(4);
441 colsel.addElement(5);
443 MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
445 assertEquals("[0, 1, 3]", cs.getSelected().toString());
448 @Test(groups = { "Functional" })
449 public void testMapColumnSelection_null() throws IOException
451 setupMappedAlignments();
452 ColumnSelection cs = new ColumnSelection();
453 HiddenColumns hs = new HiddenColumns();
454 MappingUtils.mapColumnSelection(null, null, dnaView, proteinView, cs,
456 assertTrue("mapped selection not empty", cs.getSelected().isEmpty());
460 * Tests for the method that converts a series of [start, end] ranges to
463 @Test(groups = { "Functional" })
464 public void testFlattenRanges()
466 assertEquals("[1, 2, 3, 4]",
467 Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4 })));
470 Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 2, 3,
474 Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 1, 2,
477 "[1, 2, 3, 4, 7, 8, 9, 12]",
478 Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
480 // trailing unpaired start position is ignored:
482 "[1, 2, 3, 4, 7, 8, 9, 12]",
483 Arrays.toString(MappingUtils.flattenRanges(new int[] { 1, 4, 7,
488 * Test mapping a sequence group made of entire columns.
490 * @throws IOException
492 @Test(groups = { "Functional" })
493 public void testMapSequenceGroup_columns() throws IOException
496 * Set up dna and protein Seq1/2/3 with mappings (held on the protein
499 AlignmentI cdna = loadAlignment(
500 ">Seq1\nACGGCA\n>Seq2\nTGACAG\n>Seq3\nTACGTA\n",
502 cdna.setDataset(null);
503 AlignmentI protein = loadAlignment(">Seq1\nKA\n>Seq2\nLQ\n>Seq3\nQV\n",
505 protein.setDataset(null);
506 AlignedCodonFrame acf = new AlignedCodonFrame();
507 MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
508 for (int seq = 0; seq < 3; seq++)
510 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
511 .getSequenceAt(seq).getDatasetSequence(), map);
513 List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
516 AlignViewportI dnaView = new AlignViewport(cdna);
517 AlignViewportI proteinView = new AlignViewport(protein);
518 protein.setCodonFrames(acfList);
521 * Select all sequences, column 2 in the protein
523 SequenceGroup sg = new SequenceGroup();
524 sg.setColourText(true);
525 sg.setIdColour(Color.GREEN);
526 sg.setOutlineColour(Color.LIGHT_GRAY);
527 sg.addSequence(protein.getSequenceAt(0), false);
528 sg.addSequence(protein.getSequenceAt(1), false);
529 sg.addSequence(protein.getSequenceAt(2), false);
534 * Verify the mapped sequence group in dna
536 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
537 proteinView, dnaView);
538 assertTrue(mappedGroup.getColourText());
539 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
540 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
541 assertEquals(3, mappedGroup.getSequences().size());
542 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
543 assertSame(cdna.getSequenceAt(1), mappedGroup.getSequences().get(1));
544 assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(2));
545 assertEquals(3, mappedGroup.getStartRes());
546 assertEquals(5, mappedGroup.getEndRes());
549 * Verify mapping sequence group from dna to protein
552 sg.addSequence(cdna.getSequenceAt(0), false);
553 sg.addSequence(cdna.getSequenceAt(1), false);
554 sg.addSequence(cdna.getSequenceAt(2), false);
555 // select columns 2 and 3 in DNA which span protein columns 0 and 1
558 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
559 assertTrue(mappedGroup.getColourText());
560 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
561 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
562 assertEquals(3, mappedGroup.getSequences().size());
563 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(0));
564 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(1));
565 assertSame(protein.getSequenceAt(2), mappedGroup.getSequences().get(2));
566 assertEquals(0, mappedGroup.getStartRes());
567 assertEquals(1, mappedGroup.getEndRes());
571 * Test mapping a sequence group made of a sequences/columns region.
573 * @throws IOException
575 @Test(groups = { "Functional" })
576 public void testMapSequenceGroup_region() throws IOException
579 * Set up gapped dna and protein Seq1/2/3 with mappings (held on the protein
582 AlignmentI cdna = loadAlignment(
583 ">Seq1\nA-CG-GC--AT-CA\n>Seq2\n-TG-AC-AG-T-AT\n>Seq3\n-T--ACG-TAAT-G\n",
585 cdna.setDataset(null);
586 AlignmentI protein = loadAlignment(
587 ">Seq1\n-KA-S\n>Seq2\n--L-QY\n>Seq3\nQ-V-M\n", FileFormat.Fasta);
588 protein.setDataset(null);
589 AlignedCodonFrame acf = new AlignedCodonFrame();
590 MapList map = new MapList(new int[] { 1, 9 }, new int[] { 1, 3 }, 3, 1);
591 for (int seq = 0; seq < 3; seq++)
593 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(), protein
594 .getSequenceAt(seq).getDatasetSequence(), map);
596 List<AlignedCodonFrame> acfList = Arrays.asList(new AlignedCodonFrame[]
599 AlignViewportI dnaView = new AlignViewport(cdna);
600 AlignViewportI proteinView = new AlignViewport(protein);
601 protein.setCodonFrames(acfList);
604 * Select Seq1 and Seq2 in the protein, column 1 (K/-). Expect mapped
605 * sequence group to cover Seq1, columns 0-3 (ACG). Because the selection
606 * only includes a gap in Seq2 there is no mappable selection region in the
609 SequenceGroup sg = new SequenceGroup();
610 sg.setColourText(true);
611 sg.setIdColour(Color.GREEN);
612 sg.setOutlineColour(Color.LIGHT_GRAY);
613 sg.addSequence(protein.getSequenceAt(0), false);
614 sg.addSequence(protein.getSequenceAt(1), false);
619 * Verify the mapped sequence group in dna
621 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
622 proteinView, dnaView);
623 assertTrue(mappedGroup.getColourText());
624 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
625 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
626 assertEquals(1, mappedGroup.getSequences().size());
627 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
628 // Seq2 in protein has a gap in column 1 - ignored
629 // Seq1 has K which should map to columns 0-3 in Seq1
630 assertEquals(0, mappedGroup.getStartRes());
631 assertEquals(3, mappedGroup.getEndRes());
634 * Now select cols 2-4 in protein. These cover Seq1:AS Seq2:LQ Seq3:VM which
635 * extend over DNA columns 3-12, 1-7, 6-13 respectively, or 1-13 overall.
639 mappedGroup = MappingUtils.mapSequenceGroup(sg, proteinView, dnaView);
640 assertEquals(1, mappedGroup.getStartRes());
641 assertEquals(13, mappedGroup.getEndRes());
644 * Verify mapping sequence group from dna to protein
647 sg.addSequence(cdna.getSequenceAt(0), false);
649 // select columns 4,5 - includes Seq1:codon2 (A) only
652 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
653 assertEquals(2, mappedGroup.getStartRes());
654 assertEquals(2, mappedGroup.getEndRes());
656 // add Seq2 to dna selection cols 4-5 include codons 1 and 2 (LQ)
657 sg.addSequence(cdna.getSequenceAt(1), false);
658 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
659 assertEquals(2, mappedGroup.getStartRes());
660 assertEquals(4, mappedGroup.getEndRes());
662 // add Seq3 to dna selection cols 4-5 include codon 1 (Q)
663 sg.addSequence(cdna.getSequenceAt(2), false);
664 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
665 assertEquals(0, mappedGroup.getStartRes());
666 assertEquals(4, mappedGroup.getEndRes());
669 @Test(groups = { "Functional" })
670 public void testFindMappingsForSequence()
672 SequenceI seq1 = new Sequence("Seq1", "ABC");
673 SequenceI seq2 = new Sequence("Seq2", "ABC");
674 SequenceI seq3 = new Sequence("Seq3", "ABC");
675 SequenceI seq4 = new Sequence("Seq4", "ABC");
676 seq1.createDatasetSequence();
677 seq2.createDatasetSequence();
678 seq3.createDatasetSequence();
679 seq4.createDatasetSequence();
682 * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1
684 AlignedCodonFrame acf1 = new AlignedCodonFrame();
685 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
686 acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
687 AlignedCodonFrame acf2 = new AlignedCodonFrame();
688 acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
689 AlignedCodonFrame acf3 = new AlignedCodonFrame();
690 acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
692 List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
698 * Seq1 has three mappings
700 List<AlignedCodonFrame> result = MappingUtils.findMappingsForSequence(
702 assertEquals(3, result.size());
703 assertTrue(result.contains(acf1));
704 assertTrue(result.contains(acf2));
705 assertTrue(result.contains(acf3));
708 * Seq2 has two mappings
710 result = MappingUtils.findMappingsForSequence(seq2, mappings);
711 assertEquals(2, result.size());
712 assertTrue(result.contains(acf1));
713 assertTrue(result.contains(acf2));
716 * Seq3 has one mapping
718 result = MappingUtils.findMappingsForSequence(seq3, mappings);
719 assertEquals(1, result.size());
720 assertTrue(result.contains(acf3));
723 * Seq4 has no mappings
725 result = MappingUtils.findMappingsForSequence(seq4, mappings);
726 assertEquals(0, result.size());
728 result = MappingUtils.findMappingsForSequence(null, mappings);
729 assertEquals(0, result.size());
731 result = MappingUtils.findMappingsForSequence(seq1, null);
732 assertEquals(0, result.size());
734 result = MappingUtils.findMappingsForSequence(null, null);
735 assertEquals(0, result.size());
739 * just like the one above, but this time, we provide a set of sequences to
740 * subselect the mapping search
742 @Test(groups = { "Functional" })
743 public void testFindMappingsForSequenceAndOthers()
745 SequenceI seq1 = new Sequence("Seq1", "ABC");
746 SequenceI seq2 = new Sequence("Seq2", "ABC");
747 SequenceI seq3 = new Sequence("Seq3", "ABC");
748 SequenceI seq4 = new Sequence("Seq4", "ABC");
749 seq1.createDatasetSequence();
750 seq2.createDatasetSequence();
751 seq3.createDatasetSequence();
752 seq4.createDatasetSequence();
755 * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1, seq3 to seq4
757 AlignedCodonFrame acf1 = new AlignedCodonFrame();
758 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
759 acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
760 AlignedCodonFrame acf2 = new AlignedCodonFrame();
761 acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
762 AlignedCodonFrame acf3 = new AlignedCodonFrame();
763 acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
764 AlignedCodonFrame acf4 = new AlignedCodonFrame();
765 acf4.addMap(seq3.getDatasetSequence(), seq4.getDatasetSequence(), map);
767 List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
776 List<AlignedCodonFrame> result = MappingUtils
777 .findMappingsForSequenceAndOthers(null, mappings,
778 Arrays.asList(new SequenceI[] { seq1, seq2 }));
779 assertTrue(result.isEmpty());
781 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, null,
782 Arrays.asList(new SequenceI[] { seq1, seq2 }));
783 assertTrue(result.isEmpty());
786 * Seq1 has three mappings, but filter argument will only accept
789 result = MappingUtils.findMappingsForSequenceAndOthers(
792 Arrays.asList(new SequenceI[] { seq1, seq2,
793 seq1.getDatasetSequence() }));
794 assertEquals(2, result.size());
795 assertTrue(result.contains(acf1));
796 assertTrue(result.contains(acf2));
797 assertFalse("Did not expect to find mapping acf3 - subselect failed",
798 result.contains(acf3));
800 "Did not expect to find mapping acf4 - doesn't involve sequence",
801 result.contains(acf4));
804 * and verify the no filter case
806 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
808 assertEquals(3, result.size());
809 assertTrue(result.contains(acf1));
810 assertTrue(result.contains(acf2));
811 assertTrue(result.contains(acf3));
814 @Test(groups = { "Functional" })
815 public void testMapEditCommand()
817 SequenceI dna = new Sequence("Seq1", "---ACG---GCATCA", 8, 16);
818 SequenceI protein = new Sequence("Seq2", "-T-AS", 5, 7);
819 dna.createDatasetSequence();
820 protein.createDatasetSequence();
821 AlignedCodonFrame acf = new AlignedCodonFrame();
822 MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3, 1);
823 acf.addMap(dna.getDatasetSequence(), protein.getDatasetSequence(), map);
824 List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
827 AlignmentI prot = new Alignment(new SequenceI[] { protein });
828 prot.setCodonFrames(mappings);
829 AlignmentI nuc = new Alignment(new SequenceI[] { dna });
832 * construct and perform the edit command to turn "-T-AS" in to "-T-A--S"
833 * i.e. insert two gaps at column 4
835 EditCommand ec = new EditCommand();
836 final Edit edit = ec.new Edit(Action.INSERT_GAP,
837 new SequenceI[] { protein }, 4, 2, '-');
838 ec.appendEdit(edit, prot, true, null);
841 * the mapped edit command should be to insert 6 gaps before base 4 in the
842 * nucleotide sequence, which corresponds to aligned column 12 in the dna
844 EditCommand mappedEdit = MappingUtils.mapEditCommand(ec, false, nuc,
846 assertEquals(1, mappedEdit.getEdits().size());
847 Edit e = mappedEdit.getEdits().get(0);
848 assertEquals(1, e.getSequences().length);
849 assertEquals(dna, e.getSequences()[0]);
850 assertEquals(12, e.getPosition());
851 assertEquals(6, e.getNumber());
855 * Tests for the method that converts a series of [start, end] ranges to
856 * single positions, where the mapping is to a reverse strand i.e. start is
857 * greater than end point mapped to
859 @Test(groups = { "Functional" })
860 public void testFlattenRanges_reverseStrand()
862 assertEquals("[4, 3, 2, 1]",
863 Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 1 })));
866 Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 3, 2,
870 Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 4, 3,
873 "[12, 9, 8, 7, 4, 3, 2, 1]",
874 Arrays.toString(MappingUtils.flattenRanges(new int[] { 12, 12,
876 // forwards and backwards anyone?
878 "[4, 5, 6, 3, 2, 1]",
879 Arrays.toString(MappingUtils.flattenRanges(new int[] { 4, 6, 3,
881 // backwards and forwards
883 "[3, 2, 1, 4, 5, 6]",
884 Arrays.toString(MappingUtils.flattenRanges(new int[] { 3, 1, 4,
886 // trailing unpaired start position is ignored:
888 "[12, 9, 8, 7, 4, 3, 2]",
889 Arrays.toString(MappingUtils.flattenRanges(new int[] { 12, 12,
894 * Test mapping a column selection including hidden columns
896 * @throws IOException
898 @Test(groups = { "Functional" })
899 public void testMapColumnSelection_hiddenColumns() throws IOException
901 setupMappedAlignments();
903 ColumnSelection proteinSelection = new ColumnSelection();
904 HiddenColumns hiddenCols = new HiddenColumns();
907 * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
908 * in dna respectively, overall 0-4
910 proteinSelection.hideSelectedColumns(0, hiddenCols);
911 ColumnSelection dnaSelection = new ColumnSelection();
912 HiddenColumns dnaHidden = new HiddenColumns();
913 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
914 proteinView, dnaView, dnaSelection, dnaHidden);
915 assertEquals("[]", dnaSelection.getSelected().toString());
916 List<int[]> hidden = dnaHidden.getHiddenRegions();
917 assertEquals(1, hidden.size());
918 assertEquals("[0, 4]", Arrays.toString(hidden.get(0)));
921 * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
923 dnaSelection = new ColumnSelection();
924 dnaHidden = new HiddenColumns();
925 hiddenCols.revealAllHiddenColumns(proteinSelection);
926 // the unhidden columns are now marked selected!
927 assertEquals("[0]", proteinSelection.getSelected().toString());
928 // deselect these or hideColumns will be expanded to include 0
929 proteinSelection.clear();
930 proteinSelection.hideSelectedColumns(1, hiddenCols);
931 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
932 proteinView, dnaView, dnaSelection, dnaHidden);
933 hidden = dnaHidden.getHiddenRegions();
934 assertEquals(1, hidden.size());
935 assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
938 * Column 2 in protein picks up gaps only - no mapping
940 dnaSelection = new ColumnSelection();
941 dnaHidden = new HiddenColumns();
942 hiddenCols.revealAllHiddenColumns(proteinSelection);
943 proteinSelection.clear();
944 proteinSelection.hideSelectedColumns(2, hiddenCols);
945 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
946 proteinView, dnaView, dnaSelection, dnaHidden);
947 assertTrue(dnaHidden.getHiddenRegions().isEmpty());
950 * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
951 * 6-9, 6-10, 5-8 respectively, overall to 5-10
953 dnaSelection = new ColumnSelection();
954 dnaHidden = new HiddenColumns();
955 hiddenCols.revealAllHiddenColumns(proteinSelection);
956 proteinSelection.clear();
957 proteinSelection.hideSelectedColumns(3, hiddenCols); // 5-10 hidden in dna
958 proteinSelection.addElement(1); // 0-3 selected in dna
959 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
960 proteinView, dnaView, dnaSelection, dnaHidden);
961 assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
962 hidden = dnaHidden.getHiddenRegions();
963 assertEquals(1, hidden.size());
964 assertEquals("[5, 10]", Arrays.toString(hidden.get(0)));
967 * Combine hiding columns 1 and 3 to get discontiguous hidden columns
969 dnaSelection = new ColumnSelection();
970 dnaHidden = new HiddenColumns();
971 hiddenCols.revealAllHiddenColumns(proteinSelection);
972 proteinSelection.clear();
973 proteinSelection.hideSelectedColumns(1, hiddenCols);
974 proteinSelection.hideSelectedColumns(3, hiddenCols);
975 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
976 proteinView, dnaView, dnaSelection, dnaHidden);
977 hidden = dnaHidden.getHiddenRegions();
978 assertEquals(2, hidden.size());
979 assertEquals("[0, 3]", Arrays.toString(hidden.get(0)));
980 assertEquals("[5, 10]", Arrays.toString(hidden.get(1)));
983 @Test(groups = { "Functional" })
984 public void testGetLength()
986 assertEquals(0, MappingUtils.getLength(null));
989 * [start, end] ranges
991 List<int[]> ranges = new ArrayList<int[]>();
992 assertEquals(0, MappingUtils.getLength(ranges));
993 ranges.add(new int[] { 1, 1 });
994 assertEquals(1, MappingUtils.getLength(ranges));
995 ranges.add(new int[] { 2, 10 });
996 assertEquals(10, MappingUtils.getLength(ranges));
997 ranges.add(new int[] { 20, 10 });
998 assertEquals(21, MappingUtils.getLength(ranges));
1001 * [start, end, start, end...] ranges
1004 ranges.add(new int[] { 1, 5, 8, 4 });
1005 ranges.add(new int[] { 8, 2 });
1006 ranges.add(new int[] { 12, 12 });
1007 assertEquals(18, MappingUtils.getLength(ranges));
1010 @Test(groups = { "Functional" })
1011 public void testContains()
1013 assertFalse(MappingUtils.contains(null, 1));
1014 List<int[]> ranges = new ArrayList<int[]>();
1015 assertFalse(MappingUtils.contains(ranges, 1));
1017 ranges.add(new int[] { 1, 4 });
1018 ranges.add(new int[] { 6, 6 });
1019 ranges.add(new int[] { 8, 10 });
1020 ranges.add(new int[] { 30, 20 });
1021 ranges.add(new int[] { -16, -44 });
1023 assertFalse(MappingUtils.contains(ranges, 0));
1024 assertTrue(MappingUtils.contains(ranges, 1));
1025 assertTrue(MappingUtils.contains(ranges, 2));
1026 assertTrue(MappingUtils.contains(ranges, 3));
1027 assertTrue(MappingUtils.contains(ranges, 4));
1028 assertFalse(MappingUtils.contains(ranges, 5));
1030 assertTrue(MappingUtils.contains(ranges, 6));
1031 assertFalse(MappingUtils.contains(ranges, 7));
1033 assertTrue(MappingUtils.contains(ranges, 8));
1034 assertTrue(MappingUtils.contains(ranges, 9));
1035 assertTrue(MappingUtils.contains(ranges, 10));
1037 assertFalse(MappingUtils.contains(ranges, 31));
1038 assertTrue(MappingUtils.contains(ranges, 30));
1039 assertTrue(MappingUtils.contains(ranges, 29));
1040 assertTrue(MappingUtils.contains(ranges, 20));
1041 assertFalse(MappingUtils.contains(ranges, 19));
1043 assertFalse(MappingUtils.contains(ranges, -15));
1044 assertTrue(MappingUtils.contains(ranges, -16));
1045 assertTrue(MappingUtils.contains(ranges, -44));
1046 assertFalse(MappingUtils.contains(ranges, -45));
1050 * Test the method that drops positions from the start of a mapped range
1052 @Test(groups = "Functional")
1053 public void testRemoveStartPositions()
1055 int[] ranges = new int[] { 1, 10 };
1056 int[] adjusted = MappingUtils.removeStartPositions(0, ranges);
1057 assertEquals("[1, 10]", Arrays.toString(adjusted));
1059 adjusted = MappingUtils.removeStartPositions(1, ranges);
1060 assertEquals("[2, 10]", Arrays.toString(adjusted));
1061 assertEquals("[1, 10]", Arrays.toString(ranges));
1064 adjusted = MappingUtils.removeStartPositions(1, ranges);
1065 assertEquals("[3, 10]", Arrays.toString(adjusted));
1066 assertEquals("[2, 10]", Arrays.toString(ranges));
1068 ranges = new int[] { 2, 3, 10, 12 };
1069 adjusted = MappingUtils.removeStartPositions(1, ranges);
1070 assertEquals("[3, 3, 10, 12]", Arrays.toString(adjusted));
1071 assertEquals("[2, 3, 10, 12]", Arrays.toString(ranges));
1073 ranges = new int[] { 2, 2, 8, 12 };
1074 adjusted = MappingUtils.removeStartPositions(1, ranges);
1075 assertEquals("[8, 12]", Arrays.toString(adjusted));
1076 assertEquals("[2, 2, 8, 12]", Arrays.toString(ranges));
1078 ranges = new int[] { 2, 2, 8, 12 };
1079 adjusted = MappingUtils.removeStartPositions(2, ranges);
1080 assertEquals("[9, 12]", Arrays.toString(adjusted));
1081 assertEquals("[2, 2, 8, 12]", Arrays.toString(ranges));
1083 ranges = new int[] { 2, 2, 4, 4, 9, 12 };
1084 adjusted = MappingUtils.removeStartPositions(1, ranges);
1085 assertEquals("[4, 4, 9, 12]", Arrays.toString(adjusted));
1086 assertEquals("[2, 2, 4, 4, 9, 12]", Arrays.toString(ranges));
1088 ranges = new int[] { 2, 2, 4, 4, 9, 12 };
1089 adjusted = MappingUtils.removeStartPositions(2, ranges);
1090 assertEquals("[9, 12]", Arrays.toString(adjusted));
1091 assertEquals("[2, 2, 4, 4, 9, 12]", Arrays.toString(ranges));
1093 ranges = new int[] { 2, 3, 9, 12 };
1094 adjusted = MappingUtils.removeStartPositions(3, ranges);
1095 assertEquals("[10, 12]", Arrays.toString(adjusted));
1096 assertEquals("[2, 3, 9, 12]", Arrays.toString(ranges));
1100 * Test the method that drops positions from the start of a mapped range, on
1101 * the reverse strand
1103 @Test(groups = "Functional")
1104 public void testRemoveStartPositions_reverseStrand()
1106 int[] ranges = new int[] { 10, 1 };
1107 int[] adjusted = MappingUtils.removeStartPositions(0, ranges);
1108 assertEquals("[10, 1]", Arrays.toString(adjusted));
1109 assertEquals("[10, 1]", Arrays.toString(ranges));
1112 adjusted = MappingUtils.removeStartPositions(1, ranges);
1113 assertEquals("[9, 1]", Arrays.toString(adjusted));
1114 assertEquals("[10, 1]", Arrays.toString(ranges));
1117 adjusted = MappingUtils.removeStartPositions(1, ranges);
1118 assertEquals("[8, 1]", Arrays.toString(adjusted));
1119 assertEquals("[9, 1]", Arrays.toString(ranges));
1121 ranges = new int[] { 12, 11, 9, 6 };
1122 adjusted = MappingUtils.removeStartPositions(1, ranges);
1123 assertEquals("[11, 11, 9, 6]", Arrays.toString(adjusted));
1124 assertEquals("[12, 11, 9, 6]", Arrays.toString(ranges));
1126 ranges = new int[] { 12, 12, 8, 4 };
1127 adjusted = MappingUtils.removeStartPositions(1, ranges);
1128 assertEquals("[8, 4]", Arrays.toString(adjusted));
1129 assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
1131 ranges = new int[] { 12, 12, 8, 4 };
1132 adjusted = MappingUtils.removeStartPositions(2, ranges);
1133 assertEquals("[7, 4]", Arrays.toString(adjusted));
1134 assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
1136 ranges = new int[] { 12, 12, 10, 10, 8, 4 };
1137 adjusted = MappingUtils.removeStartPositions(1, ranges);
1138 assertEquals("[10, 10, 8, 4]", Arrays.toString(adjusted));
1139 assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
1141 ranges = new int[] { 12, 12, 10, 10, 8, 4 };
1142 adjusted = MappingUtils.removeStartPositions(2, ranges);
1143 assertEquals("[8, 4]", Arrays.toString(adjusted));
1144 assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
1146 ranges = new int[] { 12, 11, 8, 4 };
1147 adjusted = MappingUtils.removeStartPositions(3, ranges);
1148 assertEquals("[7, 4]", Arrays.toString(adjusted));
1149 assertEquals("[12, 11, 8, 4]", Arrays.toString(ranges));