Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 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
1.0100%
 

Contributing tests

This file is covered by 23 tests. .

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  1 toggle @BeforeClass(alwaysRun = true)
66    public void setUp()
67    {
68  1 Console.initLogger();
69    }
70   
 
71  1 toggle @BeforeClass(alwaysRun = true)
72    public void setUpJvOptionPane()
73    {
74  1 JvOptionPane.setInteractiveMode(false);
75  1 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  1 toggle @Test(groups = { "Functional" })
86    public void testBuildSearchResults()
87    {
88  1 final Sequence seq1 = new Sequence("Seq1/5-10", "C-G-TA-GC");
89  1 seq1.createDatasetSequence();
90   
91  1 final Sequence aseq1 = new Sequence("Seq1/12-13", "-P-R");
92  1 aseq1.createDatasetSequence();
93   
94    /*
95    * Map dna bases 5-10 to protein residues 12-13
96    */
97  1 AlignedCodonFrame acf = new AlignedCodonFrame();
98  1 MapList map = new MapList(new int[] { 5, 10 }, new int[] { 12, 13 }, 3,
99    1);
100  1 acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
101  1 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  1 SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 12, acfList);
109  1 assertEquals(1, sr.getResults().size());
110  1 SearchResultMatchI m = sr.getResults().get(0);
111  1 assertEquals(seq1.getDatasetSequence(), m.getSequence());
112  1 assertEquals(5, m.getStart());
113  1 assertEquals(7, m.getEnd());
114  1 sr = MappingUtils.buildSearchResults(aseq1, 13, acfList);
115  1 assertEquals(1, sr.getResults().size());
116  1 m = sr.getResults().get(0);
117  1 assertEquals(seq1.getDatasetSequence(), m.getSequence());
118  1 assertEquals(8, m.getStart());
119  1 assertEquals(10, m.getEnd());
120   
121    /*
122    * Check inverse mappings, from codons 5-7, 8-10 to protein 12, 13
123    */
124  7 for (int i = 5; i < 11; i++)
125    {
126  6 sr = MappingUtils.buildSearchResults(seq1, i, acfList);
127  6 assertEquals(1, sr.getResults().size());
128  6 m = sr.getResults().get(0);
129  6 assertEquals(aseq1.getDatasetSequence(), m.getSequence());
130  6 int residue = i > 7 ? 13 : 12;
131  6 assertEquals(residue, m.getStart());
132  6 assertEquals(residue, m.getEnd());
133    }
134    }
135   
136    /**
137    * Simple test of mapping with introns involved.
138    */
 
139  1 toggle @Test(groups = { "Functional" })
140    public void testBuildSearchResults_withIntron()
141    {
142  1 final Sequence seq1 = new Sequence("Seq1/5-17", "c-G-tAGa-GcAgCtt");
143  1 seq1.createDatasetSequence();
144   
145  1 final Sequence aseq1 = new Sequence("Seq1/8-9", "-E-D");
146  1 aseq1.createDatasetSequence();
147   
148    /*
149    * Map dna bases [6, 8, 9], [11, 13, 115] to protein residues 8 and 9
150    */
151  1 AlignedCodonFrame acf = new AlignedCodonFrame();
152  1 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  1 acf.addMap(seq1.getDatasetSequence(), aseq1.getDatasetSequence(), map);
157  1 List<AlignedCodonFrame> acfList = Arrays
158    .asList(new AlignedCodonFrame[]
159    { acf });
160   
161    /*
162    * Check protein residue 8 maps to [6, 8, 9]
163    */
164  1 SearchResultsI sr = MappingUtils.buildSearchResults(aseq1, 8, acfList);
165  1 assertEquals(2, sr.getResults().size());
166  1 SearchResultMatchI m = sr.getResults().get(0);
167  1 assertEquals(seq1.getDatasetSequence(), m.getSequence());
168  1 assertEquals(6, m.getStart());
169  1 assertEquals(6, m.getEnd());
170  1 m = sr.getResults().get(1);
171  1 assertEquals(seq1.getDatasetSequence(), m.getSequence());
172  1 assertEquals(8, m.getStart());
173  1 assertEquals(9, m.getEnd());
174   
175    /*
176    * Check protein residue 9 maps to [11, 13, 15]
177    */
178  1 sr = MappingUtils.buildSearchResults(aseq1, 9, acfList);
179  1 assertEquals(3, sr.getResults().size());
180  1 m = sr.getResults().get(0);
181  1 assertEquals(seq1.getDatasetSequence(), m.getSequence());
182  1 assertEquals(11, m.getStart());
183  1 assertEquals(11, m.getEnd());
184  1 m = sr.getResults().get(1);
185  1 assertEquals(seq1.getDatasetSequence(), m.getSequence());
186  1 assertEquals(13, m.getStart());
187  1 assertEquals(13, m.getEnd());
188  1 m = sr.getResults().get(2);
189  1 assertEquals(seq1.getDatasetSequence(), m.getSequence());
190  1 assertEquals(15, m.getStart());
191  1 assertEquals(15, m.getEnd());
192   
193    /*
194    * Check inverse mappings, from codons to protein
195    */
196  14 for (int i = 5; i < 18; i++)
197    {
198  13 sr = MappingUtils.buildSearchResults(seq1, i, acfList);
199  13 int residue = (i == 6 || i == 8 || i == 9) ? 8
200  10 : (i == 11 || i == 13 || i == 15 ? 9 : 0);
201  13 if (residue == 0)
202    {
203  7 assertEquals(0, sr.getResults().size());
204  7 continue;
205    }
206  6 assertEquals(1, sr.getResults().size());
207  6 m = sr.getResults().get(0);
208  6 assertEquals(aseq1.getDatasetSequence(), m.getSequence());
209  6 assertEquals(residue, m.getStart());
210  6 assertEquals(residue, m.getEnd());
211    }
212    }
213   
214    /**
215    * Test mapping a sequence group made of entire sequences.
216    *
217    * @throws IOException
218    */
 
219  1 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  1 AlignmentI cdna = loadAlignment(">Seq1\nACG\n>Seq2\nTGA\n>Seq3\nTAC\n",
227    FileFormat.Fasta);
228  1 cdna.setDataset(null);
229  1 AlignmentI protein = loadAlignment(">Seq1\nK\n>Seq2\nL\n>Seq3\nQ\n",
230    FileFormat.Fasta);
231  1 protein.setDataset(null);
232  1 AlignedCodonFrame acf = new AlignedCodonFrame();
233  1 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 3, 1);
234  4 for (int seq = 0; seq < 3; seq++)
235    {
236  3 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
237    protein.getSequenceAt(seq).getDatasetSequence(), map);
238    }
239  1 List<AlignedCodonFrame> acfList = Arrays
240    .asList(new AlignedCodonFrame[]
241    { acf });
242   
243  1 AlignViewportI dnaView = new AlignViewport(cdna);
244  1 AlignViewportI proteinView = new AlignViewport(protein);
245  1 protein.setCodonFrames(acfList);
246   
247    /*
248    * Select Seq1 and Seq3 in the protein
249    */
250  1 SequenceGroup sg = new SequenceGroup();
251  1 sg.setColourText(true);
252  1 sg.setIdColour(Color.GREEN);
253  1 sg.setOutlineColour(Color.LIGHT_GRAY);
254  1 sg.addSequence(protein.getSequenceAt(0), false);
255  1 sg.addSequence(protein.getSequenceAt(2), false);
256  1 sg.setEndRes(protein.getWidth() - 1);
257   
258    /*
259    * Verify the mapped sequence group in dna
260    */
261  1 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
262    proteinView, dnaView);
263  1 assertTrue(mappedGroup.getColourText());
264  1 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
265  1 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
266  1 assertEquals(2, mappedGroup.getSequences().size());
267  1 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
268  1 assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(1));
269  1 assertEquals(0, mappedGroup.getStartRes());
270  1 assertEquals(2, mappedGroup.getEndRes()); // 3 columns (1 codon)
271   
272    /*
273    * Verify mapping sequence group from dna to protein
274    */
275  1 sg.clear();
276  1 sg.addSequence(cdna.getSequenceAt(1), false);
277  1 sg.addSequence(cdna.getSequenceAt(0), false);
278  1 sg.setStartRes(0);
279  1 sg.setEndRes(2);
280  1 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
281  1 assertTrue(mappedGroup.getColourText());
282  1 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
283  1 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
284  1 assertEquals(2, mappedGroup.getSequences().size());
285  1 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
286  1 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
287  1 assertEquals(0, mappedGroup.getStartRes());
288  1 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  14 toggle protected AlignmentI loadAlignment(final String data, FileFormatI format)
301    throws IOException
302    {
303  14 AlignmentI a = new FormatAdapter().readFile(data, DataSourceType.PASTE,
304    format);
305  14 a.setDataset(null);
306  14 return a;
307    }
308   
309    /**
310    * Test mapping a column selection in protein to its dna equivalent
311    *
312    * @throws IOException
313    */
 
314  1 toggle @Test(groups = { "Functional" })
315    public void testMapColumnSelection_proteinToDna() throws IOException
316    {
317  1 setupMappedAlignments();
318   
319  1 ColumnSelection colsel = new ColumnSelection();
320  1 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  1 colsel.addElement(0);
327  1 ColumnSelection cs = new ColumnSelection();
328  1 HiddenColumns hs = new HiddenColumns();
329  1 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
330    cs, hs);
331  1 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  1 cs.clear();
337  1 colsel.clear();
338  1 colsel.addElement(1);
339  1 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
340    cs, hs);
341  1 assertEquals("[0, 1, 2, 3]", cs.getSelected().toString());
342   
343    /*
344    * Column 2 in protein picks up gaps only - no mapping
345    */
346  1 cs.clear();
347  1 colsel.clear();
348  1 colsel.addElement(2);
349  1 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
350    cs, hs);
351  1 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  1 cs.clear();
358  1 colsel.clear();
359  1 colsel.addElement(3);
360  1 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
361    cs, hs);
362  1 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  1 cs.clear();
369  1 colsel.clear();
370  1 colsel.addElement(1);
371  1 colsel.addElement(3);
372  1 MappingUtils.mapColumnSelection(colsel, hidden, proteinView, dnaView,
373    cs, hs);
374  1 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  4 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  4 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  4 cdna.setDataset(null);
396  4 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  4 protein.setDataset(null);
400   
401    // map first dna to first protein seq
402  4 AlignedCodonFrame acf = new AlignedCodonFrame();
403  4 MapList map = new MapList(new int[] { 10, 12, 15, 15, 17, 18 },
404    new int[]
405    { 40, 41 }, 3, 1);
406  4 acf.addMap(cdna.getSequenceAt(0).getDatasetSequence(),
407    protein.getSequenceAt(0).getDatasetSequence(), map);
408   
409    // map second dna to second protein seq
410  4 map = new MapList(new int[] { 20, 20, 22, 23, 24, 26 },
411    new int[]
412    { 50, 51 }, 3, 1);
413  4 acf.addMap(cdna.getSequenceAt(1).getDatasetSequence(),
414    protein.getSequenceAt(1).getDatasetSequence(), map);
415   
416    // map third dna to third protein seq
417  4 map = new MapList(new int[] { 30, 30, 32, 34, 36, 37 },
418    new int[]
419    { 60, 61 }, 3, 1);
420  4 acf.addMap(cdna.getSequenceAt(2).getDatasetSequence(),
421    protein.getSequenceAt(2).getDatasetSequence(), map);
422  4 List<AlignedCodonFrame> acfList = Arrays
423    .asList(new AlignedCodonFrame[]
424    { acf });
425   
426  4 dnaView = new AlignViewport(cdna);
427  4 proteinView = new AlignViewport(protein);
428  4 protein.setCodonFrames(acfList);
429    }
430   
431    /**
432    * Test mapping a column selection in dna to its protein equivalent
433    *
434    * @throws IOException
435    */
 
436  1 toggle @Test(groups = { "Functional" })
437    public void testMapColumnSelection_dnaToProtein() throws IOException
438    {
439  1 setupMappedAlignments();
440   
441  1 ColumnSelection colsel = new ColumnSelection();
442  1 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  1 ColumnSelection cs = new ColumnSelection();
449  1 HiddenColumns hs = new HiddenColumns();
450  1 colsel.addElement(0);
451  1 MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
452    cs, hs);
453  1 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  1 colsel.addElement(3);
460  1 colsel.addElement(4);
461  1 colsel.addElement(5);
462  1 cs.clear();
463  1 MappingUtils.mapColumnSelection(colsel, hidden, dnaView, proteinView,
464    cs, hs);
465  1 assertEquals("[0, 1, 3]", cs.getSelected().toString());
466    }
467   
 
468  1 toggle @Test(groups = { "Functional" })
469    public void testMapColumnSelection_null() throws IOException
470    {
471  1 setupMappedAlignments();
472  1 ColumnSelection cs = new ColumnSelection();
473  1 HiddenColumns hs = new HiddenColumns();
474  1 MappingUtils.mapColumnSelection(null, null, dnaView, proteinView, cs,
475    hs);
476  1 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  1 toggle @Test(groups = { "Functional" })
484    public void testFlattenRanges()
485    {
486  1 assertEquals("[1, 2, 3, 4]",
487    Arrays.toString(MappingUtils.flattenRanges(new int[]
488    { 1, 4 })));
489  1 assertEquals("[1, 2, 3, 4]",
490    Arrays.toString(MappingUtils.flattenRanges(new int[]
491    { 1, 2, 3, 4 })));
492  1 assertEquals("[1, 2, 3, 4]",
493    Arrays.toString(MappingUtils.flattenRanges(new int[]
494    { 1, 1, 2, 2, 3, 3, 4, 4 })));
495  1 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  1 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  1 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  1 AlignmentI cdna = loadAlignment(
517    ">Seq1\nACGGCA\n>Seq2\nTGACAG\n>Seq3\nTACGTA\n",
518    FileFormat.Fasta);
519  1 cdna.setDataset(null);
520  1 AlignmentI protein = loadAlignment(">Seq1\nKA\n>Seq2\nLQ\n>Seq3\nQV\n",
521    FileFormat.Fasta);
522  1 protein.setDataset(null);
523  1 AlignedCodonFrame acf = new AlignedCodonFrame();
524  1 MapList map = new MapList(new int[] { 1, 6 }, new int[] { 1, 2 }, 3, 1);
525  4 for (int seq = 0; seq < 3; seq++)
526    {
527  3 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
528    protein.getSequenceAt(seq).getDatasetSequence(), map);
529    }
530  1 List<AlignedCodonFrame> acfList = Arrays
531    .asList(new AlignedCodonFrame[]
532    { acf });
533   
534  1 AlignViewportI dnaView = new AlignViewport(cdna);
535  1 AlignViewportI proteinView = new AlignViewport(protein);
536  1 protein.setCodonFrames(acfList);
537   
538    /*
539    * Select all sequences, column 2 in the protein
540    */
541  1 SequenceGroup sg = new SequenceGroup();
542  1 sg.setColourText(true);
543  1 sg.setIdColour(Color.GREEN);
544  1 sg.setOutlineColour(Color.LIGHT_GRAY);
545  1 sg.addSequence(protein.getSequenceAt(0), false);
546  1 sg.addSequence(protein.getSequenceAt(1), false);
547  1 sg.addSequence(protein.getSequenceAt(2), false);
548  1 sg.setStartRes(1);
549  1 sg.setEndRes(1);
550   
551    /*
552    * Verify the mapped sequence group in dna
553    */
554  1 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
555    proteinView, dnaView);
556  1 assertTrue(mappedGroup.getColourText());
557  1 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
558  1 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
559  1 assertEquals(3, mappedGroup.getSequences().size());
560  1 assertSame(cdna.getSequenceAt(0), mappedGroup.getSequences().get(0));
561  1 assertSame(cdna.getSequenceAt(1), mappedGroup.getSequences().get(1));
562  1 assertSame(cdna.getSequenceAt(2), mappedGroup.getSequences().get(2));
563  1 assertEquals(3, mappedGroup.getStartRes());
564  1 assertEquals(5, mappedGroup.getEndRes());
565   
566    /*
567    * Verify mapping sequence group from dna to protein
568    */
569  1 sg.clear();
570  1 sg.addSequence(cdna.getSequenceAt(0), false);
571  1 sg.addSequence(cdna.getSequenceAt(1), false);
572  1 sg.addSequence(cdna.getSequenceAt(2), false);
573    // select columns 2 and 3 in DNA which span protein columns 0 and 1
574  1 sg.setStartRes(2);
575  1 sg.setEndRes(3);
576  1 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
577  1 assertTrue(mappedGroup.getColourText());
578  1 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
579  1 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
580  1 assertEquals(3, mappedGroup.getSequences().size());
581  1 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(0));
582  1 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(1));
583  1 assertSame(protein.getSequenceAt(2), mappedGroup.getSequences().get(2));
584  1 assertEquals(0, mappedGroup.getStartRes());
585  1 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  1 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  1 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  1 cdna.setDataset(null);
604  1 AlignmentI protein = loadAlignment(
605    ">Seq1\n-KA-S\n>Seq2\n--L-QY\n>Seq3\nQ-V-M\n",
606    FileFormat.Fasta);
607  1 protein.setDataset(null);
608  1 AlignedCodonFrame acf = new AlignedCodonFrame();
609  1 MapList map = new MapList(new int[] { 1, 9 }, new int[] { 1, 3 }, 3, 1);
610  4 for (int seq = 0; seq < 3; seq++)
611    {
612  3 acf.addMap(cdna.getSequenceAt(seq).getDatasetSequence(),
613    protein.getSequenceAt(seq).getDatasetSequence(), map);
614    }
615  1 List<AlignedCodonFrame> acfList = Arrays
616    .asList(new AlignedCodonFrame[]
617    { acf });
618   
619  1 AlignViewportI dnaView = new AlignViewport(cdna);
620  1 AlignViewportI proteinView = new AlignViewport(protein);
621  1 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  1 SequenceGroup sg = new SequenceGroup();
630  1 sg.setColourText(true);
631  1 sg.setIdColour(Color.GREEN);
632  1 sg.setOutlineColour(Color.LIGHT_GRAY);
633  1 sg.addSequence(protein.getSequenceAt(0), false);
634  1 sg.addSequence(protein.getSequenceAt(1), false);
635  1 sg.setStartRes(1);
636  1 sg.setEndRes(1);
637   
638    /*
639    * Verify the mapped sequence group in dna
640    */
641  1 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
642    proteinView, dnaView);
643  1 assertTrue(mappedGroup.getColourText());
644  1 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
645  1 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
646  1 assertEquals(1, mappedGroup.getSequences().size());
647  1 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  1 assertEquals(0, mappedGroup.getStartRes());
651  1 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  1 sg.setStartRes(2);
658  1 sg.setEndRes(4);
659  1 mappedGroup = MappingUtils.mapSequenceGroup(sg, proteinView, dnaView);
660  1 assertEquals(1, mappedGroup.getStartRes());
661  1 assertEquals(13, mappedGroup.getEndRes());
662   
663    /*
664    * Verify mapping sequence group from dna to protein
665    */
666  1 sg.clear();
667  1 sg.addSequence(cdna.getSequenceAt(0), false);
668   
669    // select columns 4,5 - includes Seq1:codon2 (A) only
670  1 sg.setStartRes(4);
671  1 sg.setEndRes(5);
672  1 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
673  1 assertEquals(2, mappedGroup.getStartRes());
674  1 assertEquals(2, mappedGroup.getEndRes());
675   
676    // add Seq2 to dna selection cols 4-5 include codons 1 and 2 (LQ)
677  1 sg.addSequence(cdna.getSequenceAt(1), false);
678  1 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
679  1 assertEquals(2, mappedGroup.getStartRes());
680  1 assertEquals(4, mappedGroup.getEndRes());
681   
682    // add Seq3 to dna selection cols 4-5 include codon 1 (Q)
683  1 sg.addSequence(cdna.getSequenceAt(2), false);
684  1 mappedGroup = MappingUtils.mapSequenceGroup(sg, dnaView, proteinView);
685  1 assertEquals(0, mappedGroup.getStartRes());
686  1 assertEquals(4, mappedGroup.getEndRes());
687    }
688   
 
689  1 toggle @Test(groups = { "Functional" })
690    public void testFindMappingsForSequence()
691    {
692  1 SequenceI seq1 = new Sequence("Seq1", "ABC");
693  1 SequenceI seq2 = new Sequence("Seq2", "ABC");
694  1 SequenceI seq3 = new Sequence("Seq3", "ABC");
695  1 SequenceI seq4 = new Sequence("Seq4", "ABC");
696  1 seq1.createDatasetSequence();
697  1 seq2.createDatasetSequence();
698  1 seq3.createDatasetSequence();
699  1 seq4.createDatasetSequence();
700   
701    /*
702    * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1
703    */
704  1 AlignedCodonFrame acf1 = new AlignedCodonFrame();
705  1 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
706  1 acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
707  1 AlignedCodonFrame acf2 = new AlignedCodonFrame();
708  1 acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
709  1 AlignedCodonFrame acf3 = new AlignedCodonFrame();
710  1 acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
711   
712  1 List<AlignedCodonFrame> mappings = new ArrayList<>();
713  1 mappings.add(acf1);
714  1 mappings.add(acf2);
715  1 mappings.add(acf3);
716   
717    /*
718    * Seq1 has three mappings
719    */
720  1 List<AlignedCodonFrame> result = MappingUtils
721    .findMappingsForSequence(seq1, mappings);
722  1 assertEquals(3, result.size());
723  1 assertTrue(result.contains(acf1));
724  1 assertTrue(result.contains(acf2));
725  1 assertTrue(result.contains(acf3));
726   
727    /*
728    * Seq2 has two mappings
729    */
730  1 result = MappingUtils.findMappingsForSequence(seq2, mappings);
731  1 assertEquals(2, result.size());
732  1 assertTrue(result.contains(acf1));
733  1 assertTrue(result.contains(acf2));
734   
735    /*
736    * Seq3 has one mapping
737    */
738  1 result = MappingUtils.findMappingsForSequence(seq3, mappings);
739  1 assertEquals(1, result.size());
740  1 assertTrue(result.contains(acf3));
741   
742    /*
743    * Seq4 has no mappings
744    */
745  1 result = MappingUtils.findMappingsForSequence(seq4, mappings);
746  1 assertEquals(0, result.size());
747   
748  1 result = MappingUtils.findMappingsForSequence(null, mappings);
749  1 assertEquals(0, result.size());
750   
751  1 result = MappingUtils.findMappingsForSequence(seq1, null);
752  1 assertEquals(0, result.size());
753   
754  1 result = MappingUtils.findMappingsForSequence(null, null);
755  1 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  1 toggle @Test(groups = { "Functional" })
763    public void testFindMappingsForSequenceAndOthers()
764    {
765  1 SequenceI seq1 = new Sequence("Seq1", "ABC");
766  1 SequenceI seq2 = new Sequence("Seq2", "ABC");
767  1 SequenceI seq3 = new Sequence("Seq3", "ABC");
768  1 SequenceI seq4 = new Sequence("Seq4", "ABC");
769  1 seq1.createDatasetSequence();
770  1 seq2.createDatasetSequence();
771  1 seq3.createDatasetSequence();
772  1 seq4.createDatasetSequence();
773   
774    /*
775    * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1, seq3 to seq4
776    */
777  1 AlignedCodonFrame acf1 = new AlignedCodonFrame();
778  1 MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1);
779  1 acf1.addMap(seq1.getDatasetSequence(), seq2.getDatasetSequence(), map);
780  1 AlignedCodonFrame acf2 = new AlignedCodonFrame();
781  1 acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map);
782  1 AlignedCodonFrame acf3 = new AlignedCodonFrame();
783  1 acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map);
784  1 AlignedCodonFrame acf4 = new AlignedCodonFrame();
785  1 acf4.addMap(seq3.getDatasetSequence(), seq4.getDatasetSequence(), map);
786   
787  1 List<AlignedCodonFrame> mappings = new ArrayList<>();
788  1 mappings.add(acf1);
789  1 mappings.add(acf2);
790  1 mappings.add(acf3);
791  1 mappings.add(acf4);
792   
793    /*
794    * test for null args
795    */
796  1 List<AlignedCodonFrame> result = MappingUtils
797    .findMappingsForSequenceAndOthers(null, mappings,
798    Arrays.asList(new SequenceI[]
799    { seq1, seq2 }));
800  1 assertTrue(result.isEmpty());
801   
802  1 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, null,
803    Arrays.asList(new SequenceI[]
804    { seq1, seq2 }));
805  1 assertTrue(result.isEmpty());
806   
807    /*
808    * Seq1 has three mappings, but filter argument will only accept
809    * those to seq2
810    */
811  1 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
812    Arrays.asList(new SequenceI[]
813    { seq1, seq2, seq1.getDatasetSequence() }));
814  1 assertEquals(2, result.size());
815  1 assertTrue(result.contains(acf1));
816  1 assertTrue(result.contains(acf2));
817  1 assertFalse("Did not expect to find mapping acf3 - subselect failed",
818    result.contains(acf3));
819  1 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  1 result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings,
827    null);
828  1 assertEquals(3, result.size());
829  1 assertTrue(result.contains(acf1));
830  1 assertTrue(result.contains(acf2));
831  1 assertTrue(result.contains(acf3));
832    }
833   
 
834  1 toggle @Test(groups = { "Functional" })
835    public void testMapEditCommand()
836    {
837  1 SequenceI dna = new Sequence("Seq1", "---ACG---GCATCA", 8, 16);
838  1 SequenceI protein = new Sequence("Seq2", "-T-AS", 5, 7);
839  1 dna.createDatasetSequence();
840  1 protein.createDatasetSequence();
841  1 AlignedCodonFrame acf = new AlignedCodonFrame();
842  1 MapList map = new MapList(new int[] { 8, 16 }, new int[] { 5, 7 }, 3,
843    1);
844  1 acf.addMap(dna.getDatasetSequence(), protein.getDatasetSequence(), map);
845  1 List<AlignedCodonFrame> mappings = new ArrayList<>();
846  1 mappings.add(acf);
847   
848  1 AlignmentI prot = new Alignment(new SequenceI[] { protein });
849  1 prot.setCodonFrames(mappings);
850  1 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  1 EditCommand ec = new EditCommand();
857  1 final Edit edit = ec.new Edit(Action.INSERT_GAP,
858    new SequenceI[]
859    { protein }, 4, 2, '-');
860  1 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  1 EditCommand mappedEdit = MappingUtils.mapEditCommand(ec, false, nuc,
867    '-', mappings);
868  1 assertEquals(1, mappedEdit.getEdits().size());
869  1 Edit e = mappedEdit.getEdits().get(0);
870  1 assertEquals(1, e.getSequences().length);
871  1 assertEquals(dna, e.getSequences()[0]);
872  1 assertEquals(12, e.getPosition());
873  1 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  1 toggle @Test(groups = { "Functional" })
882    public void testFlattenRanges_reverseStrand()
883    {
884  1 assertEquals("[4, 3, 2, 1]",
885    Arrays.toString(MappingUtils.flattenRanges(new int[]
886    { 4, 1 })));
887  1 assertEquals("[4, 3, 2, 1]",
888    Arrays.toString(MappingUtils.flattenRanges(new int[]
889    { 4, 3, 2, 1 })));
890  1 assertEquals("[4, 3, 2, 1]",
891    Arrays.toString(MappingUtils.flattenRanges(new int[]
892    { 4, 4, 3, 3, 2, 2, 1, 1 })));
893  1 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  1 assertEquals("[4, 5, 6, 3, 2, 1]",
898    Arrays.toString(MappingUtils.flattenRanges(new int[]
899    { 4, 6, 3, 1 })));
900    // backwards and forwards
901  1 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  1 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  1 toggle @Test(groups = { "Functional" })
916    public void testMapColumnSelection_hiddenColumns() throws IOException
917    {
918  1 setupMappedAlignments();
919   
920  1 ColumnSelection proteinSelection = new ColumnSelection();
921  1 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  1 proteinSelection.hideSelectedColumns(0, hiddenCols);
928  1 ColumnSelection dnaSelection = new ColumnSelection();
929  1 HiddenColumns dnaHidden = new HiddenColumns();
930  1 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
931    proteinView, dnaView, dnaSelection, dnaHidden);
932  1 assertEquals("[]", dnaSelection.getSelected().toString());
933  1 Iterator<int[]> regions = dnaHidden.iterator();
934  1 assertEquals(1, dnaHidden.getNumberOfRegions());
935  1 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  1 dnaSelection = new ColumnSelection();
941  1 dnaHidden = new HiddenColumns();
942  1 hiddenCols.revealAllHiddenColumns(proteinSelection);
943    // the unhidden columns are now marked selected!
944  1 assertEquals("[0]", proteinSelection.getSelected().toString());
945    // deselect these or hideColumns will be expanded to include 0
946  1 proteinSelection.clear();
947  1 proteinSelection.hideSelectedColumns(1, hiddenCols);
948  1 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
949    proteinView, dnaView, dnaSelection, dnaHidden);
950  1 regions = dnaHidden.iterator();
951  1 assertEquals(1, dnaHidden.getNumberOfRegions());
952  1 assertEquals("[0, 3]", Arrays.toString(regions.next()));
953   
954    /*
955    * Column 2 in protein picks up gaps only - no mapping
956    */
957  1 dnaSelection = new ColumnSelection();
958  1 dnaHidden = new HiddenColumns();
959  1 hiddenCols.revealAllHiddenColumns(proteinSelection);
960  1 proteinSelection.clear();
961  1 proteinSelection.hideSelectedColumns(2, hiddenCols);
962  1 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
963    proteinView, dnaView, dnaSelection, dnaHidden);
964  1 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  1 dnaSelection = new ColumnSelection();
971  1 dnaHidden = new HiddenColumns();
972  1 hiddenCols.revealAllHiddenColumns(proteinSelection);
973  1 proteinSelection.clear();
974  1 proteinSelection.hideSelectedColumns(3, hiddenCols); // 5-10 hidden in dna
975  1 proteinSelection.addElement(1); // 0-3 selected in dna
976  1 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
977    proteinView, dnaView, dnaSelection, dnaHidden);
978  1 assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString());
979  1 regions = dnaHidden.iterator();
980  1 assertEquals(1, dnaHidden.getNumberOfRegions());
981  1 assertEquals("[5, 10]", Arrays.toString(regions.next()));
982   
983    /*
984    * Combine hiding columns 1 and 3 to get discontiguous hidden columns
985    */
986  1 dnaSelection = new ColumnSelection();
987  1 dnaHidden = new HiddenColumns();
988  1 hiddenCols.revealAllHiddenColumns(proteinSelection);
989  1 proteinSelection.clear();
990  1 proteinSelection.hideSelectedColumns(1, hiddenCols);
991  1 proteinSelection.hideSelectedColumns(3, hiddenCols);
992  1 MappingUtils.mapColumnSelection(proteinSelection, hiddenCols,
993    proteinView, dnaView, dnaSelection, dnaHidden);
994  1 regions = dnaHidden.iterator();
995  1 assertEquals(2, dnaHidden.getNumberOfRegions());
996  1 assertEquals("[0, 3]", Arrays.toString(regions.next()));
997  1 assertEquals("[5, 10]", Arrays.toString(regions.next()));
998    }
999   
 
1000  1 toggle @Test(groups = { "Functional" })
1001    public void testGetLength()
1002    {
1003  1 assertEquals(0, MappingUtils.getLength(null));
1004   
1005    /*
1006    * [start, end] ranges
1007    */
1008  1 List<int[]> ranges = new ArrayList<>();
1009  1 assertEquals(0, MappingUtils.getLength(ranges));
1010  1 ranges.add(new int[] { 1, 1 });
1011  1 assertEquals(1, MappingUtils.getLength(ranges));
1012  1 ranges.add(new int[] { 2, 10 });
1013  1 assertEquals(10, MappingUtils.getLength(ranges));
1014  1 ranges.add(new int[] { 20, 10 });
1015  1 assertEquals(21, MappingUtils.getLength(ranges));
1016   
1017    /*
1018    * [start, end, start, end...] ranges
1019    */
1020  1 ranges.clear();
1021  1 ranges.add(new int[] { 1, 5, 8, 4 });
1022  1 ranges.add(new int[] { 8, 2 });
1023  1 ranges.add(new int[] { 12, 12 });
1024  1 assertEquals(18, MappingUtils.getLength(ranges));
1025    }
1026   
 
1027  1 toggle @Test(groups = { "Functional" })
1028    public void testContains()
1029    {
1030  1 assertFalse(MappingUtils.contains(null, 1));
1031  1 List<int[]> ranges = new ArrayList<>();
1032  1 assertFalse(MappingUtils.contains(ranges, 1));
1033   
1034  1 ranges.add(new int[] { 1, 4 });
1035  1 ranges.add(new int[] { 6, 6 });
1036  1 ranges.add(new int[] { 8, 10 });
1037  1 ranges.add(new int[] { 30, 20 });
1038  1 ranges.add(new int[] { -16, -44 });
1039   
1040  1 assertFalse(MappingUtils.contains(ranges, 0));
1041  1 assertTrue(MappingUtils.contains(ranges, 1));
1042  1 assertTrue(MappingUtils.contains(ranges, 2));
1043  1 assertTrue(MappingUtils.contains(ranges, 3));
1044  1 assertTrue(MappingUtils.contains(ranges, 4));
1045  1 assertFalse(MappingUtils.contains(ranges, 5));
1046   
1047  1 assertTrue(MappingUtils.contains(ranges, 6));
1048  1 assertFalse(MappingUtils.contains(ranges, 7));
1049   
1050  1 assertTrue(MappingUtils.contains(ranges, 8));
1051  1 assertTrue(MappingUtils.contains(ranges, 9));
1052  1 assertTrue(MappingUtils.contains(ranges, 10));
1053   
1054  1 assertFalse(MappingUtils.contains(ranges, 31));
1055  1 assertTrue(MappingUtils.contains(ranges, 30));
1056  1 assertTrue(MappingUtils.contains(ranges, 29));
1057  1 assertTrue(MappingUtils.contains(ranges, 20));
1058  1 assertFalse(MappingUtils.contains(ranges, 19));
1059   
1060  1 assertFalse(MappingUtils.contains(ranges, -15));
1061  1 assertTrue(MappingUtils.contains(ranges, -16));
1062  1 assertTrue(MappingUtils.contains(ranges, -44));
1063  1 assertFalse(MappingUtils.contains(ranges, -45));
1064    }
1065   
1066    /**
1067    * Test the method that drops positions from the start of a mapped range
1068    */
 
1069  1 toggle @Test(groups = "Functional")
1070    public void testRemoveStartPositions()
1071    {
1072  1 int[] ranges = new int[] { 1, 10 };
1073  1 int[] adjusted = MappingUtils.removeStartPositions(0, ranges);
1074  1 assertEquals("[1, 10]", Arrays.toString(adjusted));
1075   
1076  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1077  1 assertEquals("[2, 10]", Arrays.toString(adjusted));
1078  1 assertEquals("[1, 10]", Arrays.toString(ranges));
1079   
1080  1 ranges = adjusted;
1081  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1082  1 assertEquals("[3, 10]", Arrays.toString(adjusted));
1083  1 assertEquals("[2, 10]", Arrays.toString(ranges));
1084   
1085  1 ranges = new int[] { 2, 3, 10, 12 };
1086  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1087  1 assertEquals("[3, 3, 10, 12]", Arrays.toString(adjusted));
1088  1 assertEquals("[2, 3, 10, 12]", Arrays.toString(ranges));
1089   
1090  1 ranges = new int[] { 2, 2, 8, 12 };
1091  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1092  1 assertEquals("[8, 12]", Arrays.toString(adjusted));
1093  1 assertEquals("[2, 2, 8, 12]", Arrays.toString(ranges));
1094   
1095  1 ranges = new int[] { 2, 2, 8, 12 };
1096  1 adjusted = MappingUtils.removeStartPositions(2, ranges);
1097  1 assertEquals("[9, 12]", Arrays.toString(adjusted));
1098  1 assertEquals("[2, 2, 8, 12]", Arrays.toString(ranges));
1099   
1100  1 ranges = new int[] { 2, 2, 4, 4, 9, 12 };
1101  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1102  1 assertEquals("[4, 4, 9, 12]", Arrays.toString(adjusted));
1103  1 assertEquals("[2, 2, 4, 4, 9, 12]", Arrays.toString(ranges));
1104   
1105  1 ranges = new int[] { 2, 2, 4, 4, 9, 12 };
1106  1 adjusted = MappingUtils.removeStartPositions(2, ranges);
1107  1 assertEquals("[9, 12]", Arrays.toString(adjusted));
1108  1 assertEquals("[2, 2, 4, 4, 9, 12]", Arrays.toString(ranges));
1109   
1110  1 ranges = new int[] { 2, 3, 9, 12 };
1111  1 adjusted = MappingUtils.removeStartPositions(3, ranges);
1112  1 assertEquals("[10, 12]", Arrays.toString(adjusted));
1113  1 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  1 toggle @Test(groups = "Functional")
1121    public void testRemoveStartPositions_reverseStrand()
1122    {
1123  1 int[] ranges = new int[] { 10, 1 };
1124  1 int[] adjusted = MappingUtils.removeStartPositions(0, ranges);
1125  1 assertEquals("[10, 1]", Arrays.toString(adjusted));
1126  1 assertEquals("[10, 1]", Arrays.toString(ranges));
1127   
1128  1 ranges = adjusted;
1129  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1130  1 assertEquals("[9, 1]", Arrays.toString(adjusted));
1131  1 assertEquals("[10, 1]", Arrays.toString(ranges));
1132   
1133  1 ranges = adjusted;
1134  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1135  1 assertEquals("[8, 1]", Arrays.toString(adjusted));
1136  1 assertEquals("[9, 1]", Arrays.toString(ranges));
1137   
1138  1 ranges = new int[] { 12, 11, 9, 6 };
1139  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1140  1 assertEquals("[11, 11, 9, 6]", Arrays.toString(adjusted));
1141  1 assertEquals("[12, 11, 9, 6]", Arrays.toString(ranges));
1142   
1143  1 ranges = new int[] { 12, 12, 8, 4 };
1144  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1145  1 assertEquals("[8, 4]", Arrays.toString(adjusted));
1146  1 assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
1147   
1148  1 ranges = new int[] { 12, 12, 8, 4 };
1149  1 adjusted = MappingUtils.removeStartPositions(2, ranges);
1150  1 assertEquals("[7, 4]", Arrays.toString(adjusted));
1151  1 assertEquals("[12, 12, 8, 4]", Arrays.toString(ranges));
1152   
1153  1 ranges = new int[] { 12, 12, 10, 10, 8, 4 };
1154  1 adjusted = MappingUtils.removeStartPositions(1, ranges);
1155  1 assertEquals("[10, 10, 8, 4]", Arrays.toString(adjusted));
1156  1 assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
1157   
1158  1 ranges = new int[] { 12, 12, 10, 10, 8, 4 };
1159  1 adjusted = MappingUtils.removeStartPositions(2, ranges);
1160  1 assertEquals("[8, 4]", Arrays.toString(adjusted));
1161  1 assertEquals("[12, 12, 10, 10, 8, 4]", Arrays.toString(ranges));
1162   
1163  1 ranges = new int[] { 12, 11, 8, 4 };
1164  1 adjusted = MappingUtils.removeStartPositions(3, ranges);
1165  1 assertEquals("[7, 4]", Arrays.toString(adjusted));
1166  1 assertEquals("[12, 11, 8, 4]", Arrays.toString(ranges));
1167    }
1168   
 
1169  1 toggle @Test(groups = { "Functional" })
1170    public void testRangeContains()
1171    {
1172    /*
1173    * both forward ranges
1174    */
1175  1 assertTrue(
1176    MappingUtils.rangeContains(new int[]
1177    { 1, 10 }, new int[] { 1, 10 }));
1178  1 assertTrue(
1179    MappingUtils.rangeContains(new int[]
1180    { 1, 10 }, new int[] { 2, 10 }));
1181  1 assertTrue(
1182    MappingUtils.rangeContains(new int[]
1183    { 1, 10 }, new int[] { 1, 9 }));
1184  1 assertTrue(
1185    MappingUtils.rangeContains(new int[]
1186    { 1, 10 }, new int[] { 4, 5 }));
1187  1 assertFalse(
1188    MappingUtils.rangeContains(new int[]
1189    { 1, 10 }, new int[] { 0, 9 }));
1190  1 assertFalse(
1191    MappingUtils.rangeContains(new int[]
1192    { 1, 10 }, new int[] { -10, -9 }));
1193  1 assertFalse(
1194    MappingUtils.rangeContains(new int[]
1195    { 1, 10 }, new int[] { 1, 11 }));
1196  1 assertFalse(
1197    MappingUtils.rangeContains(new int[]
1198    { 1, 10 }, new int[] { 11, 12 }));
1199   
1200    /*
1201    * forward range, reverse query
1202    */
1203  1 assertTrue(
1204    MappingUtils.rangeContains(new int[]
1205    { 1, 10 }, new int[] { 10, 1 }));
1206  1 assertTrue(
1207    MappingUtils.rangeContains(new int[]
1208    { 1, 10 }, new int[] { 9, 1 }));
1209  1 assertTrue(
1210    MappingUtils.rangeContains(new int[]
1211    { 1, 10 }, new int[] { 10, 2 }));
1212  1 assertTrue(
1213    MappingUtils.rangeContains(new int[]
1214    { 1, 10 }, new int[] { 5, 5 }));
1215  1 assertFalse(
1216    MappingUtils.rangeContains(new int[]
1217    { 1, 10 }, new int[] { 11, 1 }));
1218  1 assertFalse(
1219    MappingUtils.rangeContains(new int[]
1220    { 1, 10 }, new int[] { 10, 0 }));
1221   
1222    /*
1223    * reverse range, forward query
1224    */
1225  1 assertTrue(
1226    MappingUtils.rangeContains(new int[]
1227    { 10, 1 }, new int[] { 1, 10 }));
1228  1 assertTrue(
1229    MappingUtils.rangeContains(new int[]
1230    { 10, 1 }, new int[] { 1, 9 }));
1231  1 assertTrue(
1232    MappingUtils.rangeContains(new int[]
1233    { 10, 1 }, new int[] { 2, 10 }));
1234  1 assertTrue(
1235    MappingUtils.rangeContains(new int[]
1236    { 10, 1 }, new int[] { 6, 6 }));
1237  1 assertFalse(
1238    MappingUtils.rangeContains(new int[]
1239    { 10, 1 }, new int[] { 6, 11 }));
1240  1 assertFalse(
1241    MappingUtils.rangeContains(new int[]
1242    { 10, 1 }, new int[] { 11, 20 }));
1243  1 assertFalse(
1244    MappingUtils.rangeContains(new int[]
1245    { 10, 1 }, new int[] { -3, -2 }));
1246   
1247    /*
1248    * both reverse
1249    */
1250  1 assertTrue(
1251    MappingUtils.rangeContains(new int[]
1252    { 10, 1 }, new int[] { 10, 1 }));
1253  1 assertTrue(
1254    MappingUtils.rangeContains(new int[]
1255    { 10, 1 }, new int[] { 9, 1 }));
1256  1 assertTrue(
1257    MappingUtils.rangeContains(new int[]
1258    { 10, 1 }, new int[] { 10, 2 }));
1259  1 assertTrue(
1260    MappingUtils.rangeContains(new int[]
1261    { 10, 1 }, new int[] { 3, 3 }));
1262  1 assertFalse(
1263    MappingUtils.rangeContains(new int[]
1264    { 10, 1 }, new int[] { 11, 1 }));
1265  1 assertFalse(
1266    MappingUtils.rangeContains(new int[]
1267    { 10, 1 }, new int[] { 10, 0 }));
1268  1 assertFalse(
1269    MappingUtils.rangeContains(new int[]
1270    { 10, 1 }, new int[] { 12, 11 }));
1271  1 assertFalse(
1272    MappingUtils.rangeContains(new int[]
1273    { 10, 1 }, new int[] { -5, -8 }));
1274   
1275    /*
1276    * bad arguments
1277    */
1278  1 assertFalse(
1279    MappingUtils.rangeContains(new int[]
1280    { 1, 10, 12 }, new int[] { 1, 10 }));
1281  1 assertFalse(
1282    MappingUtils.rangeContains(new int[]
1283    { 1, 10 }, new int[] { 1 }));
1284  1 assertFalse(MappingUtils.rangeContains(new int[] { 1, 10 }, null));
1285  1 assertFalse(MappingUtils.rangeContains(null, new int[] { 1, 10 }));
1286    }
1287   
 
1288  1 toggle @Test(groups = "Functional")
1289    public void testRemoveEndPositions()
1290    {
1291  1 List<int[]> ranges = new ArrayList<>();
1292   
1293    /*
1294    * case 1: truncate last range
1295    */
1296  1 ranges.add(new int[] { 1, 10 });
1297  1 ranges.add(new int[] { 20, 30 });
1298  1 MappingUtils.removeEndPositions(5, ranges);
1299  1 assertEquals(2, ranges.size());
1300  1 assertEquals(25, ranges.get(1)[1]);
1301   
1302    /*
1303    * case 2: remove last range
1304    */
1305  1 ranges.clear();
1306  1 ranges.add(new int[] { 1, 10 });
1307  1 ranges.add(new int[] { 20, 22 });
1308  1 MappingUtils.removeEndPositions(3, ranges);
1309  1 assertEquals(1, ranges.size());
1310  1 assertEquals(10, ranges.get(0)[1]);
1311   
1312    /*
1313    * case 3: truncate penultimate range
1314    */
1315  1 ranges.clear();
1316  1 ranges.add(new int[] { 1, 10 });
1317  1 ranges.add(new int[] { 20, 21 });
1318  1 MappingUtils.removeEndPositions(3, ranges);
1319  1 assertEquals(1, ranges.size());
1320  1 assertEquals(9, ranges.get(0)[1]);
1321   
1322    /*
1323    * case 4: remove last two ranges
1324    */
1325  1 ranges.clear();
1326  1 ranges.add(new int[] { 1, 10 });
1327  1 ranges.add(new int[] { 20, 20 });
1328  1 ranges.add(new int[] { 30, 30 });
1329  1 MappingUtils.removeEndPositions(3, ranges);
1330  1 assertEquals(1, ranges.size());
1331  1 assertEquals(9, ranges.get(0)[1]);
1332    }
1333   
 
1334  1 toggle @Test(groups = "Functional")
1335    public void testFindOverlap()
1336    {
1337  1 List<int[]> ranges = new ArrayList<>();
1338  1 ranges.add(new int[] { 4, 8 });
1339  1 ranges.add(new int[] { 10, 12 });
1340  1 ranges.add(new int[] { 16, 19 });
1341   
1342  1 int[] overlap = MappingUtils.findOverlap(ranges, 5, 13);
1343  1 assertArrayEquals(overlap, new int[] { 5, 12 });
1344  1 overlap = MappingUtils.findOverlap(ranges, -100, 100);
1345  1 assertArrayEquals(overlap, new int[] { 4, 19 });
1346  1 overlap = MappingUtils.findOverlap(ranges, 7, 17);
1347  1 assertArrayEquals(overlap, new int[] { 7, 17 });
1348  1 overlap = MappingUtils.findOverlap(ranges, 13, 15);
1349  1 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  1 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  1 SequenceI dna = new Sequence("dna", "aaatttgggcccaaatttgggccc");
1369  1 SequenceI cds1 = new Sequence("cds1/1-6", "aaattt");
1370  1 SequenceI cds2 = new Sequence("cds1/4-9", "tttggg");
1371  1 SequenceI cds3 = new Sequence("cds1/19-24", "gggccc");
1372   
1373  1 cds1.setDatasetSequence(dna);
1374  1 cds2.setDatasetSequence(dna);
1375  1 cds3.setDatasetSequence(dna);
1376   
1377  1 SequenceI pep1 = new Sequence("pep1", "KF");
1378  1 SequenceI pep2 = new Sequence("pep2", "FG");
1379  1 SequenceI pep3 = new Sequence("pep3", "GP");
1380  1 pep1.createDatasetSequence();
1381  1 pep2.createDatasetSequence();
1382  1 pep3.createDatasetSequence();
1383   
1384    /*
1385    * add mappings from coding positions of dna to respective peptides
1386    */
1387  1 AlignedCodonFrame acf = new AlignedCodonFrame();
1388  1 acf.addMap(dna, pep1,
1389    new MapList(new int[]
1390    { 1, 6 }, new int[] { 1, 2 }, 3, 1));
1391  1 acf.addMap(dna, pep2,
1392    new MapList(new int[]
1393    { 4, 9 }, new int[] { 1, 2 }, 3, 1));
1394  1 acf.addMap(dna, pep3,
1395    new MapList(new int[]
1396    { 19, 24 }, new int[] { 1, 2 }, 3, 1));
1397   
1398  1 List<AlignedCodonFrame> acfList = Arrays
1399    .asList(new AlignedCodonFrame[]
1400    { acf });
1401   
1402  1 AlignmentI cdna = new Alignment(new SequenceI[] { cds1, cds2, cds3 });
1403  1 AlignmentI protein = new Alignment(
1404    new SequenceI[]
1405    { pep1, pep2, pep3 });
1406  1 AlignViewportI cdnaView = new AlignViewport(cdna);
1407  1 AlignViewportI peptideView = new AlignViewport(protein);
1408  1 protein.setCodonFrames(acfList);
1409   
1410    /*
1411    * Select pep1 and pep3 in the protein alignment
1412    */
1413  1 SequenceGroup sg = new SequenceGroup();
1414  1 sg.setColourText(true);
1415  1 sg.setIdColour(Color.GREEN);
1416  1 sg.setOutlineColour(Color.LIGHT_GRAY);
1417  1 sg.addSequence(pep1, false);
1418  1 sg.addSequence(pep3, false);
1419  1 sg.setEndRes(protein.getWidth() - 1);
1420   
1421    /*
1422    * Verify the mapped sequence group in dna is cds1 and cds3
1423    */
1424  1 SequenceGroup mappedGroup = MappingUtils.mapSequenceGroup(sg,
1425    peptideView, cdnaView);
1426  1 assertTrue(mappedGroup.getColourText());
1427  1 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
1428  1 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
1429  1 assertEquals(2, mappedGroup.getSequences().size());
1430  1 assertSame(cds1, mappedGroup.getSequences().get(0));
1431  1 assertSame(cds3, mappedGroup.getSequences().get(1));
1432    // columns 1-6 selected (0-5 base zero)
1433  1 assertEquals(0, mappedGroup.getStartRes());
1434  1 assertEquals(5, mappedGroup.getEndRes());
1435   
1436    /*
1437    * Select mapping sequence group from dna to protein
1438    */
1439  1 sg.clear();
1440  1 sg.addSequence(cds2, false);
1441  1 sg.addSequence(cds1, false);
1442  1 sg.setStartRes(0);
1443  1 sg.setEndRes(cdna.getWidth() - 1);
1444  1 mappedGroup = MappingUtils.mapSequenceGroup(sg, cdnaView, peptideView);
1445  1 assertTrue(mappedGroup.getColourText());
1446  1 assertSame(sg.getIdColour(), mappedGroup.getIdColour());
1447  1 assertSame(sg.getOutlineColour(), mappedGroup.getOutlineColour());
1448  1 assertEquals(2, mappedGroup.getSequences().size());
1449  1 assertSame(protein.getSequenceAt(1), mappedGroup.getSequences().get(0));
1450  1 assertSame(protein.getSequenceAt(0), mappedGroup.getSequences().get(1));
1451  1 assertEquals(0, mappedGroup.getStartRes());
1452  1 assertEquals(1, mappedGroup.getEndRes()); // two columns
1453    }
1454   
1455    // new for 2.12
 
1456  1 toggle @Test(groups = "Functional")
1457    public void testAddRange()
1458    {
1459  1 int[] range = { 1, 5 };
1460  1 List<int[]> ranges = new ArrayList<>();
1461   
1462    // add to empty list:
1463  1 MappingUtils.addRange(range, ranges);
1464  1 assertEquals(1, ranges.size());
1465  1 assertSame(range, ranges.get(0));
1466   
1467    // extend contiguous (same position):
1468  1 MappingUtils.addRange(new int[] { 5, 10 }, ranges);
1469  1 assertEquals(1, ranges.size());
1470  1 assertEquals(1, ranges.get(0)[0]);
1471  1 assertEquals(10, ranges.get(0)[1]);
1472   
1473    // extend contiguous (next position):
1474  1 MappingUtils.addRange(new int[] { 11, 15 }, ranges);
1475  1 assertEquals(1, ranges.size());
1476  1 assertEquals(1, ranges.get(0)[0]);
1477  1 assertEquals(15, ranges.get(0)[1]);
1478   
1479    // change direction: range is not merged:
1480  1 MappingUtils.addRange(new int[] { 16, 10 }, ranges);
1481  1 assertEquals(2, ranges.size());
1482  1 assertEquals(16, ranges.get(1)[0]);
1483  1 assertEquals(10, ranges.get(1)[1]);
1484   
1485    // extend reverse contiguous (same position):
1486  1 MappingUtils.addRange(new int[] { 10, 8 }, ranges);
1487  1 assertEquals(2, ranges.size());
1488  1 assertEquals(16, ranges.get(1)[0]);
1489  1 assertEquals(8, ranges.get(1)[1]);
1490   
1491    // extend reverse contiguous (next position):
1492  1 MappingUtils.addRange(new int[] { 7, 6 }, ranges);
1493  1 assertEquals(2, ranges.size());
1494  1 assertEquals(16, ranges.get(1)[0]);
1495  1 assertEquals(6, ranges.get(1)[1]);
1496   
1497    // change direction: range is not merged:
1498  1 MappingUtils.addRange(new int[] { 6, 9 }, ranges);
1499  1 assertEquals(3, ranges.size());
1500  1 assertEquals(6, ranges.get(2)[0]);
1501  1 assertEquals(9, ranges.get(2)[1]);
1502   
1503    // not contiguous: not merged
1504  1 MappingUtils.addRange(new int[] { 11, 12 }, ranges);
1505  1 assertEquals(4, ranges.size());
1506  1 assertEquals(11, ranges.get(3)[0]);
1507  1 assertEquals(12, ranges.get(3)[1]);
1508    }
1509    }