Clover icon

Coverage Report

  1. Project Clover database Tue Mar 10 2026 14:58:44 GMT
  2. Package jalview.util

File MappingUtilsTest.java

 

Code metrics

18
705
27
1
1,509
1,038
40
0.06
26.11
27
1.48

Classes

Class Line # Actions
MappingUtilsTest 63 705 40
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

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.util;
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 java.awt.Color;
31    import java.io.IOException;
32    import java.util.ArrayList;
33    import java.util.Arrays;
34    import java.util.Iterator;
35    import java.util.List;
36   
37    import org.testng.annotations.BeforeClass;
38    import org.testng.annotations.Test;
39   
40    import jalview.api.AlignViewportI;
41    import jalview.bin.Console;
42    import jalview.commands.EditCommand;
43    import jalview.commands.EditCommand.Action;
44    import jalview.commands.EditCommand.Edit;
45    import jalview.datamodel.AlignedCodonFrame;
46    import jalview.datamodel.Alignment;
47    import jalview.datamodel.AlignmentI;
48    import jalview.datamodel.ColumnSelection;
49    import jalview.datamodel.HiddenColumns;
50    import jalview.datamodel.SearchResultMatchI;
51    import jalview.datamodel.SearchResultsI;
52    import jalview.datamodel.Sequence;
53    import jalview.datamodel.SequenceGroup;
54    import jalview.datamodel.SequenceI;
55    import jalview.gui.AlignViewport;
56    import jalview.gui.JvOptionPane;
57    import jalview.io.DataSourceType;
58    import jalview.io.FileFormat;
59    import jalview.io.FileFormatI;
60    import jalview.io.FormatAdapter;
61   
62   
 
63    public class MappingUtilsTest
64    {
 
65  0 toggle @BeforeClass(alwaysRun = true)
66    public void setUp()
67    {
68  0 Console.initLogger();
69    }
70   
 
71  0 toggle @BeforeClass(alwaysRun = true)
72    public void setUpJvOptionPane()
73    {
74  0 JvOptionPane.setInteractiveMode(false);
75  0 JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION);
76    }
77   
78    private AlignViewportI dnaView;
79   
80    private AlignViewportI proteinView;
81   
82    /**
83    * Simple test of mapping with no intron involved.
84    */
 
85  0 toggle @Test(groups = { "Functional" })
86    public void testBuildSearchResults()
87    {
88  0 final Sequence seq1 = new Sequence("Seq1/5-10", "C-G-TA-GC");
89  0 seq1.createDatasetSequence();
90   
91  0 final Sequence aseq1 = new Sequence("Seq1/12-13", "-P-R");
92  0 aseq1.createDatasetSequence();
93   
94    /*
95    * Map dna bases 5-10 to protein residues 12-13
96    */
97  0 AlignedCodonFrame acf = new AlignedCodonFrame();
98  0 MapList map = new MapList(new int[] { 5, 10 }, new int[] { 12, 13 }, 3,
99    1);
100  0 acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
101  0 List<AlignedCodonFrame> acfList = Arrays
102    .asList(new AlignedCodonFrame[]
103    { acf });
104   
105    /*
106    * Check protein residue 12 maps to codon 5-7, 13 to codon 8-10
107    */
108  0 SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 12, acfList);
109  0 assertEquals(1, sr.getResults().size());
110  0 SearchResultMatchI m = sr.getResults().get(0);
111  0 assertEquals(seq1.getDatasetSequence(), m.getSequence());
112  0 assertEquals(5, m.getStart());
113  0 assertEquals(7, m.getEnd());
114  0 sr = MappingUtils.buildSearchResults(aseq1, 13, acfList);
115  0 assertEquals(1, sr.getResults().size());
116  0 m = sr.getResults().get(0);
117  0 assertEquals(seq1.getDatasetSequence(), m.getSequence());
118  0 assertEquals(8, m.getStart());
119  0 assertEquals(10, m.getEnd());
120   
121    /*
122    * Check inverse mappings, from codons 5-7, 8-10 to protein 12, 13
123    */
124  0 for (int i = 5; i < 11; i++)
125    {
126  0 sr = MappingUtils.buildSearchResults(seq1, i, acfList);
127  0 assertEquals(1, sr.getResults().size());
128  0 m = sr.getResults().get(0);
129  0 assertEquals(aseq1.getDatasetSequence(), m.getSequence());
130  0 int residue = i > 7 ? 13 : 12;
131  0 assertEquals(residue, m.getStart());
132  0 assertEquals(residue, m.getEnd());
133    }
134    }
135   
136    /**
137    * Simple test of mapping with introns involved.
138    */
 
139  0 toggle @Test(groups = { "Functional" })
140    public void testBuildSearchResults_withIntron()
141    {
142  0 final Sequence seq1 = new Sequence("Seq1/5-17", "c-G-tAGa-GcAgCtt");
143  0 seq1.createDatasetSequence();
144   
145  0 final Sequence aseq1 = new Sequence("Seq1/8-9", "-E-D");
146  0 aseq1.createDatasetSequence();
147   
148    /*
149    * Map dna bases [6, 8, 9], [11, 13, 115] to protein residues 8 and 9
150    */
151  0 AlignedCodonFrame acf = new AlignedCodonFrame();
152  0 MapList map = new MapList(
153    new int[]
154    { 6, 6, 8, 9, 11, 11, 13, 13, 15, 15 }, new int[] { 8, 9 }, 3,
155    1);
156  0 acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
157  0 List<AlignedCodonFrame> acfList = Arrays
158    .asList(new AlignedCodonFrame[]
159    { acf });
160   
161    /*
162    * Check protein residue 8 maps to [6, 8, 9]
163    */
164  0 SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 8, acfList);
165  0 assertEquals(2, sr.getResults().size());
166  0 SearchResultMatchI m = sr.getResults().get(0);
167  0 assertEquals(seq1.getDatasetSequence(), m.getSequence());
168  0 assertEquals(6, m.getStart());
169  0 assertEquals(6, m.getEnd());
170  0 m = sr.getResults().get(1);
171  0 assertEquals(seq1.getDatasetSequence(), m.getSequence());
172  0 assertEquals(8, m.getStart());
173  0 assertEquals(9, m.getEnd());
174   
175    /*
176    * Check protein residue 9 maps to [11, 13, 15]
177    */
178  0 sr = MappingUtils.buildSearchResults(aseq1, 9, acfList);
179  0 assertEquals(3, sr.getResults().size());
180  0 m = sr.getResults().get(0);
181  0 assertEquals(seq1.getDatasetSequence(), m.getSequence());
182  0 assertEquals(11, m.getStart());
183  0 assertEquals(11, m.getEnd());
184  0 m = sr.getResults().get(1);
185  0 assertEquals(seq1.getDatasetSequence(), m.getSequence());
186  0 assertEquals(13, m.getStart());
187  0 assertEquals(13, m.getEnd());
188  0 m = sr.getResults().get(2);
189  0 assertEquals(seq1.getDatasetSequence(), m.getSequence());
190  0 assertEquals(15, m.getStart());
191  0 assertEquals(15, m.getEnd());
192   
193    /*
194    * Check inverse mappings, from codons to protein
195    */
196  0 for (int i = 5; i < 18; i++)
197    {
198  0 sr = MappingUtils.buildSearchResults(seq1, i, acfList);
199  0 int residue = (i == 6 || i == 8 || i == 9) ? 8
200  0 : (i == 11 || i == 13 || i == 15 ? 9 : 0);
201  0 if (residue == 0)
202    {
203  0 assertEquals(0, sr.getResults().size());
204  0 continue;
205    }
206  0 assertEquals(1, sr.getResults().size());
207  0 m = sr.getResults().get(0);
208  0 assertEquals(aseq1.getDatasetSequence(), m.getSequence());
209  0 assertEquals(residue, m.getStart());
210  0 assertEquals(residue, m.getEnd());
211    }
212    }
213   
214    /**
215    * Test mapping a sequence group made of entire sequences.
216    *
217    * @throws IOException
218    */
 
219  0 toggle @Test(groups = { "Functional" })
220    public void testMapSequenceGroup_sequences() throws IOException
221    {
222    /*
223    * Set up dna and protein Seq1/2/3 with mappings (held on the protein
224    * viewport).
225    */
226  0 AlignmentI cdna = loadAlignment(">Seq1\nACG\n>Seq2\nTGA\n>Seq3\nTAC\n",
227    FileFormat.Fasta);
228  0 cdna.setDataset(null);
229  0 AlignmentI protein = loadAlignment(">Seq1\nK\n>Seq2\nL\n>Seq3\nQ\n",
230    FileFormat.Fasta);
231  0 protein.setDataset(null);
232  0 AlignedCodonFrame acf = new AlignedCodonFrame();
233  0 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 3, 1);
234  0 for (int seq = 0; seq < 3; seq++)
235    {
236  0 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
237    protein.getSequenceAt(seq).getDatasetSequence(), map);
238    }
239  0 List<AlignedCodonFrame> acfList = Arrays
240    .asList(new AlignedCodonFrame[]
241    { acf });
242   
243  0 AlignViewportI dnaView = new AlignViewport(cdna);
244  0 AlignViewportI proteinView = new AlignViewport(protein);
245  0 protein.setCodonFrames(acfList);
246   
247    /*
248    * Select Seq1 and Seq3 in the protein
249    */
250  0 SequenceGroup sg = new SequenceGroup();
251  0 sg.setColourText(true);
252  0 sg.setIdColour(Color.GREEN);
253  0 sg.setOutlineColour(Color.LIGHT_GRAY);
254  0 sg.addSequence(protein.getSequenceAt(0), false);
255  0 sg.addSequence(protein.getSequenceAt(2), false);
256  0 sg.setEndRes(protein.getWidth() - 1);
257   
258    /*
259    * Verify the mapped sequence group in dna
260    */
261  0 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
262    proteinView, dnaView);
263  0 assertTrue(mappedGroup.getColourText());
264  0 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
265  0 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
266  0 assertEquals(2, mappedGroup.getSequences().size());
267  0 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
268  0 assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
269  0 assertEquals(0, mappedGroup.getStartRes());
270  0 assertEquals(2, mappedGroup.getEndRes()); // 3 columns (1 codon)
271   
272    /*
273    * Verify mapping sequence group from dna to protein
274    */
275  0 sg.clear();
276  0 sg.addSequence(cdna.getSequenceAt(1), false);
277  0 sg.addSequence(cdna.getSequenceAt(0), false);
278  0 sg.setStartRes(0);
279  0 sg.setEndRes(2);
280  0 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
281  0 assertTrue(mappedGroup.getColourText());
282  0 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
283  0 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
284  0 assertEquals(2, mappedGroup.getSequences().size());
285  0 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
286  0 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
287  0 assertEquals(0, mappedGroup.getStartRes());
288  0 assertEquals(0, mappedGroup.getEndRes());
289    }
290   
291    /**
292    * Helper method to load an alignment and ensure dataset sequences are set up.
293    *
294    * @param data
295    * @param format
296    * TODO
297    * @return
298    * @throws IOException
299    */
 
300  0 toggle protected AlignmentI loadAlignment(final String data, FileFormatI format)
301    throws IOException
302    {
303  0 AlignmentI a = new FormatAdapter().readFile(data, DataSourceType.PASTE,
304    format);
305  0 a.setDataset(null);
306  0 return a;
307    }
308   
309    /**
310    * Test mapping a column selection in protein to its dna equivalent
311    *
312    * @throws IOException
313    */
 
314  0 toggle @Test(groups = { "Functional" })
315    public void testMapColumnSelection_proteinToDna() throws IOException
316    {
317  0 setupMappedAlignments();
318   
319  0 ColumnSelection colsel = new ColumnSelection();
320  0 HiddenColumns hidden = new HiddenColumns();
321   
322    /*
323    * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
324    * in dna respectively, overall 0-4
325    */
326  0 colsel.addElement(0);
327  0 ColumnSelection cs = new ColumnSelection();
328  0 HiddenColumns hs = new HiddenColumns();
329  0 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
330    cs, hs);
331  0 assertEquals("[0, 1, 2, 3, 4]", cs.getSelected().toString());
332   
333    /*
334    * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
335    */
336  0 cs.clear();
337  0 colsel.clear();
338  0 colsel.addElement(1);
339  0 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
340    cs, hs);
341  0 assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
342   
343    /*
344    * Column 2 in protein picks up gaps only - no mapping
345    */
346  0 cs.clear();
347  0 colsel.clear();
348  0 colsel.addElement(2);
349  0 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
350    cs, hs);
351  0 assertEquals("[]", cs.getSelected().toString());
352   
353    /*
354    * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
355    * 6-9, 6-10, 5-8 respectively, overall to 5-10
356    */
357  0 cs.clear();
358  0 colsel.clear();
359  0 colsel.addElement(3);
360  0 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
361    cs, hs);
362  0 assertEquals("[5, 6, 7, 8, 9, 10]", cs.getSelected().toString());
363   
364    /*
365    * Combine selection of columns 1 and 3 to get a discontiguous mapped
366    * selection
367    */
368  0 cs.clear();
369  0 colsel.clear();
370  0 colsel.addElement(1);
371  0 colsel.addElement(3);
372  0 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
373    cs, hs);
374  0 assertEquals("[0, 1, 2, 3, 5, 6, 7, 8, 9, 10]",
375    cs.getSelected().toString());
376    }
377   
378    /**
379    * Set up mappings for tests from 3 dna to 3 protein sequences. Sequences have
380    * offset start positions for a more general test case.
381    *
382    * @throws IOException
383    */
 
384  0 toggle protected void setupMappedAlignments() throws IOException
385    {
386    /*
387    * Map (upper-case = coding):
388    * Seq1/10-18 AC-GctGtC-T to Seq1/40 -K-P
389    * Seq2/20-27 Tc-GA-G-T-T to Seq2/20-27 L--Q
390    * Seq3/30-38 TtTT-AaCGg- to Seq3/60-61\nG--S
391    */
392  0 AlignmentI cdna = loadAlignment(">Seq1/10-18\nAC-GctGtC-T\n"
393    + ">Seq2/20-27\nTc-GA-G-T-Tc\n" + ">Seq3/30-38\nTtTT-AaCGg-\n",
394    FileFormat.Fasta);
395  0 cdna.setDataset(null);
396  0 AlignmentI protein = loadAlignment(
397    ">Seq1/40-41\n-K-P\n>Seq2/50-51\nL--Q\n>Seq3/60-61\nG--S\n",
398    FileFormat.Fasta);
399  0 protein.setDataset(null);
400   
401    // map first dna to first protein seq
402  0 AlignedCodonFrame acf = new AlignedCodonFrame();
403  0 MapList map = new MapList(new int[] { 10, 12, 15, 15, 17, 18 },
404    new int[]
405    { 40, 41 }, 3, 1);
406  0 acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(),
407    protein.getSequenceAt(0).getDatasetSequence(), map);
408   
409    // map second dna to second protein seq
410  0 map = new MapList(new int[] { 20, 20, 22, 23, 24, 26 },
411    new int[]
412    { 50, 51 }, 3, 1);
413  0 acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(),
414    protein.getSequenceAt(1).getDatasetSequence(), map);
415   
416    // map third dna to third protein seq
417  0 map = new MapList(new int[] { 30, 30, 32, 34, 36, 37 },
418    new int[]
419    { 60, 61 }, 3, 1);
420  0 acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(),
421    protein.getSequenceAt(2).getDatasetSequence(), map);
422  0 List<AlignedCodonFrame> acfList = Arrays
423    .asList(new AlignedCodonFrame[]
424    { acf });
425   
426  0 dnaView = new AlignViewport(cdna);
427  0 proteinView = new AlignViewport(protein);
428  0 protein.setCodonFrames(acfList);
429    }
430   
431    /**
432    * Test mapping a column selection in dna to its protein equivalent
433    *
434    * @throws IOException
435    */
 
436  0 toggle @Test(groups = { "Functional" })
437    public void testMapColumnSelection_dnaToProtein() throws IOException
438    {
439  0 setupMappedAlignments();
440   
441  0 ColumnSelection colsel = new ColumnSelection();
442  0 HiddenColumns hidden = new HiddenColumns();
443   
444    /*
445    * Column 0 in dna picks up first bases which map to residue 1, columns 0-1
446    * in protein.
447    */
448  0 ColumnSelection cs = new ColumnSelection();
449  0 HiddenColumns hs = new HiddenColumns();
450  0 colsel.addElement(0);
451  0 MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
452    cs, hs);
453  0 assertEquals("[0, 1]", cs.getSelected().toString());
454   
455    /*
456    * Columns 3-5 in dna map to the first residues in protein Seq1, Seq2, and
457    * the first two in Seq3. Overall to columns 0, 1, 3 (col2 is all gaps).
458    */
459  0 colsel.addElement(3);
460  0 colsel.addElement(4);
461  0 colsel.addElement(5);
462  0 cs.clear();
463  0 MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
464    cs, hs);
465  0 assertEquals("[0, 1, 3]", cs.getSelected().toString());
466    }
467   
 
468  0 toggle @Test(groups = { "Functional" })
469    public void testMapColumnSelection_null() throws IOException
470    {
471  0 setupMappedAlignments();
472  0 ColumnSelection cs = new ColumnSelection();
473  0 HiddenColumns hs = new HiddenColumns();
474  0 MappingUtils.mapColumnSelection(null, null, dnaView, proteinView, cs,
475    hs);
476  0 assertTrue("mapped selection not empty", cs.getSelected().isEmpty());
477    }
478   
479    /**
480    * Tests for the method that converts a series of [start, end] ranges to
481    * single positions
482    */
 
483  0 toggle @Test(groups = { "Functional" })
484    public void testFlattenRanges()
485    {
486  0 assertEquals("[1, 2, 3, 4]",
487    Arrays.toString(MappingUtils.flattenRanges(new int[]
488    { 1, 4 })));
489  0 assertEquals("[1, 2, 3, 4]",
490    Arrays.toString(MappingUtils.flattenRanges(new int[]
491    { 1, 2, 3, 4 })));
492  0 assertEquals("[1, 2, 3, 4]",
493    Arrays.toString(MappingUtils.flattenRanges(new int[]
494    { 1, 1, 2, 2, 3, 3, 4, 4 })));
495  0 assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
496    Arrays.toString(MappingUtils.flattenRanges(new int[]
497    { 1, 4, 7, 9, 12, 12 })));
498    // trailing unpaired start position is ignored:
499  0 assertEquals("[1, 2, 3, 4, 7, 8, 9, 12]",
500    Arrays.toString(MappingUtils.flattenRanges(new int[]
501    { 1, 4, 7, 9, 12, 12, 15 })));
502    }
503   
504    /**
505    * Test mapping a sequence group made of entire columns.
506    *
507    * @throws IOException
508    */
 
509  0 toggle @Test(groups = { "Functional" })
510    public void testMapSequenceGroup_columns() throws IOException
511    {
512    /*
513    * Set up dna and protein Seq1/2/3 with mappings (held on the protein
514    * viewport).
515    */
516  0 AlignmentI cdna = loadAlignment(
517    ">Seq1\nACGGCA\n>Seq2\nTGACAG\n>Seq3\nTACGTA\n",
518    FileFormat.Fasta);
519  0 cdna.setDataset(null);
520  0 AlignmentI protein = loadAlignment(">Seq1\nKA\n>Seq2\nLQ\n>Seq3\nQV\n",
521    FileFormat.Fasta);
522  0 protein.setDataset(null);
523  0 AlignedCodonFrame acf = new AlignedCodonFrame();
524  0 MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
525  0 for (int seq = 0; seq < 3; seq++)
526    {
527  0 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
528    protein.getSequenceAt(seq).getDatasetSequence(), map);
529    }
530  0 List<AlignedCodonFrame> acfList = Arrays
531    .asList(new AlignedCodonFrame[]
532    { acf });
533   
534  0 AlignViewportI dnaView = new AlignViewport(cdna);
535  0 AlignViewportI proteinView = new AlignViewport(protein);
536  0 protein.setCodonFrames(acfList);
537   
538    /*
539    * Select all sequences, column 2 in the protein
540    */
541  0 SequenceGroup sg = new SequenceGroup();
542  0 sg.setColourText(true);
543  0 sg.setIdColour(Color.GREEN);
544  0 sg.setOutlineColour(Color.LIGHT_GRAY);
545  0 sg.addSequence(protein.getSequenceAt(0), false);
546  0 sg.addSequence(protein.getSequenceAt(1), false);
547  0 sg.addSequence(protein.getSequenceAt(2), false);
548  0 sg.setStartRes(1);
549  0 sg.setEndRes(1);
550   
551    /*
552    * Verify the mapped sequence group in dna
553    */
554  0 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
555    proteinView, dnaView);
556  0 assertTrue(mappedGroup.getColourText());
557  0 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
558  0 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
559  0 assertEquals(3, mappedGroup.getSequences().size());
560  0 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
561  0 assertSame(cdna.getSequenceAt(1), mappedGroup.getSequences().get(1));
562  0 assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(2));
563  0 assertEquals(3, mappedGroup.getStartRes());
564  0 assertEquals(5, mappedGroup.getEndRes());
565   
566    /*
567    * Verify mapping sequence group from dna to protein
568    */
569  0 sg.clear();
570  0 sg.addSequence(cdna.getSequenceAt(0), false);
571  0 sg.addSequence(cdna.getSequenceAt(1), false);
572  0 sg.addSequence(cdna.getSequenceAt(2), false);
573    // select columns 2 and 3 in DNA which span protein columns 0 and 1
574  0 sg.setStartRes(2);
575  0 sg.setEndRes(3);
576  0 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
577  0 assertTrue(mappedGroup.getColourText());
578  0 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
579  0 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
580  0 assertEquals(3, mappedGroup.getSequences().size());
581  0 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(0));
582  0 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(1));
583  0 assertSame(protein.getSequenceAt(2), mappedGroup.getSequences().get(2));
584  0 assertEquals(0, mappedGroup.getStartRes());
585  0 assertEquals(1, mappedGroup.getEndRes());
586    }
587   
588    /**
589    * Test mapping a sequence group made of a sequences/columns region.
590    *
591    * @throws IOException
592    */
 
593  0 toggle @Test(groups = { "Functional" })
594    public void testMapSequenceGroup_region() throws IOException
595    {
596    /*
597    * Set up gapped dna and protein Seq1/2/3 with mappings (held on the protein
598    * viewport).
599    */
600  0 AlignmentI cdna = loadAlignment(
601    ">Seq1\nA-CG-GC--AT-CA\n>Seq2\n-TG-AC-AG-T-AT\n>Seq3\n-T--ACG-TAAT-G\n",
602    FileFormat.Fasta);
603  0 cdna.setDataset(null);
604  0 AlignmentI protein = loadAlignment(
605    ">Seq1\n-KA-S\n>Seq2\n--L-QY\n>Seq3\nQ-V-M\n",
606    FileFormat.Fasta);
607  0 protein.setDataset(null);
608  0 AlignedCodonFrame acf = new AlignedCodonFrame();
609  0 MapList map = new MapList(new int[] { 1, 9 }, new int[] { 1, 3 }, 3, 1);
610  0 for (int seq = 0; seq < 3; seq++)
611    {
612  0 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
613    protein.getSequenceAt(seq).getDatasetSequence(), map);
614    }
615  0 List<AlignedCodonFrame> acfList = Arrays
616    .asList(new AlignedCodonFrame[]
617    { acf });
618   
619  0 AlignViewportI dnaView = new AlignViewport(cdna);
620  0 AlignViewportI proteinView = new AlignViewport(protein);
621  0 protein.setCodonFrames(acfList);
622   
623    /*
624    * Select Seq1 and Seq2 in the protein, column 1 (K/-). Expect mapped
625    * sequence group to cover Seq1, columns 0-3 (ACG). Because the selection
626    * only includes a gap in Seq2 there is no mappable selection region in the
627    * corresponding DNA.
628    */
629  0 SequenceGroup sg = new SequenceGroup();
630  0 sg.setColourText(true);
631  0 sg.setIdColour(Color.GREEN);
632  0 sg.setOutlineColour(Color.LIGHT_GRAY);
633  0 sg.addSequence(protein.getSequenceAt(0), false);
634  0 sg.addSequence(protein.getSequenceAt(1), false);
635  0 sg.setStartRes(1);
636  0 sg.setEndRes(1);
637   
638    /*
639    * Verify the mapped sequence group in dna
640    */
641  0 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
642    proteinView, dnaView);
643  0 assertTrue(mappedGroup.getColourText());
644  0 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
645  0 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
646  0 assertEquals(1, mappedGroup.getSequences().size());
647  0 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
648    // Seq2 in protein has a gap in column 1 - ignored
649    // Seq1 has K which should map to columns 0-3 in Seq1
650  0 assertEquals(0, mappedGroup.getStartRes());
651  0 assertEquals(3, mappedGroup.getEndRes());
652   
653    /*
654    * Now select cols 2-4 in protein. These cover Seq1:AS Seq2:LQ Seq3:VM which
655    * extend over DNA columns 3-12, 1-7, 6-13 respectively, or 1-13 overall.
656    */
657  0 sg.setStartRes(2);
658  0 sg.setEndRes(4);
659  0 mappedGroup = MappingUtils.mapSequenceGroup(sg, proteinView, dnaView);
660  0 assertEquals(1, mappedGroup.getStartRes());
661  0 assertEquals(13, mappedGroup.getEndRes());
662   
663    /*
664    * Verify mapping sequence group from dna to protein
665    */
666  0 sg.clear();
667  0 sg.addSequence(cdna.getSequenceAt(0), false);
668   
669    // select columns 4,5 - includes Seq1:codon2 (A) only
670  0 sg.setStartRes(4);
671  0 sg.setEndRes(5);
672  0 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
673  0 assertEquals(2, mappedGroup.getStartRes());
674  0 assertEquals(2, mappedGroup.getEndRes());
675   
676    // add Seq2 to dna selection cols 4-5 include codons 1 and 2 (LQ)
677  0 sg.addSequence(cdna.getSequenceAt(1), false);
678  0 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
679  0 assertEquals(2, mappedGroup.getStartRes());
680  0 assertEquals(4, mappedGroup.getEndRes());
681   
682    // add Seq3 to dna selection cols 4-5 include codon 1 (Q)
683  0 sg.addSequence(cdna.getSequenceAt(2), false);
684  0 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
685  0 assertEquals(0, mappedGroup.getStartRes());
686  0 assertEquals(4, mappedGroup.getEndRes());
687    }
688   
 
689  0 toggle @Test(groups = { "Functional" })
690    public void testFindMappingsForSequence()
691    {
692  0 SequenceI seq1 = new Sequence("Seq1", "ABC");
693  0 SequenceI seq2 = new Sequence("Seq2", "ABC");
694  0 SequenceI seq3 = new Sequence("Seq3", "ABC");
695  0 SequenceI seq4 = new Sequence("Seq4", "ABC");
696  0 seq1.createDatasetSequence();
697  0 seq2.createDatasetSequence();
698  0 seq3.createDatasetSequence();
699  0 seq4.createDatasetSequence();
700   
701    /*
702    * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1
703    */
704  0 AlignedCodonFrame acf1 = new AlignedCodonFrame();
705  0 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
706  0 acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
707  0 AlignedCodonFrame acf2 = new AlignedCodonFrame();
708  0 acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
709  0 AlignedCodonFrame acf3 = new AlignedCodonFrame();
710  0 acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
711   
712  0 List<AlignedCodonFrame> mappings = new ArrayList<>();
713  0 mappings.add(acf1);
714  0 mappings.add(acf2);
715  0 mappings.add(acf3);
716   
717    /*
718    * Seq1 has three mappings
719    */
720  0 List<AlignedCodonFrame> result = MappingUtils
721    .findMappingsForSequence(seq1, mappings);
722  0 assertEquals(3, result.size());
723  0 assertTrue(result.contains(acf1));
724  0 assertTrue(result.contains(acf2));
725  0 assertTrue(result.contains(acf3));
726   
727    /*
728    * Seq2 has two mappings
729    */
730  0 result = MappingUtils.findMappingsForSequence(seq2, mappings);
731  0 assertEquals(2, result.size());
732  0 assertTrue(result.contains(acf1));
733  0 assertTrue(result.contains(acf2));
734   
735    /*
736    * Seq3 has one mapping
737    */
738  0 result = MappingUtils.findMappingsForSequence(seq3, mappings);
739  0 assertEquals(1, result.size());
740  0 assertTrue(result.contains(acf3));
741   
742    /*
743    * Seq4 has no mappings
744    */
745  0 result = MappingUtils.findMappingsForSequence(seq4, mappings);
746  0 assertEquals(0, result.size());
747   
748  0 result = MappingUtils.findMappingsForSequence(null, mappings);
749  0 assertEquals(0, result.size());
750   
751  0 result = MappingUtils.findMappingsForSequence(seq1, null);
752  0 assertEquals(0, result.size());
753   
754  0 result = MappingUtils.findMappingsForSequence(null, null);
755  0 assertEquals(0, result.size());
756    }
757   
758    /**
759    * just like the one above, but this time, we provide a set of sequences to
760    * subselect the mapping search
761    */
 
762  0 toggle @Test(groups = { "Functional" })
763    public void testFindMappingsForSequenceAndOthers()
764    {
765  0 SequenceI seq1 = new Sequence("Seq1", "ABC");
766  0 SequenceI seq2 = new Sequence("Seq2", "ABC");
767  0 SequenceI seq3 = new Sequence("Seq3", "ABC");
768  0 SequenceI seq4 = new Sequence("Seq4", "ABC");
769  0 seq1.createDatasetSequence();
770  0 seq2.createDatasetSequence();
771  0 seq3.createDatasetSequence();
772  0 seq4.createDatasetSequence();
773   
774    /*
775    * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1, seq3 to seq4
776    */
777  0 AlignedCodonFrame acf1 = new AlignedCodonFrame();
778  0 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
779  0 acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
780  0 AlignedCodonFrame acf2 = new AlignedCodonFrame();
781  0 acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
782  0 AlignedCodonFrame acf3 = new AlignedCodonFrame();
783  0 acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
784  0 AlignedCodonFrame acf4 = new AlignedCodonFrame();
785  0 acf4.addMap(seq3.getDatasetSequence(), seq4.getDatasetSequence(), map);
786   
787  0 List<AlignedCodonFrame> mappings = new ArrayList<>();
788  0 mappings.add(acf1);
789  0 mappings.add(acf2);
790  0 mappings.add(acf3);
791  0 mappings.add(acf4);
792   
793    /*
794    * test for null args
795    */
796  0 List<AlignedCodonFrame> result = MappingUtils
797    .findMappingsForSequenceAndOthers(null, mappings,
798    Arrays.asList(new SequenceI[]
799    { seq1, seq2 }));
800  0 assertTrue(result.isEmpty());
801   
802  0 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, null,
803    Arrays.asList(new SequenceI[]
804    { seq1, seq2 }));
805  0 assertTrue(result.isEmpty());
806   
807    /*
808    * Seq1 has three mappings, but filter argument will only accept
809    * those to seq2
810    */
811  0 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
812    Arrays.asList(new SequenceI[]
813    { seq1, seq2, seq1.getDatasetSequence() }));
814  0 assertEquals(2, result.size());
815  0 assertTrue(result.contains(acf1));
816  0 assertTrue(result.contains(acf2));
817  0 assertFalse("Did not expect to find mapping acf3 - subselect failed",
818    result.contains(acf3));
819  0 assertFalse(
820    "Did not expect to find mapping acf4 - doesn't involve sequence",
821    result.contains(acf4));
822   
823    /*
824    * and verify the no filter case
825    */
826  0 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
827    null);
828  0 assertEquals(3, result.size());
829  0 assertTrue(result.contains(acf1));
830  0 assertTrue(result.contains(acf2));
831  0 assertTrue(result.contains(acf3));
832    }
833   
 
834  0 toggle @Test(groups = { "Functional" })
835    public void testMapEditCommand()
836    {
837  0 SequenceI dna = new Sequence("Seq1", "---ACG---GCATCA", 8, 16);
838  0 SequenceI protein = new Sequence("Seq2", "-T-AS", 5, 7);
839  0 dna.createDatasetSequence();
840  0 protein.createDatasetSequence();
841  0 AlignedCodonFrame acf = new AlignedCodonFrame();
842  0 MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3,
843    1);
844  0 acf.addMap(dna.getDatasetSequence(), protein.getDatasetSequence(), map);
845  0 List<AlignedCodonFrame> mappings = new ArrayList<>();
846  0 mappings.add(acf);
847   
848  0 AlignmentI prot = new Alignment(new SequenceI[] { protein });
849  0 prot.setCodonFrames(mappings);
850  0 AlignmentI nuc = new Alignment(new SequenceI[] { dna });
851   
852    /*
853    * construct and perform the edit command to turn "-T-AS" in to "-T-A--S"
854    * i.e. insert two gaps at column 4
855    */
856  0 EditCommand ec = new EditCommand();
857  0 final Edit edit = ec.new Edit(Action.INSERT_GAP,
858    new SequenceI[]
859    { protein }, 4, 2, '-');
860  0 ec.appendEdit(edit, prot, true, null);
861   
862    /*
863    * the mapped edit command should be to insert 6 gaps before base 4 in the
864    * nucleotide sequence, which corresponds to aligned column 12 in the dna
865    */
866  0 EditCommand mappedEdit = MappingUtils.mapEditCommand(ec, false, nuc,
867    '-', mappings);
868  0 assertEquals(1, mappedEdit.getEdits().size());
869  0 Edit e = mappedEdit.getEdits().get(0);
870  0 assertEquals(1, e.getSequences().length);
871  0 assertEquals(dna, e.getSequences()[0]);
872  0 assertEquals(12, e.getPosition());
873  0 assertEquals(6, e.getNumber());
874    }
875   
876    /**
877    * Tests for the method that converts a series of [start, end] ranges to
878    * single positions, where the mapping is to a reverse strand i.e. start is
879    * greater than end point mapped to
880    */
 
881  0 toggle @Test(groups = { "Functional" })
882    public void testFlattenRanges_reverseStrand()
883    {
884  0 assertEquals("[4, 3, 2, 1]",
885    Arrays.toString(MappingUtils.flattenRanges(new int[]
886    { 4, 1 })));
887  0 assertEquals("[4, 3, 2, 1]",
888    Arrays.toString(MappingUtils.flattenRanges(new int[]
889    { 4, 3, 2, 1 })));
890  0 assertEquals("[4, 3, 2, 1]",
891    Arrays.toString(MappingUtils.flattenRanges(new int[]
892    { 4, 4, 3, 3, 2, 2, 1, 1 })));
893  0 assertEquals("[12, 9, 8, 7, 4, 3, 2, 1]",
894    Arrays.toString(MappingUtils.flattenRanges(new int[]
895    { 12, 12, 9, 7, 4, 1 })));
896    // forwards and backwards anyone?
897  0 assertEquals("[4, 5, 6, 3, 2, 1]",
898    Arrays.toString(MappingUtils.flattenRanges(new int[]
899    { 4, 6, 3, 1 })));
900    // backwards and forwards
901  0 assertEquals("[3, 2, 1, 4, 5, 6]",
902    Arrays.toString(MappingUtils.flattenRanges(new int[]
903    { 3, 1, 4, 6 })));
904    // trailing unpaired start position is ignored:
905  0 assertEquals("[12, 9, 8, 7, 4, 3, 2]",
906    Arrays.toString(MappingUtils.flattenRanges(new int[]
907    { 12, 12, 9, 7, 4, 2, 1 })));
908    }
909   
910    /**
911    * Test mapping a column selection including hidden columns
912    *
913    * @throws IOException
914    */
 
915  0 toggle @Test(groups = { "Functional" })
916    public void testMapColumnSelection_hiddenColumns() throws IOException
917    {
918  0 setupMappedAlignments();
919   
920  0 ColumnSelection proteinSelection = new ColumnSelection();
921  0 HiddenColumns hiddenCols = new HiddenColumns();
922   
923    /*
924    * Column 0 in protein picks up Seq2/L, Seq3/G which map to cols 0-4 and 0-3
925    * in dna respectively, overall 0-4
926    */
927  0 proteinSelection.hideSelectedColumns(0, hiddenCols);
928  0 ColumnSelection dnaSelection = new ColumnSelection();
929  0 HiddenColumns dnaHidden = new HiddenColumns();
930  0 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
931    proteinView, dnaView, dnaSelection, dnaHidden);
932  0 assertEquals("[]", dnaSelection.getSelected().toString());
933  0 Iterator<int[]> regions = dnaHidden.iterator();
934  0 assertEquals(1, dnaHidden.getNumberOfRegions());
935  0 assertEquals("[0, 4]", Arrays.toString(regions.next()));
936   
937    /*
938    * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna
939    */
940  0 dnaSelection = new ColumnSelection();
941  0 dnaHidden = new HiddenColumns();
942  0 hiddenCols.revealAllHiddenColumns(proteinSelection);
943    // the unhidden columns are now marked selected!
944  0 assertEquals("[0]", proteinSelection.getSelected().toString());
945    // deselect these or hideColumns will be expanded to include 0
946  0 proteinSelection.clear();
947  0 proteinSelection.hideSelectedColumns(1, hiddenCols);
948  0 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
949    proteinView, dnaView, dnaSelection, dnaHidden);
950  0 regions = dnaHidden.iterator();
951  0 assertEquals(1, dnaHidden.getNumberOfRegions());
952  0 assertEquals("[0, 3]", Arrays.toString(regions.next()));
953   
954    /*
955    * Column 2 in protein picks up gaps only - no mapping
956    */
957  0 dnaSelection = new ColumnSelection();
958  0 dnaHidden = new HiddenColumns();
959  0 hiddenCols.revealAllHiddenColumns(proteinSelection);
960  0 proteinSelection.clear();
961  0 proteinSelection.hideSelectedColumns(2, hiddenCols);
962  0 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
963    proteinView, dnaView, dnaSelection, dnaHidden);
964  0 assertEquals(0, dnaHidden.getNumberOfRegions());
965   
966    /*
967    * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns
968    * 6-9, 6-10, 5-8 respectively, overall to 5-10
969    */
970  0 dnaSelection = new ColumnSelection();
971  0 dnaHidden = new HiddenColumns();
972  0 hiddenCols.revealAllHiddenColumns(proteinSelection);
973  0 proteinSelection.clear();
974  0 proteinSelection.hideSelectedColumns(3, hiddenCols); // 5-10 hidden in dna
975  0 proteinSelection.addElement(1); // 0-3 selected in dna
976  0 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
977    proteinView, dnaView, dnaSelection, dnaHidden);
978  0 assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
979  0 regions = dnaHidden.iterator();
980  0 assertEquals(1, dnaHidden.getNumberOfRegions());
981  0 assertEquals("[5, 10]", Arrays.toString(regions.next()));
982   
983    /*
984    * Combine hiding columns 1 and 3 to get discontiguous hidden columns
985    */
986  0 dnaSelection = new ColumnSelection();
987  0 dnaHidden = new HiddenColumns();
988  0 hiddenCols.revealAllHiddenColumns(proteinSelection);
989  0 proteinSelection.clear();
990  0 proteinSelection.hideSelectedColumns(1, hiddenCols);
991  0 proteinSelection.hideSelectedColumns(3, hiddenCols);
992  0 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
993    proteinView, dnaView, dnaSelection, dnaHidden);
994  0 regions = dnaHidden.iterator();
995  0 assertEquals(2, dnaHidden.getNumberOfRegions());
996  0 assertEquals("[0, 3]", Arrays.toString(regions.next()));
997  0 assertEquals("[5, 10]", Arrays.toString(regions.next()));
998    }
999   
 
1000  0 toggle @Test(groups = { "Functional" })
1001    public void testGetLength()
1002    {
1003  0 assertEquals(0, MappingUtils.getLength(null));
1004   
1005    /*
1006    * [start, end] ranges
1007    */
1008  0 List<int[]> ranges = new ArrayList<>();
1009  0 assertEquals(0, MappingUtils.getLength(ranges));
1010  0 ranges.add(new int[] { 1, 1 });
1011  0 assertEquals(1, MappingUtils.getLength(ranges));
1012  0 ranges.add(new int[] { 2, 10 });
1013  0 assertEquals(10, MappingUtils.getLength(ranges));
1014  0 ranges.add(new int[] { 20, 10 });
1015  0 assertEquals(21, MappingUtils.getLength(ranges));
1016   
1017    /*
1018    * [start, end, start, end...] ranges
1019    */
1020  0 ranges.clear();
1021  0 ranges.add(new int[] { 1, 5, 8, 4 });
1022  0 ranges.add(new int[] { 8, 2 });
1023  0 ranges.add(new int[] { 12, 12 });
1024  0 assertEquals(18, MappingUtils.getLength(ranges));
1025    }
1026   
 
1027  0 toggle @Test(groups = { "Functional" })
1028    public void testContains()
1029    {
1030  0 assertFalse(MappingUtils.contains(null, 1));
1031  0 List<int[]> ranges = new ArrayList<>();
1032  0 assertFalse(MappingUtils.contains(ranges, 1));
1033   
1034  0 ranges.add(new int[] { 1, 4 });
1035  0 ranges.add(new int[] { 6, 6 });
1036  0 ranges.add(new int[] { 8, 10 });
1037  0 ranges.add(new int[] { 30, 20 });
1038  0 ranges.add(new int[] { -16, -44 });
1039   
1040  0 assertFalse(MappingUtils.contains(ranges, 0));
1041  0 assertTrue(MappingUtils.contains(ranges, 1));
1042  0 assertTrue(MappingUtils.contains(ranges, 2));
1043  0 assertTrue(MappingUtils.contains(ranges, 3));
1044  0 assertTrue(MappingUtils.contains(ranges, 4));
1045  0 assertFalse(MappingUtils.contains(ranges, 5));
1046   
1047  0 assertTrue(MappingUtils.contains(ranges, 6));
1048  0 assertFalse(MappingUtils.contains(ranges, 7));
1049   
1050  0 assertTrue(MappingUtils.contains(ranges, 8));
1051  0 assertTrue(MappingUtils.contains(ranges, 9));
1052  0 assertTrue(MappingUtils.contains(ranges, 10));
1053   
1054  0 assertFalse(MappingUtils.contains(ranges, 31));
1055  0 assertTrue(MappingUtils.contains(ranges, 30));
1056  0 assertTrue(MappingUtils.contains(ranges, 29));
1057  0 assertTrue(MappingUtils.contains(ranges, 20));
1058  0 assertFalse(MappingUtils.contains(ranges, 19));
1059   
1060  0 assertFalse(MappingUtils.contains(ranges, -15));
1061  0 assertTrue(MappingUtils.contains(ranges, -16));
1062  0 assertTrue(MappingUtils.contains(ranges, -44));
1063  0 assertFalse(MappingUtils.contains(ranges, -45));
1064    }
1065   
1066    /**
1067    * Test the method that drops positions from the start of a mapped range
1068    */
 
1069  0 toggle @Test(groups = "Functional")
1070    public void testRemoveStartPositions()
1071    {
1072  0 int[] ranges = new int[] { 1, 10 };
1073  0 int[] adjusted = MappingUtils.removeStartPositions(0, ranges);
1074  0 assertEquals("[1, 10]", Arrays.toString(adjusted));
1075   
1076  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1077  0 assertEquals("[2, 10]", Arrays.toString(adjusted));
1078  0 assertEquals("[1, 10]", Arrays.toString(ranges));
1079   
1080  0 ranges = adjusted;
1081  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1082  0 assertEquals("[3, 10]", Arrays.toString(adjusted));
1083  0 assertEquals("[2, 10]", Arrays.toString(ranges));
1084   
1085  0 ranges = new int[] { 2, 3, 10, 12 };
1086  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1087  0 assertEquals("[3, 3, 10, 12]", Arrays.toString(adjusted));
1088  0 assertEquals("[2, 3, 10, 12]", Arrays.toString(ranges));
1089   
1090  0 ranges = new int[] { 2, 2, 8, 12 };
1091  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1092  0 assertEquals("[8, 12]", Arrays.toString(adjusted));
1093  0 assertEquals("[2, 2, 8, 12]", Arrays.toString(ranges));
1094   
1095  0 ranges = new int[] { 2, 2, 8, 12 };
1096  0 adjusted = MappingUtils.removeStartPositions(2, ranges);
1097  0 assertEquals("[9, 12]", Arrays.toString(adjusted));
1098  0 assertEquals("[2, 2, 8, 12]", Arrays.toString(ranges));
1099   
1100  0 ranges = new int[] { 2, 2, 4, 4, 9, 12 };
1101  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1102  0 assertEquals("[4, 4, 9, 12]", Arrays.toString(adjusted));
1103  0 assertEquals("[2, 2, 4, 4, 9, 12]", Arrays.toString(ranges));
1104   
1105  0 ranges = new int[] { 2, 2, 4, 4, 9, 12 };
1106  0 adjusted = MappingUtils.removeStartPositions(2, ranges);
1107  0 assertEquals("[9, 12]", Arrays.toString(adjusted));
1108  0 assertEquals("[2, 2, 4, 4, 9, 12]", Arrays.toString(ranges));
1109   
1110  0 ranges = new int[] { 2, 3, 9, 12 };
1111  0 adjusted = MappingUtils.removeStartPositions(3, ranges);
1112  0 assertEquals("[10, 12]", Arrays.toString(adjusted));
1113  0 assertEquals("[2, 3, 9, 12]", Arrays.toString(ranges));
1114    }
1115   
1116    /**
1117    * Test the method that drops positions from the start of a mapped range, on
1118    * the reverse strand
1119    */
 
1120  0 toggle @Test(groups = "Functional")
1121    public void testRemoveStartPositions_reverseStrand()
1122    {
1123  0 int[] ranges = new int[] { 10, 1 };
1124  0 int[] adjusted = MappingUtils.removeStartPositions(0, ranges);
1125  0 assertEquals("[10, 1]", Arrays.toString(adjusted));
1126  0 assertEquals("[10, 1]", Arrays.toString(ranges));
1127   
1128  0 ranges = adjusted;
1129  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1130  0 assertEquals("[9, 1]", Arrays.toString(adjusted));
1131  0 assertEquals("[10, 1]", Arrays.toString(ranges));
1132   
1133  0 ranges = adjusted;
1134  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1135  0 assertEquals("[8, 1]", Arrays.toString(adjusted));
1136  0 assertEquals("[9, 1]", Arrays.toString(ranges));
1137   
1138  0 ranges = new int[] { 12, 11, 9, 6 };
1139  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1140  0 assertEquals("[11, 11, 9, 6]", Arrays.toString(adjusted));
1141  0 assertEquals("[12, 11, 9, 6]", Arrays.toString(ranges));
1142   
1143  0 ranges = new int[] { 12, 12, 8, 4 };
1144  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1145  0 assertEquals("[8, 4]", Arrays.toString(adjusted));
1146  0 assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
1147   
1148  0 ranges = new int[] { 12, 12, 8, 4 };
1149  0 adjusted = MappingUtils.removeStartPositions(2, ranges);
1150  0 assertEquals("[7, 4]", Arrays.toString(adjusted));
1151  0 assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
1152   
1153  0 ranges = new int[] { 12, 12, 10, 10, 8, 4 };
1154  0 adjusted = MappingUtils.removeStartPositions(1, ranges);
1155  0 assertEquals("[10, 10, 8, 4]", Arrays.toString(adjusted));
1156  0 assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
1157   
1158  0 ranges = new int[] { 12, 12, 10, 10, 8, 4 };
1159  0 adjusted = MappingUtils.removeStartPositions(2, ranges);
1160  0 assertEquals("[8, 4]", Arrays.toString(adjusted));
1161  0 assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
1162   
1163  0 ranges = new int[] { 12, 11, 8, 4 };
1164  0 adjusted = MappingUtils.removeStartPositions(3, ranges);
1165  0 assertEquals("[7, 4]", Arrays.toString(adjusted));
1166  0 assertEquals("[12, 11, 8, 4]", Arrays.toString(ranges));
1167    }
1168   
 
1169  0 toggle @Test(groups = { "Functional" })
1170    public void testRangeContains()
1171    {
1172    /*
1173    * both forward ranges
1174    */
1175  0 assertTrue(
1176    MappingUtils.rangeContains(new int[]
1177    { 1, 10 }, new int[] { 1, 10 }));
1178  0 assertTrue(
1179    MappingUtils.rangeContains(new int[]
1180    { 1, 10 }, new int[] { 2, 10 }));
1181  0 assertTrue(
1182    MappingUtils.rangeContains(new int[]
1183    { 1, 10 }, new int[] { 1, 9 }));
1184  0 assertTrue(
1185    MappingUtils.rangeContains(new int[]
1186    { 1, 10 }, new int[] { 4, 5 }));
1187  0 assertFalse(
1188    MappingUtils.rangeContains(new int[]
1189    { 1, 10 }, new int[] { 0, 9 }));
1190  0 assertFalse(
1191    MappingUtils.rangeContains(new int[]
1192    { 1, 10 }, new int[] { -10, -9 }));
1193  0 assertFalse(
1194    MappingUtils.rangeContains(new int[]
1195    { 1, 10 }, new int[] { 1, 11 }));
1196  0 assertFalse(
1197    MappingUtils.rangeContains(new int[]
1198    { 1, 10 }, new int[] { 11, 12 }));
1199   
1200    /*
1201    * forward range, reverse query
1202    */
1203  0 assertTrue(
1204    MappingUtils.rangeContains(new int[]
1205    { 1, 10 }, new int[] { 10, 1 }));
1206  0 assertTrue(
1207    MappingUtils.rangeContains(new int[]
1208    { 1, 10 }, new int[] { 9, 1 }));
1209  0 assertTrue(
1210    MappingUtils.rangeContains(new int[]
1211    { 1, 10 }, new int[] { 10, 2 }));
1212  0 assertTrue(
1213    MappingUtils.rangeContains(new int[]
1214    { 1, 10 }, new int[] { 5, 5 }));
1215  0 assertFalse(
1216    MappingUtils.rangeContains(new int[]
1217    { 1, 10 }, new int[] { 11, 1 }));
1218  0 assertFalse(
1219    MappingUtils.rangeContains(new int[]
1220    { 1, 10 }, new int[] { 10, 0 }));
1221   
1222    /*
1223    * reverse range, forward query
1224    */
1225  0 assertTrue(
1226    MappingUtils.rangeContains(new int[]
1227    { 10, 1 }, new int[] { 1, 10 }));
1228  0 assertTrue(
1229    MappingUtils.rangeContains(new int[]
1230    { 10, 1 }, new int[] { 1, 9 }));
1231  0 assertTrue(
1232    MappingUtils.rangeContains(new int[]
1233    { 10, 1 }, new int[] { 2, 10 }));
1234  0 assertTrue(
1235    MappingUtils.rangeContains(new int[]
1236    { 10, 1 }, new int[] { 6, 6 }));
1237  0 assertFalse(
1238    MappingUtils.rangeContains(new int[]
1239    { 10, 1 }, new int[] { 6, 11 }));
1240  0 assertFalse(
1241    MappingUtils.rangeContains(new int[]
1242    { 10, 1 }, new int[] { 11, 20 }));
1243  0 assertFalse(
1244    MappingUtils.rangeContains(new int[]
1245    { 10, 1 }, new int[] { -3, -2 }));
1246   
1247    /*
1248    * both reverse
1249    */
1250  0 assertTrue(
1251    MappingUtils.rangeContains(new int[]
1252    { 10, 1 }, new int[] { 10, 1 }));
1253  0 assertTrue(
1254    MappingUtils.rangeContains(new int[]
1255    { 10, 1 }, new int[] { 9, 1 }));
1256  0 assertTrue(
1257    MappingUtils.rangeContains(new int[]
1258    { 10, 1 }, new int[] { 10, 2 }));
1259  0 assertTrue(
1260    MappingUtils.rangeContains(new int[]
1261    { 10, 1 }, new int[] { 3, 3 }));
1262  0 assertFalse(
1263    MappingUtils.rangeContains(new int[]
1264    { 10, 1 }, new int[] { 11, 1 }));
1265  0 assertFalse(
1266    MappingUtils.rangeContains(new int[]
1267    { 10, 1 }, new int[] { 10, 0 }));
1268  0 assertFalse(
1269    MappingUtils.rangeContains(new int[]
1270    { 10, 1 }, new int[] { 12, 11 }));
1271  0 assertFalse(
1272    MappingUtils.rangeContains(new int[]
1273    { 10, 1 }, new int[] { -5, -8 }));
1274   
1275    /*
1276    * bad arguments
1277    */
1278  0 assertFalse(
1279    MappingUtils.rangeContains(new int[]
1280    { 1, 10, 12 }, new int[] { 1, 10 }));
1281  0 assertFalse(
1282    MappingUtils.rangeContains(new int[]
1283    { 1, 10 }, new int[] { 1 }));
1284  0 assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, null));
1285  0 assertFalse(MappingUtils.rangeContains(null, new int[] { 1, 10 }));
1286    }
1287   
 
1288  0 toggle @Test(groups = "Functional")
1289    public void testRemoveEndPositions()
1290    {
1291  0 List<int[]> ranges = new ArrayList<>();
1292   
1293    /*
1294    * case 1: truncate last range
1295    */
1296  0 ranges.add(new int[] { 1, 10 });
1297  0 ranges.add(new int[] { 20, 30 });
1298  0 MappingUtils.removeEndPositions(5, ranges);
1299  0 assertEquals(2, ranges.size());
1300  0 assertEquals(25, ranges.get(1)[1]);
1301   
1302    /*
1303    * case 2: remove last range
1304    */
1305  0 ranges.clear();
1306  0 ranges.add(new int[] { 1, 10 });
1307  0 ranges.add(new int[] { 20, 22 });
1308  0 MappingUtils.removeEndPositions(3, ranges);
1309  0 assertEquals(1, ranges.size());
1310  0 assertEquals(10, ranges.get(0)[1]);
1311   
1312    /*
1313    * case 3: truncate penultimate range
1314    */
1315  0 ranges.clear();
1316  0 ranges.add(new int[] { 1, 10 });
1317  0 ranges.add(new int[] { 20, 21 });
1318  0 MappingUtils.removeEndPositions(3, ranges);
1319  0 assertEquals(1, ranges.size());
1320  0 assertEquals(9, ranges.get(0)[1]);
1321   
1322    /*
1323    * case 4: remove last two ranges
1324    */
1325  0 ranges.clear();
1326  0 ranges.add(new int[] { 1, 10 });
1327  0 ranges.add(new int[] { 20, 20 });
1328  0 ranges.add(new int[] { 30, 30 });
1329  0 MappingUtils.removeEndPositions(3, ranges);
1330  0 assertEquals(1, ranges.size());
1331  0 assertEquals(9, ranges.get(0)[1]);
1332    }
1333   
 
1334  0 toggle @Test(groups = "Functional")
1335    public void testFindOverlap()
1336    {
1337  0 List<int[]> ranges = new ArrayList<>();
1338  0 ranges.add(new int[] { 4, 8 });
1339  0 ranges.add(new int[] { 10, 12 });
1340  0 ranges.add(new int[] { 16, 19 });
1341   
1342  0 int[] overlap = MappingUtils.findOverlap(ranges, 5, 13);
1343  0 assertArrayEquals(overlap, new int[] { 5, 12 });
1344  0 overlap = MappingUtils.findOverlap(ranges, -100, 100);
1345  0 assertArrayEquals(overlap, new int[] { 4, 19 });
1346  0 overlap = MappingUtils.findOverlap(ranges, 7, 17);
1347  0 assertArrayEquals(overlap, new int[] { 7, 17 });
1348  0 overlap = MappingUtils.findOverlap(ranges, 13, 15);
1349  0 assertNull(overlap);
1350    }
1351   
1352    /**
1353    * Test mapping a sequence group where sequences in and outside the group
1354    * share a dataset sequence (e.g. alternative CDS for the same gene)
1355    * <p>
1356    * This scenario doesn't arise after JAL-3763 changes, but test left as still
1357    * valid
1358    *
1359    * @throws IOException
1360    */
 
1361  0 toggle @Test(groups = { "Functional" })
1362    public void testMapSequenceGroup_sharedDataset() throws IOException
1363    {
1364    /*
1365    * Set up dna and protein Seq1/2/3 with mappings (held on the protein
1366    * viewport). CDS sequences share the same 'gene' dataset sequence.
1367    */
1368  0 SequenceI dna = new Sequence("dna", "aaatttgggcccaaatttgggccc");
1369  0 SequenceI cds1 = new Sequence("cds1/1-6", "aaattt");
1370  0 SequenceI cds2 = new Sequence("cds1/4-9", "tttggg");
1371  0 SequenceI cds3 = new Sequence("cds1/19-24", "gggccc");
1372   
1373  0 cds1.setDatasetSequence(dna);
1374  0 cds2.setDatasetSequence(dna);
1375  0 cds3.setDatasetSequence(dna);
1376   
1377  0 SequenceI pep1 = new Sequence("pep1", "KF");
1378  0 SequenceI pep2 = new Sequence("pep2", "FG");
1379  0 SequenceI pep3 = new Sequence("pep3", "GP");
1380  0 pep1.createDatasetSequence();
1381  0 pep2.createDatasetSequence();
1382  0 pep3.createDatasetSequence();
1383   
1384    /*
1385    * add mappings from coding positions of dna to respective peptides
1386    */
1387  0 AlignedCodonFrame acf = new AlignedCodonFrame();
1388  0 acf.addMap(dna, pep1,
1389    new MapList(new int[]
1390    { 1, 6 }, new int[] { 1, 2 }, 3, 1));
1391  0 acf.addMap(dna, pep2,
1392    new MapList(new int[]
1393    { 4, 9 }, new int[] { 1, 2 }, 3, 1));
1394  0 acf.addMap(dna, pep3,
1395    new MapList(new int[]
1396    { 19, 24 }, new int[] { 1, 2 }, 3, 1));
1397   
1398  0 List<AlignedCodonFrame> acfList = Arrays
1399    .asList(new AlignedCodonFrame[]
1400    { acf });
1401   
1402  0 AlignmentI cdna = new Alignment(new SequenceI[] { cds1, cds2, cds3 });
1403  0 AlignmentI protein = new Alignment(
1404    new SequenceI[]
1405    { pep1, pep2, pep3 });
1406  0 AlignViewportI cdnaView = new AlignViewport(cdna);
1407  0 AlignViewportI peptideView = new AlignViewport(protein);
1408  0 protein.setCodonFrames(acfList);
1409   
1410    /*
1411    * Select pep1 and pep3 in the protein alignment
1412    */
1413  0 SequenceGroup sg = new SequenceGroup();
1414  0 sg.setColourText(true);
1415  0 sg.setIdColour(Color.GREEN);
1416  0 sg.setOutlineColour(Color.LIGHT_GRAY);
1417  0 sg.addSequence(pep1, false);
1418  0 sg.addSequence(pep3, false);
1419  0 sg.setEndRes(protein.getWidth() - 1);
1420   
1421    /*
1422    * Verify the mapped sequence group in dna is cds1 and cds3
1423    */
1424  0 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
1425    peptideView, cdnaView);
1426  0 assertTrue(mappedGroup.getColourText());
1427  0 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
1428  0 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
1429  0 assertEquals(2, mappedGroup.getSequences().size());
1430  0 assertSame(cds1, mappedGroup.getSequences().get(0));
1431  0 assertSame(cds3, mappedGroup.getSequences().get(1));
1432    // columns 1-6 selected (0-5 base zero)
1433  0 assertEquals(0, mappedGroup.getStartRes());
1434  0 assertEquals(5, mappedGroup.getEndRes());
1435   
1436    /*
1437    * Select mapping sequence group from dna to protein
1438    */
1439  0 sg.clear();
1440  0 sg.addSequence(cds2, false);
1441  0 sg.addSequence(cds1, false);
1442  0 sg.setStartRes(0);
1443  0 sg.setEndRes(cdna.getWidth() - 1);
1444  0 mappedGroup = MappingUtils.mapSequenceGroup(sg, cdnaView, peptideView);
1445  0 assertTrue(mappedGroup.getColourText());
1446  0 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
1447  0 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
1448  0 assertEquals(2, mappedGroup.getSequences().size());
1449  0 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
1450  0 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
1451  0 assertEquals(0, mappedGroup.getStartRes());
1452  0 assertEquals(1, mappedGroup.getEndRes()); // two columns
1453    }
1454   
1455    // new for 2.12
 
1456  0 toggle @Test(groups = "Functional")
1457    public void testAddRange()
1458    {
1459  0 int[] range = { 1, 5 };
1460  0 List<int[]> ranges = new ArrayList<>();
1461   
1462    // add to empty list:
1463  0 MappingUtils.addRange(range, ranges);
1464  0 assertEquals(1, ranges.size());
1465  0 assertSame(range, ranges.get(0));
1466   
1467    // extend contiguous (same position):
1468  0 MappingUtils.addRange(new int[] { 5, 10 }, ranges);
1469  0 assertEquals(1, ranges.size());
1470  0 assertEquals(1, ranges.get(0)[0]);
1471  0 assertEquals(10, ranges.get(0)[1]);
1472   
1473    // extend contiguous (next position):
1474  0 MappingUtils.addRange(new int[] { 11, 15 }, ranges);
1475  0 assertEquals(1, ranges.size());
1476  0 assertEquals(1, ranges.get(0)[0]);
1477  0 assertEquals(15, ranges.get(0)[1]);
1478   
1479    // change direction: range is not merged:
1480  0 MappingUtils.addRange(new int[] { 16, 10 }, ranges);
1481  0 assertEquals(2, ranges.size());
1482  0 assertEquals(16, ranges.get(1)[0]);
1483  0 assertEquals(10, ranges.get(1)[1]);
1484   
1485    // extend reverse contiguous (same position):
1486  0 MappingUtils.addRange(new int[] { 10, 8 }, ranges);
1487  0 assertEquals(2, ranges.size());
1488  0 assertEquals(16, ranges.get(1)[0]);
1489  0 assertEquals(8, ranges.get(1)[1]);
1490   
1491    // extend reverse contiguous (next position):
1492  0 MappingUtils.addRange(new int[] { 7, 6 }, ranges);
1493  0 assertEquals(2, ranges.size());
1494  0 assertEquals(16, ranges.get(1)[0]);
1495  0 assertEquals(6, ranges.get(1)[1]);
1496   
1497    // change direction: range is not merged:
1498  0 MappingUtils.addRange(new int[] { 6, 9 }, ranges);
1499  0 assertEquals(3, ranges.size());
1500  0 assertEquals(6, ranges.get(2)[0]);
1501  0 assertEquals(9, ranges.get(2)[1]);
1502   
1503    // not contiguous: not merged
1504  0 MappingUtils.addRange(new int[] { 11, 12 }, ranges);
1505  0 assertEquals(4, ranges.size());
1506  0 assertEquals(11, ranges.get(3)[0]);
1507  0 assertEquals(12, ranges.get(3)[1]);
1508    }
1509    }