1 package org.broadinstitute.hellbender.tools;
2 
3 import htsjdk.samtools.SAMFileHeader;
4 import org.broadinstitute.hellbender.GATKBaseTest;
5 import org.broadinstitute.hellbender.tools.AnalyzeSaturationMutagenesis.*;
6 import org.broadinstitute.hellbender.utils.read.ArtificialReadUtils;
7 import org.broadinstitute.hellbender.utils.read.GATKRead;
8 import org.testng.Assert;
9 import org.testng.annotations.Test;
10 
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collections;
14 import java.util.List;
15 
16 import static org.broadinstitute.hellbender.tools.AnalyzeSaturationMutagenesis.CodonTracker.NO_FRAME_SHIFT_CODON;
17 import static org.broadinstitute.hellbender.tools.AnalyzeSaturationMutagenesis.*;
18 
19 public class AnalyzeSaturationMutagenesisUnitTest extends GATKBaseTest {
20     final private static byte CALL_A = (byte)'A';
21     final private static byte CALL_C = (byte)'C';
22     final private static byte CALL_G = (byte)'G';
23     final private static byte CALL_T = (byte)'T';
24     final private static byte NO_CALL = (byte)'-';
25     final private static byte QUAL_10 = (byte)10;
26     final private static byte QUAL_20 = (byte)20;
27     final private static byte QUAL_30 = (byte)30;
28     final private static byte[] refSeq = "ACATGCGTCTAGTACGT".getBytes();
29     final private static String orfCoords = "3-6,8-12";
30     final private static CodonTracker localCodonTracker = new CodonTracker(orfCoords, refSeq, logger);
31 
32     @Test
testInterval()33     public void testInterval() {
34         final Interval interval1 = new Interval(1, 3);
35         Assert.assertEquals(interval1.size(), 2);
36         final Interval interval2 = new Interval(1, 3);
37         Assert.assertEquals(interval1, interval2);
38         Assert.assertEquals(interval1.hashCode(), interval2.hashCode());
39         final Interval interval3 = new Interval(1, 4);
40         Assert.assertNotEquals(interval1, interval3);
41         Assert.assertNotEquals(interval1.hashCode(), interval3.hashCode());
42     }
43 
44     @Test
testSNV()45     public void testSNV() {
46         final SNV snv1 = new SNV(0, CALL_A, CALL_C, QUAL_30);
47         final SNV snv2 = new SNV(0, CALL_A, CALL_C, QUAL_20);
48         Assert.assertEquals(snv1.hashCode(), snv2.hashCode());
49         Assert.assertEquals(snv1, snv2);
50         Assert.assertEquals(snv1.compareTo(snv2), 0);
51         final SNV snv3 = new SNV(1, CALL_A, CALL_C, QUAL_30);
52         Assert.assertNotEquals(snv1.hashCode(), snv3.hashCode());
53         Assert.assertNotEquals(snv1, snv3);
54         Assert.assertTrue(snv1.compareTo(snv3) < 0);
55         Assert.assertTrue(snv3.compareTo(snv2) > 0);
56         final SNV snv4 = new SNV(0, CALL_G, CALL_C, QUAL_30);
57         Assert.assertNotEquals(snv1.hashCode(), snv4.hashCode());
58         Assert.assertNotEquals(snv1, snv4);
59         Assert.assertTrue(snv1.compareTo(snv4) < 0);
60         Assert.assertTrue(snv4.compareTo(snv1) > 0);
61         final SNV snv5 = new SNV(0, CALL_A, CALL_G, QUAL_30);
62         Assert.assertNotEquals(snv1.hashCode(), snv5.hashCode());
63         Assert.assertNotEquals(snv1, snv5);
64         Assert.assertTrue(snv1.compareTo(snv5) < 0);
65         Assert.assertTrue(snv5.compareTo(snv1) > 0);
66         Assert.assertEquals(snv5.toString(), "1:A>G");
67     }
68 
69     @Test
testIntervalCounter()70     public void testIntervalCounter() {
71         final IntervalCounter intervalCounter = new IntervalCounter(10);
72         intervalCounter.addCount(new Interval(0, 10));
73         intervalCounter.addCount(new Interval(1, 9));
74         intervalCounter.addCount(new Interval(2, 8));
75         intervalCounter.addCount(new Interval(3, 7));
76         intervalCounter.addCount(new Interval(4, 6));
77         Assert.assertEquals(intervalCounter.countSpanners(0, 10), 1);
78         Assert.assertEquals(intervalCounter.countSpanners(5, 5), 5);
79         Assert.assertEquals(intervalCounter.countSpanners(2, 5), 3);
80         Assert.assertEquals(intervalCounter.countSpanners(5, 8), 3);
81         intervalCounter.addCount(new Interval(0, 10));
82         Assert.assertEquals(intervalCounter.countSpanners(0, 10), 2);
83     }
84 
85     @Test
testSNVCollection()86     public void testSNVCollection() {
87         final List<SNV> snvList1 = new ArrayList<>(Arrays.asList(
88                 new SNV(0, CALL_A, CALL_C, QUAL_30),
89                 new SNV(1, CALL_A, CALL_C, QUAL_20)));
90         final SNVCollectionCount cc1 = new SNVCollectionCount(snvList1, 10);
91 
92         // equality, key, compare, and hash should be independent of count and coverage
93         final List<SNV> snvList2 = Arrays.asList(
94                 new SNV(0, CALL_A, CALL_C, QUAL_30),
95                 new SNV(1, CALL_A, CALL_C, QUAL_20));
96         final SNVCollectionCount cc2 = new SNVCollectionCount(snvList2, 20);
97         Assert.assertEquals(cc1.hashCode(), cc2.hashCode());
98         Assert.assertEquals(cc1, cc2);
99         Assert.assertEquals(cc1.compareTo(cc2), 0);
100         cc2.bumpCount(30);
101         Assert.assertEquals(cc1.hashCode(), cc2.hashCode());
102         Assert.assertEquals(cc1, cc2);
103         Assert.assertEquals(cc1.compareTo(cc2), 0);
104 
105         Assert.assertEquals(cc2.getCount(), 2);
106         Assert.assertEquals(cc2.getMeanRefCoverage(), 25., .0000001);
107 
108         // changing the list shouldn't change the hash or the key
109         final int cc1Hash = cc1.hashCode();
110         final List<SNV> key1 = cc1.getSNVs();
111         snvList1.add(new SNV(2, CALL_A, CALL_C, QUAL_10));
112         Assert.assertEquals(cc1.hashCode(), cc1Hash);
113         Assert.assertEquals(cc1.getSNVs(), key1);
114 
115         // different lists should mean unequal to each other, unequal hashes, and non-zero compare
116         final SNVCollectionCount cc3 = new SNVCollectionCount(snvList1, 20);
117         Assert.assertNotEquals(cc1.hashCode(), cc3.hashCode());
118         Assert.assertNotEquals(cc1, cc3);
119         Assert.assertTrue(cc1.compareTo(cc3) < 0);
120         Assert.assertTrue(cc3.compareTo(cc1) > 0);
121     }
122 
123     @Test
testCodonVariationBasics()124     public void testCodonVariationBasics() {
125         Assert.assertTrue(CodonVariation.createDeletion(0).isDeletion());
126         Assert.assertTrue(CodonVariation.createFrameshift(0).isFrameshift());
127         Assert.assertTrue(CodonVariation.createInsertion(0,0).isInsertion());
128         Assert.assertTrue(CodonVariation.createModification(0,0).isModification());
129         Assert.assertFalse(CodonVariation.createDeletion(0).isModification());
130 
131         Assert.assertEquals(CodonVariation.createDeletion(1), CodonVariation.createDeletion(1));
132         Assert.assertNotEquals(CodonVariation.createDeletion(0), CodonVariation.createDeletion(1));
133         Assert.assertEquals(CodonVariation.createFrameshift(1), CodonVariation.createFrameshift(1));
134         Assert.assertNotEquals(CodonVariation.createFrameshift(0), CodonVariation.createFrameshift(1));
135         Assert.assertNotEquals(CodonVariation.createFrameshift(0), CodonVariation.createDeletion(0));
136         Assert.assertEquals(CodonVariation.createInsertion(1, 0),
137                             CodonVariation.createInsertion(1, 0));
138         Assert.assertNotEquals(CodonVariation.createInsertion(0, 0),
139                                CodonVariation.createInsertion(1, 0));
140         Assert.assertNotEquals(CodonVariation.createInsertion(0, 0),
141                                CodonVariation.createInsertion(0, 1));
142         Assert.assertEquals(CodonVariation.createModification(1, 0),
143                             CodonVariation.createModification(1, 0));
144         Assert.assertNotEquals(CodonVariation.createModification(0, 0),
145                                CodonVariation.createModification(1, 0));
146         Assert.assertNotEquals(CodonVariation.createModification(0, 0),
147                                CodonVariation.createModification(0, 1));
148 
149         Assert.assertEquals(CodonVariation.createDeletion(1).hashCode(), CodonVariation.createDeletion(1).hashCode());
150         Assert.assertNotEquals(CodonVariation.createDeletion(0).hashCode(), CodonVariation.createDeletion(1).hashCode());
151         Assert.assertEquals(CodonVariation.createFrameshift(1).hashCode(), CodonVariation.createFrameshift(1).hashCode());
152         Assert.assertNotEquals(CodonVariation.createFrameshift(0).hashCode(), CodonVariation.createFrameshift(1).hashCode());
153         Assert.assertNotEquals(CodonVariation.createFrameshift(0).hashCode(), CodonVariation.createDeletion(0).hashCode());
154         Assert.assertEquals(CodonVariation.createInsertion(1, 0).hashCode(),
155                 CodonVariation.createInsertion(1, 0).hashCode());
156         Assert.assertNotEquals(CodonVariation.createInsertion(0, 0).hashCode(),
157                 CodonVariation.createInsertion(1, 0).hashCode());
158         Assert.assertNotEquals(CodonVariation.createInsertion(0, 0).hashCode(),
159                 CodonVariation.createInsertion(0, 1).hashCode());
160         Assert.assertEquals(CodonVariation.createModification(1, 0).hashCode(),
161                 CodonVariation.createModification(1, 0).hashCode());
162         Assert.assertNotEquals(CodonVariation.createModification(0, 0).hashCode(),
163                 CodonVariation.createModification(1, 0).hashCode());
164         Assert.assertNotEquals(CodonVariation.createModification(0, 0).hashCode(),
165                 CodonVariation.createModification(0, 1).hashCode());
166     }
167 
168     @Test
testEncodingModifications()169     public void testEncodingModifications() {
170         // no SNVs implies no codon variations
171         Assert.assertTrue(localCodonTracker.encodeSNVsAsCodons(Collections.emptyList()).isEmpty());
172 
173         // changes outside the ORF shouldn't produce codon variations
174         Assert.assertTrue(localCodonTracker
175                 .encodeSNVsAsCodons(Collections.singletonList(new SNV(1, CALL_C, CALL_G, QUAL_30)))
176                 .isEmpty());
177         Assert.assertTrue(localCodonTracker
178                 .encodeSNVsAsCodons(Collections.singletonList(new SNV(6, CALL_G, CALL_A, QUAL_30)))
179                 .isEmpty());
180         Assert.assertTrue(localCodonTracker
181                 .encodeSNVsAsCodons(Collections.singletonList(new SNV(12, CALL_T, CALL_C, QUAL_30)))
182                 .isEmpty());
183 
184         // changes to a single codon should produce a single-codon variations
185         Assert.assertEquals(
186                 localCodonTracker.encodeSNVsAsCodons(Collections.singletonList(new SNV(2, CALL_A, CALL_C, QUAL_30))),
187                 Collections.singletonList(CodonVariation.createModification(0, 30)));
188         Assert.assertEquals(
189                 localCodonTracker.encodeSNVsAsCodons(Collections.singletonList(new SNV(5, CALL_C, CALL_G, QUAL_30))),
190                 Collections.singletonList(CodonVariation.createModification(1, 45)));
191         Assert.assertEquals(
192                 localCodonTracker.encodeSNVsAsCodons(Collections.singletonList(new SNV(7, CALL_T, CALL_G, QUAL_30))),
193                 Collections.singletonList(CodonVariation.createModification(1, 25)));
194         Assert.assertEquals(
195                 localCodonTracker.encodeSNVsAsCodons(Collections.singletonList(new SNV(8, CALL_C, CALL_A, QUAL_30))),
196                 Collections.singletonList(CodonVariation.createModification(1, 28)));
197         Assert.assertEquals(
198                 localCodonTracker.encodeSNVsAsCodons(Collections.singletonList(new SNV(11, CALL_G, CALL_A, QUAL_30))),
199                 Collections.singletonList(CodonVariation.createModification(2, 48)));
200         Assert.assertEquals(
201                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
202                         new SNV(5, CALL_C, CALL_G, QUAL_30),
203                         new SNV(7, CALL_T, CALL_G, QUAL_30),
204                         new SNV(8, CALL_C, CALL_A, QUAL_30))),
205                 Collections.singletonList(CodonVariation.createModification(1, 40)));
206 
207         // even if the change produces a nonsense codon
208         Assert.assertEquals(
209                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
210                         new SNV(5, CALL_C, CALL_T, QUAL_30),
211                         new SNV(7, CALL_T, CALL_A, QUAL_30),
212                         new SNV(8, CALL_C, CALL_A, QUAL_30))),
213                 Collections.singletonList(CodonVariation.createModification(1, 48)));
214     }
215 
216     @Test
testEncodingDeletions()217     public void testEncodingDeletions() {
218         Assert.assertEquals(
219                 localCodonTracker.encodeSNVsAsCodons(Collections.singletonList(new SNV(2, CALL_A, NO_CALL, QUAL_30))),
220                 Arrays.asList(
221                         CodonVariation.createFrameshift(0),
222                         CodonVariation.createModification(0, 57),
223                         CodonVariation.createModification(1, 55),
224                         CodonVariation.createModification(2, 11)));
225         Assert.assertEquals(
226                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
227                         new SNV(10, CALL_A, NO_CALL, QUAL_30),
228                         new SNV(12, CALL_T, NO_CALL, QUAL_30))),
229                 Arrays.asList(
230                         CodonVariation.createFrameshift(2),
231                         CodonVariation.createModification(2, 56)));
232         Assert.assertEquals(
233                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
234                         new SNV(5, CALL_C, NO_CALL, QUAL_30),
235                         new SNV(7, CALL_T, NO_CALL, QUAL_30),
236                         new SNV(8, CALL_C, NO_CALL, QUAL_30))),
237                 Collections.singletonList(CodonVariation.createDeletion(1)));
238         Assert.assertEquals(
239                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
240                         new SNV(3, CALL_T, NO_CALL, QUAL_30),
241                         new SNV(5, CALL_C, NO_CALL, QUAL_30),
242                         new SNV(8, CALL_C, NO_CALL, QUAL_30))),
243                 Arrays.asList(
244                         CodonVariation.createModification(0, 11),
245                         CodonVariation.createDeletion(1)));
246 
247     }
248 
249     @Test
testEncodingInsertions()250     public void testEncodingInsertions() {
251         Assert.assertEquals(
252                 localCodonTracker.encodeSNVsAsCodons(Collections.singletonList(
253                         new SNV(5, NO_CALL, CALL_T, QUAL_30))),
254                 Arrays.asList(
255                         CodonVariation.createFrameshift(1),
256                         CodonVariation.createModification(1, 55),
257                         CodonVariation.createModification(2, 28)));
258         Assert.assertEquals(
259                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
260                         new SNV(2, NO_CALL, CALL_T, QUAL_30),
261                         new SNV(2, NO_CALL, CALL_T, QUAL_30),
262                         new SNV(2, NO_CALL, CALL_T, QUAL_30))),
263                 Collections.emptyList());
264         Assert.assertEquals(
265                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
266                         new SNV(5, NO_CALL, CALL_T, QUAL_30),
267                         new SNV(5, NO_CALL, CALL_T, QUAL_30),
268                         new SNV(5, NO_CALL, CALL_T, QUAL_30))),
269                 Collections.singletonList(
270                         CodonVariation.createInsertion(1, 63)));
271         Assert.assertEquals(
272                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
273                         new SNV(4, NO_CALL, CALL_G, QUAL_30),
274                         new SNV(4, NO_CALL, CALL_C, QUAL_30),
275                         new SNV(4, NO_CALL, CALL_T, QUAL_30),
276                         new SNV(4, NO_CALL, CALL_G, QUAL_30),
277                         new SNV(4, NO_CALL, CALL_C, QUAL_30),
278                         new SNV(4, NO_CALL, CALL_T, QUAL_30))),
279                 Arrays.asList(
280                         CodonVariation.createInsertion(1, 30),
281                         CodonVariation.createInsertion(1, 30)));
282     }
283 
284     @Test
testFrameRecoveringIndels()285     public void testFrameRecoveringIndels() {
286         Assert.assertEquals(
287                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
288                         new SNV(3, CALL_T, NO_CALL, QUAL_30),
289                         new SNV(7, NO_CALL, CALL_A, QUAL_30))),
290                 Arrays.asList(
291                         CodonVariation.createModification(0, 9),
292                         CodonVariation.createModification(1, 13)));
293         Assert.assertEquals(
294                 localCodonTracker.encodeSNVsAsCodons(Arrays.asList(
295                         new SNV(3, NO_CALL, CALL_T, QUAL_30),
296                         new SNV(7, CALL_T, NO_CALL, QUAL_30))),
297                 Arrays.asList(
298                         CodonVariation.createModification(0, 15),
299                         CodonVariation.createModification(1, 37)));
300     }
301 
302     @Test
testWildTypeCodonCounts()303     public void testWildTypeCodonCounts() {
304         final CodonTracker codonTracker = new CodonTracker(orfCoords, refSeq, logger);
305         codonTracker.reportWildCodonCounts(new Interval(0, 17));
306         codonTracker.reportWildCodonCounts(new Interval(0, 17));
307         final int[] wildTypeCodonValues = codonTracker.getRefCodonValues();
308         final long[][] codonCounts = codonTracker.getCodonCounts();
309         for ( int codonId = 0; codonId != wildTypeCodonValues.length; ++codonId ) {
310             final long[] row = codonCounts[codonId];
311             final int wtValue = wildTypeCodonValues[codonId];
312             for ( int codonValue = 0; codonValue != 64; ++codonValue ) {
313                 Assert.assertEquals(row[codonValue], codonValue==wtValue ? 2 : 0);
314             }
315         }
316         codonTracker.reportWildCodonCounts(new Interval(6, 12));
317         Assert.assertEquals(codonCounts[1][wildTypeCodonValues[1]], 2);
318         Assert.assertEquals(codonCounts[2][wildTypeCodonValues[2]], 3);
319     }
320 
321     @Test
testVariantCodonCounts()322     public void testVariantCodonCounts() {
323         final CodonTracker codonTracker = new CodonTracker(orfCoords, refSeq, null);
324         codonTracker.reportVariantCodonCounts(new Interval(0, 17), Arrays.asList(
325                 CodonVariation.createModification(0, 0),
326                 CodonVariation.createModification(1, 1),
327                 CodonVariation.createDeletion(1),
328                 CodonVariation.createInsertion(2, 2),
329                 CodonVariation.createFrameshift(2),
330                 CodonVariation.createModification(2, 6)));
331         final long[][] codonCounts = codonTracker.getCodonCounts();
332         Assert.assertEquals(codonCounts[0][0], 1);
333         Assert.assertEquals(codonCounts[1][1], 1);
334         Assert.assertEquals(codonCounts[1][CodonTracker.FRAME_PRESERVING_INDEL_INDEX], 1);
335         Assert.assertEquals(codonCounts[2][6], 1);
336         Assert.assertEquals(codonCounts[2][CodonTracker.FRAME_PRESERVING_INDEL_INDEX], 1);
337         Assert.assertEquals(codonCounts[2][CodonTracker.FRAME_SHIFTING_INDEL_INDEX], 1);
338         Assert.assertEquals(Arrays.stream(codonCounts).mapToLong(row -> Arrays.stream(row).sum()).sum(), 6L);
339     }
340 
341     @Test
testWildTypeCodonValuesAndExons()342     public void testWildTypeCodonValuesAndExons() {
343         final List<Interval> exons = CodonTracker.getExons(orfCoords, refSeq.length);
344         Assert.assertEquals(exons, Arrays.asList(new Interval(2, 6), new Interval(7, 12)));
345         final int[] expectedCodonValues = {14, 29, 50};
346         Assert.assertTrue(Arrays.equals(CodonTracker.parseReferenceIntoCodons(refSeq, exons, null), expectedCodonValues));
347     }
348 
349     @Test
testFindFrameShift()350     public void testFindFrameShift() {
351         Assert.assertEquals(
352                 localCodonTracker.findFrameShift(Collections.singletonList(new SNV(1, CALL_A, NO_CALL, QUAL_30))),
353                 NO_FRAME_SHIFT_CODON);
354         Assert.assertEquals(
355                 localCodonTracker.findFrameShift(Collections.singletonList(new SNV(2, CALL_A, NO_CALL, QUAL_30))),
356                 0);
357         Assert.assertEquals(
358                 localCodonTracker.findFrameShift(Collections.singletonList(new SNV(4, NO_CALL, CALL_C, QUAL_30))),
359                 0);
360         Assert.assertEquals(
361                 localCodonTracker.findFrameShift(Collections.singletonList(new SNV(6, CALL_G, NO_CALL, QUAL_30))),
362                 NO_FRAME_SHIFT_CODON);
363         Assert.assertEquals(
364                 localCodonTracker.findFrameShift(Collections.singletonList(new SNV(12, NO_CALL, CALL_C, QUAL_30))),
365                 NO_FRAME_SHIFT_CODON);
366         Assert.assertEquals(
367                 localCodonTracker.findFrameShift(Arrays.asList(
368                         new SNV(5, CALL_C, NO_CALL, QUAL_30),
369                         new SNV(6, CALL_G, NO_CALL, QUAL_30),
370                         new SNV(7, CALL_T, NO_CALL, QUAL_30),
371                         new SNV(8, CALL_C, NO_CALL, QUAL_30))),
372                 NO_FRAME_SHIFT_CODON);
373     }
374 
375     @Test
testIsStop()376     public void testIsStop() {
377         Assert.assertFalse(CodonTracker.isStop(-1));
378         Assert.assertFalse(CodonTracker.isStop(47));
379         Assert.assertTrue(CodonTracker.isStop(48));
380         Assert.assertFalse(CodonTracker.isStop(49));
381         Assert.assertTrue(CodonTracker.isStop(50));
382         Assert.assertTrue(CodonTracker.isStop(56));
383         Assert.assertFalse(CodonTracker.isStop(57));
384         Assert.assertFalse(CodonTracker.isStop(99));
385     }
386 
387     @Test
testIsExonic()388     public void testIsExonic() {
389         Assert.assertFalse(localCodonTracker.isExonic(-1));
390         Assert.assertFalse(localCodonTracker.isExonic(0));
391         Assert.assertFalse(localCodonTracker.isExonic(1));
392         Assert.assertTrue(localCodonTracker.isExonic(2));
393         Assert.assertTrue(localCodonTracker.isExonic(3));
394         Assert.assertTrue(localCodonTracker.isExonic(4));
395         Assert.assertTrue(localCodonTracker.isExonic(5));
396         Assert.assertFalse(localCodonTracker.isExonic(6));
397         Assert.assertTrue(localCodonTracker.isExonic(7));
398         Assert.assertTrue(localCodonTracker.isExonic(8));
399         Assert.assertTrue(localCodonTracker.isExonic(9));
400         Assert.assertTrue(localCodonTracker.isExonic(10));
401         Assert.assertTrue(localCodonTracker.isExonic(11));
402         Assert.assertFalse(localCodonTracker.isExonic(12));
403         Assert.assertFalse(localCodonTracker.isExonic(99));
404     }
405 
406     @Test
testExonicBaseCount()407     public void testExonicBaseCount() {
408         Assert.assertEquals(localCodonTracker.exonicBaseIndex(-1), 0);
409         Assert.assertEquals(localCodonTracker.exonicBaseIndex(0), 0);
410         Assert.assertEquals(localCodonTracker.exonicBaseIndex(1), 0);
411         Assert.assertEquals(localCodonTracker.exonicBaseIndex(2), 0);
412         Assert.assertEquals(localCodonTracker.exonicBaseIndex(3), 1);
413         Assert.assertEquals(localCodonTracker.exonicBaseIndex(4), 2);
414         Assert.assertEquals(localCodonTracker.exonicBaseIndex(5), 3);
415         Assert.assertEquals(localCodonTracker.exonicBaseIndex(6), 4);
416         Assert.assertEquals(localCodonTracker.exonicBaseIndex(7), 4);
417         Assert.assertEquals(localCodonTracker.exonicBaseIndex(8), 5);
418         Assert.assertEquals(localCodonTracker.exonicBaseIndex(9), 6);
419         Assert.assertEquals(localCodonTracker.exonicBaseIndex(10), 7);
420         Assert.assertEquals(localCodonTracker.exonicBaseIndex(11), 8);
421         Assert.assertEquals(localCodonTracker.exonicBaseIndex(12), 9);
422         Assert.assertEquals(localCodonTracker.exonicBaseIndex(13), 9);
423         Assert.assertEquals(localCodonTracker.exonicBaseIndex(99), 9);
424     }
425 
426     @Test
testReadReportFlanks()427     public void testReadReportFlanks() {
428         final List<SNV> snvList = Collections.singletonList(new SNV(8, CALL_C, CALL_A, QUAL_30));
429         final ReadReport readReport1 =
430                 new ReadReport(Collections.singletonList(new Interval(2,15)), snvList);
431         Assert.assertTrue(readReport1.hasCleanLeftFlank(6));
432         Assert.assertFalse(readReport1.hasCleanLeftFlank(7));
433         Assert.assertTrue(readReport1.hasCleanRightFlank(6, refSeq.length));
434         Assert.assertFalse(readReport1.hasCleanRightFlank(7, refSeq.length));
435 
436         // unpenalized for going off the end of the reference
437         final ReadReport readReport2 =
438                 new ReadReport(Collections.singletonList(new Interval(0,17)), snvList);
439         Assert.assertTrue(readReport2.hasCleanLeftFlank(9));
440         Assert.assertTrue(readReport2.hasCleanRightFlank(9, refSeq.length));
441     }
442 
443     @Test
testCombiningCoverage()444     public void testCombiningCoverage() {
445         final ReadReport report1 = new ReadReport(Arrays.asList(
446                 new Interval(0, 9), new Interval(20, 40), new Interval(60,70), new Interval(100, 120)),
447                 Collections.emptyList());
448         final ReadReport report2 = new ReadReport(Arrays.asList(
449                 new Interval(17, 21), new Interval(22, 27), new Interval(38, 50), new Interval(58, 60), new Interval(70, 72)),
450                 Collections.emptyList());
451         Assert.assertEquals(new ReadReport(report1, report2).getRefCoverage(),
452                 Arrays.asList(new Interval(0, 9), new Interval(17, 50), new Interval(58, 72), new Interval(100, 120)));
453     }
454 
455     @Test
testCombiningSNVLists()456     public void testCombiningSNVLists() {
457         final List<SNV> list1 = Arrays.asList(
458                 new SNV(10, CALL_A, CALL_C, QUAL_30),
459                 new SNV(20, CALL_C, CALL_A, QUAL_30),
460                 new SNV(30, CALL_C, CALL_G, QUAL_30));
461         final List<SNV> list2 = Arrays.asList(
462                 new SNV(35, CALL_T, CALL_C, QUAL_30),
463                 new SNV(45, CALL_G, CALL_A, QUAL_30),
464                 new SNV(55, CALL_C, CALL_A, QUAL_30));
465         final ReadReport report1 = new ReadReport(Collections.singletonList(new Interval(0, 32)), list1);
466         final ReadReport report2 = new ReadReport(Collections.singletonList(new Interval(33, 60)), list2);
467         final List<SNV> combinedList = new ArrayList<>(list1);
468         combinedList.addAll(list2);
469         Assert.assertEquals(new ReadReport(report1, report2).getVariations(), combinedList);
470 
471         // region of overlap has no conflicting SNVs
472         final ReadReport report3 = new ReadReport(Collections.singletonList(new Interval(0, 35)), list1);
473         final ReadReport report4 = new ReadReport(Collections.singletonList(new Interval(33, 60)), list2);
474         Assert.assertEquals(new ReadReport(report3, report4).getVariations(), combinedList);
475 
476         // region of overlap has conflicting SNV: SNV at 35 is missing from report5
477         final ReadReport report5 = new ReadReport(Collections.singletonList(new Interval(0, 36)), list1);
478         final ReadReport report6 = new ReadReport(Collections.singletonList(new Interval(33, 60)), list2);
479         Assert.assertNull(new ReadReport(report5, report6).getVariations());
480 
481         // repair flaw above
482         final List<SNV> list1Plus = new ArrayList<>(list1);
483         list1Plus.add(new SNV(35, CALL_T, CALL_C, QUAL_10));
484         final ReadReport report7 = new ReadReport(Collections.singletonList(new Interval(0, 36)), list1Plus);
485         Assert.assertEquals(new ReadReport(report7, report6).getVariations(), combinedList);
486 
487         // now mess it up again by making the SNVs unequal
488         list1Plus.set(3, new SNV(35, CALL_T, CALL_A, QUAL_30));
489         Assert.assertNull(new ReadReport(report7, report6).getVariations());
490     }
491 
492     @Test
testPairedApplication()493     public void testPairedApplication() {
494         final byte[] longRefSeq = "TTTTTTTTTTAAAAAAAAAACCCCCCCCCCCCCCCTTTTTTTTTTGGGGGGGGGGCCCCCCCCCC".getBytes();
495         reference = new Reference(longRefSeq);
496         codonTracker = new CodonTracker("5-25", longRefSeq, logger);
497 
498         final List<SNV> list1 = Arrays.asList(
499                 new SNV(10, CALL_A, CALL_C, QUAL_30),
500                 new SNV(20, CALL_C, CALL_A, QUAL_30),
501                 new SNV(30, CALL_C, CALL_G, QUAL_30));
502         final List<SNV> list2 = Arrays.asList(
503                 new SNV(35, CALL_T, CALL_C, QUAL_30),
504                 new SNV(45, CALL_G, CALL_A, QUAL_30),
505                 new SNV(55, CALL_C, CALL_A, QUAL_30));
506 
507         final SAMFileHeader header = ArtificialReadUtils.createArtificialSamHeader();
508         final List<GATKRead> reads =
509             ArtificialReadUtils.createPair(header, "blahBlah", 150, 1, 151, true, false);
510         final GATKRead read1 = reads.get(0);
511         final GATKRead read2 = reads.get(1);
512         final ReadReport report1 = new ReadReport(Collections.singletonList(new Interval(0, 32)), list1);
513         final ReadReport report2 = new ReadReport(Collections.singletonList(new Interval(33, 60)), list2);
514         updateCountsForPair(read1, report1, read2, report2);
515 
516         // shouldn't be applied -- fails flanking bases test
517         Assert.assertEquals(reference.countSpanners(0, 32), 0);
518         Assert.assertEquals(reference.countSpanners(32, 33), 0);
519         Assert.assertEquals(reference.countSpanners(33, 60), 0);
520 
521         // only read1 should be applied
522         minFlankingLength = 1;
523         updateCountsForPair(read1, report1, read2, report2);
524         Assert.assertEquals(reference.countSpanners(0, 32), 1);
525         Assert.assertEquals(reference.countSpanners(32, 33), 0);
526         Assert.assertEquals(reference.countSpanners(33, 60), 0);
527 
528         // should be applied as one
529         final ReadReport report3 = new ReadReport(Collections.singletonList(new Interval(0, 35)), list1);
530         final ReadReport report4 = new ReadReport(Collections.singletonList(new Interval(33, 60)), list2);
531         updateCountsForPair(read1, report3, read2, report4);
532         Assert.assertEquals(reference.countSpanners(0, 32), 2);
533         Assert.assertEquals(reference.countSpanners(32, 33), 1);
534         Assert.assertEquals(reference.countSpanners(33, 60), 1);
535     }
536 
537     @Test
testCalculateTrim()538     public void testCalculateTrim() {
539         final byte BAD_Q = (byte)(minQ - 1);
540         final byte GOOD_Q = (byte)minQ;
541         final byte[] quals = new byte[100];
542         Arrays.fill(quals, BAD_Q);
543         Assert.assertEquals(calculateQualityTrim(quals).size(), 0);
544         Arrays.fill(quals, GOOD_Q);
545         Assert.assertEquals(calculateQualityTrim(quals), new Interval(0, 100));
546         quals[minLength] = BAD_Q;
547         Assert.assertEquals(calculateQualityTrim(quals), new Interval(0, 100));
548         quals[minLength - 1] = BAD_Q;
549         Assert.assertEquals(calculateQualityTrim(quals), new Interval(minLength + 1, 100));
550         quals[quals.length - minLength] = BAD_Q;
551         Assert.assertEquals(calculateQualityTrim(quals), new Interval(minLength + 1, quals.length - minLength));
552         Arrays.fill(quals, GOOD_Q);
553         for ( int idx = minLength - 1; idx < quals.length; idx += minLength ) {
554             quals[idx] = BAD_Q;
555         }
556         Assert.assertEquals(calculateQualityTrim(quals).size(), 0);
557     }
558 
559     @Test
testGetReadReport()560     public void testGetReadReport() {
561         final SAMFileHeader header =
562                 ArtificialReadUtils.createArtificialSamHeader(1, 0, 17);
563         final byte[] bases = Arrays.copyOf(refSeq, refSeq.length);
564         final byte[] quals = new byte[17];
565         Arrays.fill(quals, QUAL_30);
566         final GATKRead read = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 1,
567                                                                           bases, quals, "17M");
568         read.setMappingQuality(0);
569         reference = new Reference(refSeq);
570         Assert.assertEquals(getReadReport(read).getRefCoverage(), Collections.emptyList());
571 
572         read.setMappingQuality(60);
573         final ReadReport readReport = getReadReport(read);
574         Assert.assertEquals(readReport.getRefCoverage(), Collections.singletonList(new Interval(0, 17)));
575         Assert.assertEquals(readReport.getVariations().size(), 0);
576         read.getBasesNoCopy()[3] = CALL_A;
577         final ReadReport readReport2 = getReadReport(read);
578         Assert.assertEquals(readReport2.getVariations(),
579                 Collections.singletonList(new SNV(3, CALL_T, CALL_A, QUAL_30)));
580     }
581 
582     @Test
testFindLargeDeletions()583     public void testFindLargeDeletions() {
584         AnalyzeSaturationMutagenesis.minAltLength = 2;
585         AnalyzeSaturationMutagenesis.findLargeDels = true;
586         final SAMFileHeader header =
587                 ArtificialReadUtils.createArtificialSamHeader(1, 0, 17);
588         final byte[] bases = new byte[10];
589         System.arraycopy(refSeq, 0, bases, 0, 5);
590         System.arraycopy(refSeq, 12, bases, 5, 5);
591         final byte[] quals = new byte[10];
592         Arrays.fill(quals, QUAL_30);
593 
594         // OK: primary preceeds supplementary
595         final GATKRead read1 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 1,
596                 bases, quals, "5M5S");
597         read1.setAttribute("SA", "0,13,+,5S5M,60,0;");
598         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read1).toString(), "5M7D5M");
599 
600         // OK: supplementary preceeds primary
601         final GATKRead read2 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 13,
602                 bases, quals, "5S5M");
603         read2.setAttribute("SA", "0,1,+,5M5S,60,0;");
604         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read2).toString(), "5M7D5M");
605 
606         // too much overlap on read
607         final GATKRead read3 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 1,
608                 bases, quals, "6M4S");
609         read3.setAttribute("SA", "0,11,+,3S7M,60,0;");
610         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read3).toString(), "6M4S");
611 
612         // too far apart on read
613         final GATKRead read4 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 1,
614                 bases, quals, "3M7S");
615         read4.setAttribute("SA", "0,14,+,6S4M,60,0;");
616         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read4).toString(), "3M7S");
617 
618         // wrong strand
619         final GATKRead read5 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 1,
620                 bases, quals, "5M5S");
621         read5.setAttribute("SA", "0,13,-,5S5M,60,0;");
622         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read5).toString(), "5M5S");
623 
624         // wrong order
625         final GATKRead read6 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 13,
626                 bases, quals, "5M5S");
627         read6.setAttribute("SA", "0,1,+,5S5M,60,0;");
628         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read6).toString(), "5M5S");
629 
630         // OK: 1-base overlap on read
631         final GATKRead read7 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 1,
632                 bases, quals, "6M4S");
633         read7.setAttribute("SA", "0,13,+,5S5M,60,0;");
634         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read7).toString(), "6M7D4M");
635 
636         // OK: 1-base separation on read
637         final GATKRead read8 = ArtificialReadUtils.createArtificialRead(header, "read1", 0, 1,
638                 bases, quals, "4M6S");
639         read8.setAttribute("SA", "0,13,+,5S5M,60,0;");
640         Assert.assertEquals(AnalyzeSaturationMutagenesis.ReadReport.findLargeDeletions(read8).toString(), "4M7D6M");
641     }
642 }
643