JAL-1705 isFromForwardStrand added; toString (for debug) tweaked
[jalview.git] / test / jalview / util / MapListTest.java
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
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.List;
32
33 import org.testng.annotations.Test;
34
35 public class MapListTest
36 {
37
38   @Test(groups = { "Functional" })
39   public void testSomething()
40   {
41     MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
42         51, 1 }, 1, 3);
43     MapList ml1 = new MapList(new int[] { 1, 3, 17, 4 },
44             new int[] { 51, 1 }, 1, 3);
45     MapList ml2 = new MapList(new int[] { 1, 60 }, new int[] { 1, 20 }, 3,
46             1);
47     // test internal consistency
48     int to[] = new int[51];
49     testMap(ml, 1, 60);
50     MapList mldna = new MapList(new int[] { 2, 2, 6, 8, 12, 16 }, new int[]
51     { 1, 3 }, 3, 1);
52     int[] frm = mldna.locateInFrom(1, 1);
53     testLocateFrom(mldna, 1, 1, new int[] { 2, 2, 6, 7 });
54     testMap(mldna, 1, 3);
55     /*
56      * for (int from=1; from<=51; from++) { int[] too=ml.shiftTo(from); int[]
57      * toofrom=ml.shiftFrom(too[0]);
58      * System.out.println("ShiftFrom("+from+")=="+too[0]+" %
59      * "+too[1]+"\t+-+\tShiftTo("+too[0]+")=="+toofrom[0]+" % "+toofrom[1]); }
60      */
61   }
62
63   private static void testLocateFrom(MapList mldna, int i, int j, int[] ks)
64   {
65     int[] frm = mldna.locateInFrom(i, j);
66     assertEquals("Failed test locate from " + i + " to " + j,
67             Arrays.toString(frm), Arrays.toString(ks));
68   }
69
70   /**
71    * test routine. not incremental.
72    * 
73    * @param ml
74    * @param fromS
75    * @param fromE
76    */
77   private void testMap(MapList ml, int fromS, int fromE)
78   {
79     // todo convert to JUnit style tests
80     for (int from = 1; from <= 25; from++)
81     {
82       int[] too = ml.shiftFrom(from);
83       System.out.print("ShiftFrom(" + from + ")==");
84       if (too == null)
85       {
86         System.out.print("NaN\n");
87       }
88       else
89       {
90         System.out.print(too[0] + " % " + too[1] + " (" + too[2] + ")");
91         System.out.print("\t+--+\t");
92         int[] toofrom = ml.shiftTo(too[0]);
93         if (toofrom != null)
94         {
95           if (toofrom[0] != from)
96           {
97             System.err.println("Mapping not reflexive:" + from + " "
98                     + too[0] + "->" + toofrom[0]);
99           }
100           System.out.println("ShiftTo(" + too[0] + ")==" + toofrom[0]
101                   + " % " + toofrom[1] + " (" + toofrom[2] + ")");
102         }
103         else
104         {
105           System.out.println("ShiftTo(" + too[0] + ")=="
106                   + "NaN! - not Bijective Mapping!");
107         }
108       }
109     }
110     int mmap[][] = ml.makeFromMap();
111     System.out.println("FromMap : (" + mmap[0][0] + " " + mmap[0][1] + " "
112             + mmap[0][2] + " " + mmap[0][3] + " ");
113     for (int i = 1; i <= mmap[1].length; i++)
114     {
115       if (mmap[1][i - 1] == -1)
116       {
117         System.out.print(i + "=XXX");
118
119       }
120       else
121       {
122         System.out.print(i + "=" + (mmap[0][2] + mmap[1][i - 1]));
123       }
124       if (i % 20 == 0)
125       {
126         System.out.print("\n");
127       }
128       else
129       {
130         System.out.print(",");
131       }
132     }
133     // test range function
134     System.out.print("\nTest locateInFrom\n");
135     {
136       int f = mmap[0][2], t = mmap[0][3];
137       while (f <= t)
138       {
139         System.out.println("Range " + f + " to " + t);
140         int rng[] = ml.locateInFrom(f, t);
141         if (rng != null)
142         {
143           for (int i = 0; i < rng.length; i++)
144           {
145             System.out.print(rng[i] + ((i % 2 == 0) ? "," : ";"));
146           }
147         }
148         else
149         {
150           System.out.println("No range!");
151         }
152         System.out.print("\nReversed\n");
153         rng = ml.locateInFrom(t, f);
154         if (rng != null)
155         {
156           for (int i = 0; i < rng.length; i++)
157           {
158             System.out.print(rng[i] + ((i % 2 == 0) ? "," : ";"));
159           }
160         }
161         else
162         {
163           System.out.println("No range!");
164         }
165         System.out.print("\n");
166         f++;
167         t--;
168       }
169     }
170     System.out.print("\n");
171     mmap = ml.makeToMap();
172     System.out.println("ToMap : (" + mmap[0][0] + " " + mmap[0][1] + " "
173             + mmap[0][2] + " " + mmap[0][3] + " ");
174     for (int i = 1; i <= mmap[1].length; i++)
175     {
176       if (mmap[1][i - 1] == -1)
177       {
178         System.out.print(i + "=XXX");
179
180       }
181       else
182       {
183         System.out.print(i + "=" + (mmap[0][2] + mmap[1][i - 1]));
184       }
185       if (i % 20 == 0)
186       {
187         System.out.print("\n");
188       }
189       else
190       {
191         System.out.print(",");
192       }
193     }
194     System.out.print("\n");
195     // test range function
196     System.out.print("\nTest locateInTo\n");
197     {
198       int f = mmap[0][2], t = mmap[0][3];
199       while (f <= t)
200       {
201         System.out.println("Range " + f + " to " + t);
202         int rng[] = ml.locateInTo(f, t);
203         if (rng != null)
204         {
205           for (int i = 0; i < rng.length; i++)
206           {
207             System.out.print(rng[i] + ((i % 2 == 0) ? "," : ";"));
208           }
209         }
210         else
211         {
212           System.out.println("No range!");
213         }
214         System.out.print("\nReversed\n");
215         rng = ml.locateInTo(t, f);
216         if (rng != null)
217         {
218           for (int i = 0; i < rng.length; i++)
219           {
220             System.out.print(rng[i] + ((i % 2 == 0) ? "," : ";"));
221           }
222         }
223         else
224         {
225           System.out.println("No range!");
226         }
227         f++;
228         t--;
229         System.out.print("\n");
230       }
231     }
232   }
233
234   /**
235    * Tests for method that locates ranges in the 'from' map for given range in
236    * the 'to' map.
237    */
238   @Test(groups = { "Functional" })
239   public void testLocateInFrom_noIntrons()
240   {
241     /*
242      * Simple mapping with no introns
243      */
244     int[] codons = new int[] { 1, 12 };
245     int[] protein = new int[] { 1, 4 };
246     MapList ml = new MapList(codons, protein, 3, 1);
247     assertEquals("[1, 3]", Arrays.toString(ml.locateInFrom(1, 1)));
248     assertEquals("[4, 6]", Arrays.toString(ml.locateInFrom(2, 2)));
249     assertEquals("[7, 9]", Arrays.toString(ml.locateInFrom(3, 3)));
250     assertEquals("[10, 12]", Arrays.toString(ml.locateInFrom(4, 4)));
251     assertEquals("[1, 6]", Arrays.toString(ml.locateInFrom(1, 2)));
252     assertEquals("[1, 9]", Arrays.toString(ml.locateInFrom(1, 3)));
253     assertEquals("[1, 12]", Arrays.toString(ml.locateInFrom(1, 4)));
254     assertEquals("[4, 9]", Arrays.toString(ml.locateInFrom(2, 3)));
255     assertEquals("[4, 12]", Arrays.toString(ml.locateInFrom(2, 4)));
256     assertEquals("[7, 12]", Arrays.toString(ml.locateInFrom(3, 4)));
257     assertEquals("[10, 12]", Arrays.toString(ml.locateInFrom(4, 4)));
258
259     assertNull(ml.locateInFrom(0, 0));
260     assertNull(ml.locateInFrom(1, 5));
261     assertNull(ml.locateInFrom(-1, 1));
262   }
263
264   /**
265    * Tests for method that locates ranges in the 'from' map for given range in
266    * the 'to' map.
267    */
268   @Test(groups = { "Functional" })
269   public void testLocateInFrom_withIntrons()
270   {
271     /*
272      * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [16, 17, 18] i.e.
273      * 2-3, 5-7, 9-10, 12-12, 14-14, 16-18
274      */
275     int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
276     int[] protein = { 1, 4 };
277     MapList ml = new MapList(codons, protein, 3, 1);
278     assertEquals("[2, 3, 5, 5]", Arrays.toString(ml.locateInFrom(1, 1)));
279     assertEquals("[6, 7, 9, 9]", Arrays.toString(ml.locateInFrom(2, 2)));
280     assertEquals("[10, 10, 12, 12, 14, 14]",
281             Arrays.toString(ml.locateInFrom(3, 3)));
282     assertEquals("[16, 18]", Arrays.toString(ml.locateInFrom(4, 4)));
283   }
284
285   /**
286    * Tests for method that locates ranges in the 'to' map for given range in the
287    * 'from' map.
288    */
289   @Test(groups = { "Functional" })
290   public void testLocateInTo_noIntrons()
291   {
292     /*
293      * Simple mapping with no introns
294      */
295     int[] codons = new int[] { 1, 12 };
296     int[] protein = new int[] { 1, 4 };
297     MapList ml = new MapList(codons, protein, 3, 1);
298     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(1, 3)));
299     assertEquals("[2, 2]", Arrays.toString(ml.locateInTo(4, 6)));
300     assertEquals("[3, 3]", Arrays.toString(ml.locateInTo(7, 9)));
301     assertEquals("[4, 4]", Arrays.toString(ml.locateInTo(10, 12)));
302     assertEquals("[1, 2]", Arrays.toString(ml.locateInTo(1, 6)));
303     assertEquals("[1, 3]", Arrays.toString(ml.locateInTo(1, 9)));
304     assertEquals("[1, 4]", Arrays.toString(ml.locateInTo(1, 12)));
305     assertEquals("[2, 2]", Arrays.toString(ml.locateInTo(4, 6)));
306     assertEquals("[2, 4]", Arrays.toString(ml.locateInTo(4, 12)));
307
308     /*
309      * A part codon is treated as if a whole one.
310      */
311     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(1, 1)));
312     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(1, 2)));
313     assertEquals("[1, 2]", Arrays.toString(ml.locateInTo(1, 4)));
314     assertEquals("[1, 3]", Arrays.toString(ml.locateInTo(2, 8)));
315     assertEquals("[1, 4]", Arrays.toString(ml.locateInTo(3, 11)));
316     assertEquals("[2, 4]", Arrays.toString(ml.locateInTo(5, 11)));
317
318     assertNull(ml.locateInTo(0, 0));
319     assertNull(ml.locateInTo(1, 13));
320     assertNull(ml.locateInTo(-1, 1));
321   }
322
323   /**
324    * Tests for method that locates ranges in the 'to' map for given range in the
325    * 'from' map.
326    */
327   @Test(groups = { "Functional" })
328   public void testLocateInTo_withIntrons()
329   {
330     /*
331      * Exons at positions [2, 3, 5] [6, 7, 9] [10, 12, 14] [16, 17, 18] i.e.
332      * 2-3, 5-7, 9-10, 12-12, 14-14, 16-18
333      */
334     int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
335     /*
336      * Mapped proteins at positions 1, 3, 4, 6 in the sequence
337      */
338     int[] protein = { 1, 1, 3, 4, 6, 6 };
339     MapList ml = new MapList(codons, protein, 3, 1);
340
341     /*
342      * Can't map from an unmapped position
343      */
344     assertNull(ml.locateInTo(1, 2));
345     assertNull(ml.locateInTo(2, 4));
346     assertNull(ml.locateInTo(4, 4));
347
348     /*
349      * Valid range or subrange of codon1 maps to protein1.
350      */
351     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(2, 2)));
352     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(3, 3)));
353     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(3, 5)));
354     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(2, 3)));
355     assertEquals("[1, 1]", Arrays.toString(ml.locateInTo(2, 5)));
356
357     // codon position 6 starts the next protein:
358     assertEquals("[1, 1, 3, 3]", Arrays.toString(ml.locateInTo(3, 6)));
359
360     // codon positions 7 to 17 (part) cover proteins 2/3/4 at positions 3/4/6
361     assertEquals("[3, 4, 6, 6]", Arrays.toString(ml.locateInTo(7, 17)));
362
363   }
364
365   /**
366    * Test equals method.
367    */
368   @Test(groups = { "Functional" })
369   public void testEquals()
370   {
371     int[] codons = new int[] { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
372     int[] protein = new int[] { 1, 4 };
373     MapList ml = new MapList(codons, protein, 3, 1);
374     MapList ml1 = new MapList(codons, protein, 3, 1); // same values
375     MapList ml2 = new MapList(codons, protein, 2, 1); // fromRatio differs
376     MapList ml3 = new MapList(codons, protein, 3, 2); // toRatio differs
377     codons[2] = 4;
378     MapList ml6 = new MapList(codons, protein, 3, 1); // fromShifts differ
379     protein[1] = 3;
380     MapList ml7 = new MapList(codons, protein, 3, 1); // toShifts differ
381
382     assertTrue(ml.equals(ml));
383     assertTrue(ml.equals(ml1));
384     assertTrue(ml1.equals(ml));
385
386     assertFalse(ml.equals(null));
387     assertFalse(ml.equals("hello"));
388     assertFalse(ml.equals(ml2));
389     assertFalse(ml.equals(ml3));
390     assertFalse(ml.equals(ml6));
391     assertFalse(ml.equals(ml7));
392     assertFalse(ml6.equals(ml7));
393
394     try
395     {
396       MapList ml4 = new MapList(codons, null, 3, 1); // toShifts null
397       assertFalse(ml.equals(ml4));
398     } catch (NullPointerException e)
399     {
400       // actually thrown by constructor before equals can be called
401     }
402     try
403     {
404       MapList ml5 = new MapList(null, protein, 3, 1); // fromShifts null
405       assertFalse(ml.equals(ml5));
406     } catch (NullPointerException e)
407     {
408       // actually thrown by constructor before equals can be called
409     }
410   }
411
412   /**
413    * Test for the method that flattens a list of ranges into a single array.
414    */
415   @Test(groups = { "Functional" })
416   public void testGetRanges()
417   {
418     List<int[]> ranges = new ArrayList<int[]>();
419     ranges.add(new int[] { 2, 3 });
420     ranges.add(new int[] { 5, 6 });
421     assertEquals("[2, 3, 5, 6]", Arrays.toString(MapList.getRanges(ranges)));
422   }
423
424   /**
425    * Check state after construction
426    */
427   @Test(groups = { "Functional" })
428   public void testConstructor()
429   {
430     int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
431     int[] protein = { 1, 1, 3, 4, 6, 6 };
432     MapList ml = new MapList(codons, protein, 3, 1);
433     assertEquals(3, ml.getFromRatio());
434     assertEquals(2, ml.getFromLowest());
435     assertEquals(18, ml.getFromHighest());
436     assertEquals(1, ml.getToLowest());
437     assertEquals(6, ml.getToHighest());
438     assertEquals("{[2, 3], [5, 7], [9, 10], [12, 12], [14, 14], [16, 18]}",
439             prettyPrint(ml.getFromRanges()));
440     assertEquals("{[1, 1], [3, 4], [6, 6]}", prettyPrint(ml.getToRanges()));
441
442     /*
443      * Also copy constructor
444      */
445     MapList ml2 = new MapList(ml);
446     assertEquals(3, ml2.getFromRatio());
447     assertEquals(2, ml2.getFromLowest());
448     assertEquals(18, ml2.getFromHighest());
449     assertEquals(1, ml2.getToLowest());
450     assertEquals(6, ml2.getToHighest());
451     assertEquals("{[2, 3], [5, 7], [9, 10], [12, 12], [14, 14], [16, 18]}",
452             prettyPrint(ml2.getFromRanges()));
453     assertEquals("{[1, 1], [3, 4], [6, 6]}", prettyPrint(ml2.getToRanges()));
454
455     /*
456      * reverse direction
457      */
458     codons = new int[] { 9, 6 };
459     protein = new int[] { 100, 91, 80, 79 };
460     ml = new MapList(codons, protein, 3, 1);
461     assertEquals(6, ml.getFromLowest());
462     assertEquals(9, ml.getFromHighest());
463     assertEquals(79, ml.getToLowest());
464     assertEquals(100, ml.getToHighest());
465   }
466
467   /**
468    * Test constructor can merge consecutive ranges
469    */
470   @Test(groups = { "Functional" })
471   public void testConstructor_mergeRanges()
472   {
473     int[] codons = { 2, 3, 3, 7, 9, 10, 12, 12, 14, 14, 16, 17 };
474     int[] protein = { 1, 1, 1, 3, 6, 6 };
475     MapList ml = new MapList(codons, protein, 3, 1);
476     assertEquals(3, ml.getFromRatio());
477     assertEquals(2, ml.getFromLowest());
478     assertEquals(17, ml.getFromHighest());
479     assertEquals(1, ml.getToLowest());
480     assertEquals(6, ml.getToHighest());
481     assertEquals("{[2, 7], [9, 10], [12, 12], [14, 14], [16, 17]}",
482             prettyPrint(ml.getFromRanges()));
483     assertEquals("{[1, 3], [6, 6]}", prettyPrint(ml.getToRanges()));
484   }
485
486   /**
487    * Convert a List of {[i, j], [k, l], ...} to "[[i, j], [k, l], ...]"
488    * 
489    * @param ranges
490    * @return
491    */
492   private String prettyPrint(List<int[]> ranges)
493   {
494     StringBuilder sb = new StringBuilder(ranges.size() * 5);
495     boolean first = true;
496     sb.append("{");
497     for (int[] range : ranges)
498     {
499       if (!first)
500       {
501         sb.append(", ");
502       }
503       sb.append(Arrays.toString(range));
504       first = false;
505     }
506     sb.append("}");
507     return sb.toString();
508   }
509
510   /**
511    * Test the method that creates an inverse mapping
512    */
513   @Test(groups = { "Functional" })
514   public void testGetInverse()
515   {
516     int[] codons = { 2, 3, 5, 7, 9, 10, 12, 12, 14, 14, 16, 18 };
517     int[] protein = { 1, 1, 3, 4, 6, 6 };
518
519     MapList ml = new MapList(codons, protein, 3, 1);
520     MapList ml2 = ml.getInverse();
521     assertEquals(ml.getFromRatio(), ml2.getToRatio());
522     assertEquals(ml.getFromRatio(), ml2.getToRatio());
523     assertEquals(ml.getToHighest(), ml2.getFromHighest());
524     assertEquals(ml.getFromHighest(), ml2.getToHighest());
525     assertEquals(prettyPrint(ml.getFromRanges()),
526             prettyPrint(ml2.getToRanges()));
527     assertEquals(prettyPrint(ml.getToRanges()),
528             prettyPrint(ml2.getFromRanges()));
529   }
530
531   @Test(groups = { "Functional" })
532   public void testToString()
533   {
534     MapList ml = new MapList(new int[] { 1, 5, 10, 15, 25, 20 }, new int[] {
535         51, 1 }, 1, 3);
536     String s = ml.toString();
537     assertEquals("[ [1, 5] [10, 15] [25, 20] ] To [ [51, 1] ]",
538             s);
539   }
540
541   @Test(groups = { "Functional" })
542   public void testAddMapList()
543   {
544     MapList ml = new MapList(new int[] { 11, 15, 20, 25, 35, 30 },
545             new int[] { 72, 22 }, 1, 3);
546     assertEquals(11, ml.getFromLowest());
547     assertEquals(35, ml.getFromHighest());
548     assertEquals(22, ml.getToLowest());
549     assertEquals(72, ml.getToHighest());
550
551     MapList ml2 = new MapList(new int[] { 2, 4, 37, 40 }, new int[] { 12,
552         17, 78, 83, 88, 96 }, 1, 3);
553     ml.addMapList(ml2);
554     assertEquals(2, ml.getFromLowest());
555     assertEquals(40, ml.getFromHighest());
556     assertEquals(12, ml.getToLowest());
557     assertEquals(96, ml.getToHighest());
558
559     String s = ml.toString();
560     assertEquals(
561             "[ [11, 15] [20, 25] [35, 30] [2, 4] [37, 40] ] To [ [72, 22] [12, 17] [78, 83] [88, 96] ]",
562             s);
563   }
564
565   @Test(groups = { "Functional" })
566   public void testAddMapList_contiguous()
567   {
568     MapList ml = new MapList(new int[] { 11, 15 }, new int[] { 72, 58 }, 1,
569             3);
570
571     MapList ml2 = new MapList(new int[] { 15, 16 }, new int[] { 58, 53 },
572             1, 3);
573     ml.addMapList(ml2);
574     assertEquals("[ [11, 16] ] To [ [72, 53] ]", ml.toString());
575   }
576
577   @Test(groups = "Functional")
578   public void testAddRange()
579   {
580     int[] range = { 1, 5 };
581     List<int[]> ranges = new ArrayList<int[]>();
582
583     // add to empty list:
584     MapList.addRange(range, ranges);
585     assertEquals(1, ranges.size());
586     assertSame(range, ranges.get(0));
587
588     // extend contiguous (same position):
589     MapList.addRange(new int[] { 5, 10 }, ranges);
590     assertEquals(1, ranges.size());
591     assertEquals(1, ranges.get(0)[0]);
592     assertEquals(10, ranges.get(0)[1]);
593
594     // extend contiguous (next position):
595     MapList.addRange(new int[] { 11, 15 }, ranges);
596     assertEquals(1, ranges.size());
597     assertEquals(1, ranges.get(0)[0]);
598     assertEquals(15, ranges.get(0)[1]);
599
600     // change direction: range is not merged:
601     MapList.addRange(new int[] { 16, 10 }, ranges);
602     assertEquals(2, ranges.size());
603     assertEquals(16, ranges.get(1)[0]);
604     assertEquals(10, ranges.get(1)[1]);
605
606     // extend reverse contiguous (same position):
607     MapList.addRange(new int[] { 10, 8 }, ranges);
608     assertEquals(2, ranges.size());
609     assertEquals(16, ranges.get(1)[0]);
610     assertEquals(8, ranges.get(1)[1]);
611
612     // extend reverse contiguous (next position):
613     MapList.addRange(new int[] { 7, 6 }, ranges);
614     assertEquals(2, ranges.size());
615     assertEquals(16, ranges.get(1)[0]);
616     assertEquals(6, ranges.get(1)[1]);
617
618     // change direction: range is not merged:
619     MapList.addRange(new int[] { 6, 9 }, ranges);
620     assertEquals(3, ranges.size());
621     assertEquals(6, ranges.get(2)[0]);
622     assertEquals(9, ranges.get(2)[1]);
623
624     // not contiguous: not merged
625     MapList.addRange(new int[] { 11, 12 }, ranges);
626     assertEquals(4, ranges.size());
627     assertEquals(11, ranges.get(3)[0]);
628     assertEquals(12, ranges.get(3)[1]);
629   }
630
631   /**
632    * Check state after construction
633    */
634   @Test(groups = { "Functional" })
635   public void testConstructor_withLists()
636   {
637     /*
638      * reverse direction
639      */
640     int[][] codons = new int[][] { { 9, 6 } };
641     int[][] protein = new int[][] { { 100, 91 }, { 80, 79 } };
642     MapList ml = new MapList(Arrays.asList(codons), Arrays.asList(protein),
643             3, 1);
644     assertEquals(6, ml.getFromLowest());
645     assertEquals(9, ml.getFromHighest());
646     assertEquals(79, ml.getToLowest());
647     assertEquals(100, ml.getToHighest());
648   }
649
650   /**
651    * Test that method that inspects for the (first) forward or reverse from
652    * range. Single position ranges are ignored.
653    */
654   @Test(groups = { "Functional" })
655   public void testIsFromForwardStrand()
656   {
657     MapList ml = new MapList(new int[] { 2, 2, 3, 9, 12, 11 },
658             new int[] { 20, 11 }, 1, 1);
659     assertTrue(ml.isFromForwardStrand());
660
661     ml = new MapList(new int[] { 2, 2, 11, 5, 13, 14 },
662             new int[] { 20, 11 }, 1, 1);
663     assertFalse(ml.isFromForwardStrand());
664
665     ml = new MapList(new int[] { 2, 2, 4, 4, 6, 6 }, new int[] { 3, 1 }, 1,
666             1);
667     assertTrue(ml.isFromForwardStrand());
668   }
669 }