package picard.illumina.parser.readers; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import picard.PicardException; import picard.illumina.parser.BclData; import java.io.File; import java.util.Collection; import java.util.LinkedList; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class BclReaderTest { public static final File TestDataDir = new File("testdata/picard/illumina/readerTests"); public static final File PASSING_BCL_FILE = new File(TestDataDir, "bcl_passing.bcl"); public static final File QUAL_0FAILING_BCL_FILE = new File(TestDataDir, "bcl_failing.bcl"); public static final File QUAL_1FAILING_BCL_FILE = new File(TestDataDir, "bcl_failing2.bcl"); public static final File FILE_TOO_LONG = new File(TestDataDir, "bcl_tooLong.bcl"); public static final File FILE_TOO_SHORT = new File(TestDataDir, "bcl_tooShort.bcl"); public static final char[] expectedBases = new char[]{ 'C', 'A', 'A', 'A', 'T', 'C', 'T', 'G', 'T', 'A', 'A', 'G', 'C', 'C', 'A', 'A', 'C', 'A', 'C', 'C', 'A', 'A', 'C', 'G', 'A', 'T', 'A', 'C', 'A', 'A', 'C', 'A', 'T', 'G', 'C', 'A', 'C', 'A', 'A', 'C', 'G', 'C', 'A', 'A', 'G', 'T', 'G', 'C', 'A', 'C', 'G', 'T', 'A', 'C', 'A', 'A', 'C', 'G', 'C', 'A', 'C', 'A', 'T', 'T', 'T', 'A', 'A', 'G', 'C', 'G', 'T', 'C', 'A', 'T', 'G', 'A', 'G', 'C', 'T', 'C', 'T', 'A', 'C', 'G', 'A', 'A', 'C', 'C', 'C', 'A', 'T', 'A', 'T', 'G', 'G', 'G', 'C', 'T', 'G', 'A', 'A', '.', '.', 'G', 'A', 'C', 'C', 'G', 'T', 'A', 'C', 'A', 'G', 'T', 'G', 'T', 'A', '.' }; public static final int[] expectedQuals = new int[]{ 18, 29, 8, 17, 27, 25, 28, 27, 9, 29, 8, 20, 25, 24, 27, 27, 30, 8, 19, 24, 29, 29, 25, 28, 8, 29, 26, 24, 29, 8, 18, 8, 29, 28, 26, 29, 25, 8, 26, 25, 28, 25, 8, 28, 28, 27, 29, 26, 25, 26, 27, 25, 8, 18, 8, 26, 24, 29, 25, 8, 24, 8, 25, 27, 27, 25, 8, 28, 24, 27, 25, 25, 8, 27, 25, 8, 16, 24, 28, 25, 28, 8, 24, 27, 25, 8, 20, 29, 24, 27, 28, 8, 23, 10, 23, 11, 15, 11, 10, 12, 12, 2, 2, 31, 24, 8, 4, 36, 12, 17, 21, 4, 8, 12, 18, 23, 27, 2 }; public byte[] qualsAsBytes() { final byte[] byteVals = new byte[expectedQuals.length]; for (int i = 0; i < byteVals.length; i++) { byteVals[i] = (byte) expectedQuals[i]; } return byteVals; } @Test public void readValidFile() { final BclQualityEvaluationStrategy bclQualityEvaluationStrategy = new BclQualityEvaluationStrategy(BclQualityEvaluationStrategy.ILLUMINA_ALLEGED_MINIMUM_QUALITY); final BclReader reader = new BclReader(PASSING_BCL_FILE, bclQualityEvaluationStrategy, false); final byte[] quals = qualsAsBytes(); Assert.assertEquals(reader.numClustersPerCycle[0], expectedBases.length); int readNum = 0; while (readNum < reader.numClustersPerCycle[0]) { final BclData bv = reader.next(); Assert.assertEquals(bv.bases[0][0], expectedBases[readNum], " On num cluster: " + readNum); Assert.assertEquals(bv.qualities[0][0], quals[readNum], " On num cluster: " + readNum); ++readNum; } bclQualityEvaluationStrategy.assertMinimumQualities(); reader.close(); } @DataProvider(name = "failingFiles") public Object[][] failingFiles() { return new Object[][]{ {QUAL_0FAILING_BCL_FILE}, {QUAL_1FAILING_BCL_FILE}, {new File(TestDataDir, "SomeNoneExistentFile.bcl")}, {FILE_TOO_LONG}, {FILE_TOO_SHORT} }; } @Test(expectedExceptions = PicardException.class, dataProvider = "failingFiles") public void failingFileTest(final File failingFile) { final BclQualityEvaluationStrategy bclQualityEvaluationStrategy = new BclQualityEvaluationStrategy(BclQualityEvaluationStrategy.ILLUMINA_ALLEGED_MINIMUM_QUALITY); final BclReader reader = new BclReader(failingFile, bclQualityEvaluationStrategy, false); Assert.assertEquals(reader.numClustersPerCycle[0], expectedBases.length); while (reader.hasNext()) { reader.next(); } reader.close(); bclQualityEvaluationStrategy.assertMinimumQualities(); } /** * Asserts appropriate functionality of a quality-minimum-customized BLC reader, such that (1) if sub-Q2 qualities are found, the BCL * reader does not throw an exception, (2) sub-minimum calls are set to quality 1 and (3) sub-minimum calls are counted up properly. */ @Test public void lowQualityButPassingTest() throws ExecutionException, InterruptedException { final BclQualityEvaluationStrategy bclQualityEvaluationStrategy = new BclQualityEvaluationStrategy(1); // Build a list of callables, then submit them and check for errors. final Collection<Callable<Void>> callables = new LinkedList<Callable<Void>>(); for (int i = 0; i < 10; i++) { final boolean even_i = i % 2 == 0; callables.add(new Callable<Void>() { @Override public Void call() throws Exception { final BclReader reader = new BclReader(even_i ? QUAL_1FAILING_BCL_FILE : QUAL_0FAILING_BCL_FILE, bclQualityEvaluationStrategy, false); Assert.assertEquals(reader.numClustersPerCycle[0], expectedBases.length); while (reader.hasNext()) { reader.next(); } reader.close(); return null; } }); } final ExecutorService executorService = Executors.newFixedThreadPool(callables.size()); final Collection<Future<Void>> futures = new LinkedList<Future<Void>>(); for (final Callable<Void> callable : callables) { futures.add(executorService.submit(callable)); } for (final Future<Void> future : futures) { future.get(); } bclQualityEvaluationStrategy.assertMinimumQualities(); Assert.assertEquals((int) bclQualityEvaluationStrategy.getPoorQualityFrequencies().get((byte) 0), 25); Assert.assertEquals((int) bclQualityEvaluationStrategy.getPoorQualityFrequencies().get((byte) 1), 25); } @Test(expectedExceptions = PicardException.class) public void lowQualityAndFailingTest() throws ExecutionException, InterruptedException { final BclQualityEvaluationStrategy bclQualityEvaluationStrategy = new BclQualityEvaluationStrategy(BclQualityEvaluationStrategy.ILLUMINA_ALLEGED_MINIMUM_QUALITY); // Build a list of callables, then submit them and check for errors. final Collection<Callable<Void>> callables = new LinkedList<Callable<Void>>(); for (int i = 0; i < 10; i++) { final boolean even_i = i % 2 == 0; callables.add(new Callable<Void>() { @Override public Void call() throws Exception { final BclReader reader = new BclReader(even_i ? QUAL_1FAILING_BCL_FILE : QUAL_0FAILING_BCL_FILE, bclQualityEvaluationStrategy, false); Assert.assertEquals(reader.numClustersPerCycle[0], expectedBases.length); while (reader.hasNext()) { reader.next(); } reader.close(); return null; } }); } final ExecutorService executorService = Executors.newFixedThreadPool(callables.size()); final Collection<Future<Void>> futures = new LinkedList<Future<Void>>(); for (final Callable<Void> callable : callables) { futures.add(executorService.submit(callable)); } for (final Future<Void> future : futures) { future.get(); } Assert.assertEquals((int) bclQualityEvaluationStrategy.getPoorQualityFrequencies().get((byte) 0), 25); Assert.assertEquals((int) bclQualityEvaluationStrategy.getPoorQualityFrequencies().get((byte) 1), 25); bclQualityEvaluationStrategy.assertMinimumQualities(); } }