diff --git a/src/main/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilder.java b/src/main/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilder.java index 83161734ee..ea82da5615 100644 --- a/src/main/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilder.java +++ b/src/main/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilder.java @@ -30,6 +30,7 @@ import htsjdk.samtools.util.BlockCompressedOutputStream; import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.Md5CalculatingOutputStream; +import htsjdk.samtools.util.Log; import htsjdk.samtools.util.RuntimeIOException; import htsjdk.tribble.index.IndexCreator; import htsjdk.tribble.index.tabix.TabixFormat; @@ -109,6 +110,7 @@ public class VariantContextWriterBuilder { public static final EnumSet DEFAULT_OPTIONS = EnumSet.of(Options.INDEX_ON_THE_FLY); public static final EnumSet NO_OPTIONS = EnumSet.noneOf(Options.class); private static final OpenOption[] EMPTY_OPEN_OPTION_ARRAY = new OpenOption[0]; + private static final Log log = Log.getInstance(VariantContextWriter.class); public enum OutputType { UNSPECIFIED, @@ -483,14 +485,18 @@ else if (STREAM_TYPES.contains(this.outType)) writer = createBCFWriter(outPath, outStreamFromFile); break; case VCF_STREAM: - if (options.contains(Options.INDEX_ON_THE_FLY)) - throw new IllegalArgumentException("VCF index creation not supported for stream output."); + if (options.contains(Options.INDEX_ON_THE_FLY)) { + log.warn("VCF index creation not supported for stream output, index will not be created"); + options.remove(Options.INDEX_ON_THE_FLY); + } writer = createVCFWriter(null, outStreamFromFile); break; case BCF_STREAM: - if (options.contains(Options.INDEX_ON_THE_FLY)) - throw new IllegalArgumentException("BCF index creation not supported for stream output."); + if (options.contains(Options.INDEX_ON_THE_FLY)) { + log.warn("BCF index creation not supported for stream output, index will not be created"); + options.remove(Options.INDEX_ON_THE_FLY); + } writer = createBCFWriter(null, outStream); break; diff --git a/src/test/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilderUnitTest.java b/src/test/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilderUnitTest.java index b412165319..afb844f651 100644 --- a/src/test/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilderUnitTest.java +++ b/src/test/java/htsjdk/variant/variantcontext/writer/VariantContextWriterBuilderUnitTest.java @@ -58,521 +58,504 @@ import java.util.List; public class VariantContextWriterBuilderUnitTest extends VariantBaseTest { - private static final String TEST_BASENAME = "htsjdk-test VariantContextWriterBuilderUnitTest"; - private SAMSequenceDictionary dictionary; - - private File vcf; - private File vcfIdx; - private File vcfMD5; - private File bcf; - private File bcfIdx; - private File unknown; - - private List blockCompressedVCFs; - private List blockCompressedIndices; - - @BeforeSuite - public void before() throws IOException { - dictionary = createArtificialSequenceDictionary(); - vcf = File.createTempFile(TEST_BASENAME, IOUtil.VCF_FILE_EXTENSION); - vcf.deleteOnExit(); - vcfIdx = Tribble.indexFile(vcf); - vcfIdx.deleteOnExit(); - vcfMD5 = new File(vcf.getAbsolutePath() + ".md5"); - vcfMD5.deleteOnExit(); - bcf = File.createTempFile(TEST_BASENAME, IOUtil.BCF_FILE_EXTENSION); - bcf.deleteOnExit(); - bcfIdx = Tribble.indexFile(bcf); - bcfIdx.deleteOnExit(); - unknown = File.createTempFile(TEST_BASENAME, ".unknown"); - unknown.deleteOnExit(); - - blockCompressedVCFs = new ArrayList(); - blockCompressedIndices = new ArrayList(); - for (final String extension : IOUtil.BLOCK_COMPRESSED_EXTENSIONS) { - final File blockCompressed = File.createTempFile(TEST_BASENAME, IOUtil.VCF_FILE_EXTENSION + extension); - blockCompressed.deleteOnExit(); - blockCompressedVCFs.add(blockCompressed); - - final File index = new File(blockCompressed.getAbsolutePath() + TabixUtils.STANDARD_INDEX_EXTENSION); - index.deleteOnExit(); - blockCompressedIndices.add(index); + private static final String TEST_BASENAME = "htsjdk-test VariantContextWriterBuilderUnitTest"; + private SAMSequenceDictionary dictionary; + + private File vcf; + private File vcfIdx; + private File vcfMD5; + private File bcf; + private File bcfIdx; + private File unknown; + + private List blockCompressedVCFs; + private List blockCompressedIndices; + + @BeforeSuite + public void before() throws IOException { + dictionary = createArtificialSequenceDictionary(); + vcf = File.createTempFile(TEST_BASENAME, IOUtil.VCF_FILE_EXTENSION); + vcf.deleteOnExit(); + vcfIdx = Tribble.indexFile(vcf); + vcfIdx.deleteOnExit(); + vcfMD5 = new File(vcf.getAbsolutePath() + ".md5"); + vcfMD5.deleteOnExit(); + bcf = File.createTempFile(TEST_BASENAME, IOUtil.BCF_FILE_EXTENSION); + bcf.deleteOnExit(); + bcfIdx = Tribble.indexFile(bcf); + bcfIdx.deleteOnExit(); + unknown = File.createTempFile(TEST_BASENAME, ".unknown"); + unknown.deleteOnExit(); + + blockCompressedVCFs = new ArrayList(); + blockCompressedIndices = new ArrayList(); + for (final String extension : IOUtil.BLOCK_COMPRESSED_EXTENSIONS) { + final File blockCompressed = File.createTempFile(TEST_BASENAME, IOUtil.VCF_FILE_EXTENSION + extension); + blockCompressed.deleteOnExit(); + blockCompressedVCFs.add(blockCompressed); + + final File index = new File(blockCompressed.getAbsolutePath() + TabixUtils.STANDARD_INDEX_EXTENSION); + index.deleteOnExit(); + blockCompressedIndices.add(index); + } + } + + @Test + public void testSetOutputFile() throws IOException { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary); + + VariantContextWriter writer = builder.setOutputFile(vcf.getAbsolutePath()).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile VCF String"); + Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile VCF String was compressed"); + + writer = builder.setOutputFile(vcf).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile VCF File"); + Assert.assertFalse(((VCFWriter)writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile VCF File was compressed"); + + for (final String extension : IOUtil.BLOCK_COMPRESSED_EXTENSIONS) { + final File file = File.createTempFile(TEST_BASENAME + ".setoutput", extension); + file.deleteOnExit(); + final String filename = file.getAbsolutePath(); + + writer = builder.setOutputFile(filename).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile " + extension + " String"); + Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile " + extension + " String was not compressed"); + + writer = builder.setOutputFile(file).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile " + extension + " File"); + Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile " + extension + " File was not compressed"); + } + + writer = builder.setOutputFile(bcf).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFile BCF String"); + + writer = builder.setOutputFile(bcf.getAbsolutePath()).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFile BCF File"); + } + + + @DataProvider + public Iterator getFilesAndOutputTypes(){ + List cases = new ArrayList<>(); + cases.add(new Object[]{OutputType.VCF, this.vcf}); + cases.add(new Object[]{OutputType.BCF, this.bcf}); + cases.add(new Object[]{OutputType.VCF_STREAM, new File("/dev/stdout")}); + for (final File file: this.blockCompressedVCFs) { + cases.add( new Object[]{OutputType.BLOCK_COMPRESSED_VCF, file}); + } + return cases.iterator(); + } + + @Test(dataProvider = "getFilesAndOutputTypes") + public void testDetermineOutputType(OutputType expected, File file) { + Assert.assertEquals(VariantContextWriterBuilder.determineOutputTypeFromFile(file), expected); + } + + @Test(dataProvider = "getFilesAndOutputTypes") + public void testDetermineOutputTypeWithSymlink(OutputType expected, File file) throws IOException { + final File link = setUpSymlink(file); + Assert.assertEquals(expected, VariantContextWriterBuilder.determineOutputTypeFromFile(link)); } - } - @Test - public void testSetOutputFile() throws IOException { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary); + @Test(dataProvider = "getFilesAndOutputTypes") + public void testDetermineOutputTypeOnPath(OutputType expected, File file) { + Assert.assertEquals(VariantContextWriterBuilder.determineOutputTypeFromFile(file.toPath()), expected); + } + + @Test(dataProvider = "getFilesAndOutputTypes") + public void testDetermineOutputTypeWithSymlinkOnPath(OutputType expected, File file) throws IOException { + final File link = setUpSymlink(file); + Assert.assertEquals(expected, VariantContextWriterBuilder.determineOutputTypeFromFile(link.toPath())); + } + + private static File setUpSymlink(File target) throws IOException { + final Path link = Files.createTempFile("foo.", ".tmp"); + Files.deleteIfExists(link); + Files.createSymbolicLink(link, target.toPath()); + link.toFile().deleteOnExit(); + return link.toFile(); + } + + @Test + public void testSetOutputFileType() { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOutputFile(unknown); + + VariantContextWriter writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.VCF).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFileType VCF"); + Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFileType VCF was compressed"); + + writer = builder.setOption(Options.FORCE_BCF).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFileType FORCE_BCF set -> expected BCF, was VCF"); + + // test that FORCE_BCF remains in effect, overriding the explicit setting of VCF + writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.VCF).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFileType FORCE_BCF set 2 -> expected BCF, was VCF"); + + writer = builder.unsetOption(Options.FORCE_BCF).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFileType FORCE_BCF unset -> expected VCF, was BCF"); + Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFileType FORCE_BCF unset was compressed"); + + writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.BLOCK_COMPRESSED_VCF).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile BLOCK_COMPRESSED_VCF"); + Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFileType BLOCK_COMPRESSED_VCF was not compressed"); + + writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.BCF).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFileType BCF"); + } + + @Test + public void testSetOutputStream() { + final OutputStream stream = new ByteArrayOutputStream(); + + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .unsetOption(Options.INDEX_ON_THE_FLY) + .setOutputStream(stream); + + VariantContextWriter writer = builder.build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputStream default"); + + writer = builder.setOption(Options.FORCE_BCF).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputStream FORCE_BCF set -> expected BCF stream, was VCF stream"); + + // test that FORCE_BCF remains in effect, overriding the explicit setting of VCF + writer = builder.setOutputVCFStream(stream).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputStream FORCE_BCF set 2 -> expected BCF stream, was VCF stream"); - VariantContextWriter writer = builder.setOutputFile(vcf.getAbsolutePath()).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile VCF String"); - Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile VCF String was compressed"); + writer = builder.unsetOption(Options.FORCE_BCF).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputStream FORCE_BCF unset -> expected VCF stream, was BCF stream"); - writer = builder.setOutputFile(vcf).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile VCF File"); - Assert.assertFalse(((VCFWriter)writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile VCF File was compressed"); + writer = builder.setOutputBCFStream(stream).build(); + Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputStream BCF"); - for (final String extension : IOUtil.BLOCK_COMPRESSED_EXTENSIONS) { - final File file = File.createTempFile(TEST_BASENAME + ".setoutput", extension); - file.deleteOnExit(); - final String filename = file.getAbsolutePath(); + writer = builder.setOutputVCFStream(stream).build(); + Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputStream VCF"); + } + + @Test + public void testAsync() { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOutputFile(vcf); + + VariantContextWriter writer = builder.build(); + Assert.assertEquals(writer instanceof AsyncVariantContextWriter, Defaults.USE_ASYNC_IO_WRITE_FOR_TRIBBLE, "testAsync default"); - writer = builder.setOutputFile(filename).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile " + extension + " String"); - Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile " + extension + " String was not compressed"); + writer = builder.setOption(Options.USE_ASYNC_IO).build(); + Assert.assertTrue(writer instanceof AsyncVariantContextWriter, "testAsync option=set"); - writer = builder.setOutputFile(file).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile " + extension + " File"); - Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFile " + extension + " File was not compressed"); + writer = builder.unsetOption(Options.USE_ASYNC_IO).build(); + Assert.assertFalse(writer instanceof AsyncVariantContextWriter, "testAsync option=unset"); } - writer = builder.setOutputFile(bcf).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFile BCF String"); + @Test + public void testBuffering() { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOutputFile(vcf) + .unsetOption(Options.INDEX_ON_THE_FLY); // so the potential BufferedOutputStream is not wrapped in a PositionalOutputStream - writer = builder.setOutputFile(bcf.getAbsolutePath()).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFile BCF File"); - } + VariantContextWriter writer = builder.build(); + Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BufferedOutputStream, "testBuffering was not buffered by default"); + writer = builder.unsetBuffering().build(); + Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BufferedOutputStream, "testBuffering was buffered when unset"); - @DataProvider - public Iterator getFilesAndOutputTypes(){ - List cases = new ArrayList<>(); - cases.add(new Object[]{OutputType.VCF, this.vcf}); - cases.add(new Object[]{OutputType.BCF, this.bcf}); - cases.add(new Object[]{OutputType.VCF_STREAM, new File("/dev/stdout")}); - for (final File file: this.blockCompressedVCFs) { - cases.add( new Object[]{OutputType.BLOCK_COMPRESSED_VCF, file}); + writer = builder.setBuffer(8192).build(); + Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BufferedOutputStream, "testBuffering was not buffered when set"); } - return cases.iterator(); - } - - @Test(dataProvider = "getFilesAndOutputTypes") - public void testDetermineOutputType(OutputType expected, File file) { - Assert.assertEquals(VariantContextWriterBuilder.determineOutputTypeFromFile(file), expected); - } - - @Test(dataProvider = "getFilesAndOutputTypes") - public void testDetermineOutputTypeWithSymlink(OutputType expected, File file) throws IOException { - final File link = setUpSymlink(file); - Assert.assertEquals(expected, VariantContextWriterBuilder.determineOutputTypeFromFile(link)); - } - - @Test(dataProvider = "getFilesAndOutputTypes") - public void testDetermineOutputTypeOnPath(OutputType expected, File file) { - Assert.assertEquals(VariantContextWriterBuilder.determineOutputTypeFromFile(file.toPath()), expected); - } - - @Test(dataProvider = "getFilesAndOutputTypes") - public void testDetermineOutputTypeWithSymlinkOnPath(OutputType expected, File file) throws IOException { - final File link = setUpSymlink(file); - Assert.assertEquals(expected, VariantContextWriterBuilder.determineOutputTypeFromFile(link.toPath())); - } - - private static File setUpSymlink(File target) throws IOException { - final Path link = Files.createTempFile("foo.", ".tmp"); - Files.deleteIfExists(link); - Files.createSymbolicLink(link, target.toPath()); - link.toFile().deleteOnExit(); - return link.toFile(); - } - - @Test - public void testSetOutputFileType() { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputFile(unknown); - - VariantContextWriter writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.VCF).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFileType VCF"); - Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFileType VCF was compressed"); - - writer = builder.setOption(Options.FORCE_BCF).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFileType FORCE_BCF set -> expected BCF, was VCF"); - - // test that FORCE_BCF remains in effect, overriding the explicit setting of VCF - writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.VCF).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFileType FORCE_BCF set 2 -> expected BCF, was VCF"); - - writer = builder.unsetOption(Options.FORCE_BCF).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFileType FORCE_BCF unset -> expected VCF, was BCF"); - Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFileType FORCE_BCF unset was compressed"); - - writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.BLOCK_COMPRESSED_VCF).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputFile BLOCK_COMPRESSED_VCF"); - Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BlockCompressedOutputStream, "testSetOutputFileType BLOCK_COMPRESSED_VCF was not compressed"); - - writer = builder.setOutputFileType(VariantContextWriterBuilder.OutputType.BCF).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputFileType BCF"); - } - - @Test - public void testSetOutputStream() { - final OutputStream stream = new ByteArrayOutputStream(); - - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .unsetOption(Options.INDEX_ON_THE_FLY) - .setOutputStream(stream); - - VariantContextWriter writer = builder.build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputStream default"); - - writer = builder.setOption(Options.FORCE_BCF).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputStream FORCE_BCF set -> expected BCF stream, was VCF stream"); - - // test that FORCE_BCF remains in effect, overriding the explicit setting of VCF - writer = builder.setOutputVCFStream(stream).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputStream FORCE_BCF set 2 -> expected BCF stream, was VCF stream"); - - writer = builder.unsetOption(Options.FORCE_BCF).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputStream FORCE_BCF unset -> expected VCF stream, was BCF stream"); - - writer = builder.setOutputBCFStream(stream).build(); - Assert.assertTrue(writer instanceof BCF2Writer, "testSetOutputStream BCF"); - - writer = builder.setOutputVCFStream(stream).build(); - Assert.assertTrue(writer instanceof VCFWriter, "testSetOutputStream VCF"); - } - - @Test - public void testAsync() { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputFile(vcf); - - VariantContextWriter writer = builder.build(); - Assert.assertEquals(writer instanceof AsyncVariantContextWriter, Defaults.USE_ASYNC_IO_WRITE_FOR_TRIBBLE, "testAsync default"); - - writer = builder.setOption(Options.USE_ASYNC_IO).build(); - Assert.assertTrue(writer instanceof AsyncVariantContextWriter, "testAsync option=set"); - - writer = builder.unsetOption(Options.USE_ASYNC_IO).build(); - Assert.assertFalse(writer instanceof AsyncVariantContextWriter, "testAsync option=unset"); - } - - @Test - public void testBuffering() { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputFile(vcf) - .unsetOption(Options.INDEX_ON_THE_FLY); // so the potential BufferedOutputStream is not wrapped in a PositionalOutputStream - - VariantContextWriter writer = builder.build(); - Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BufferedOutputStream, "testBuffering was not buffered by default"); - - writer = builder.unsetBuffering().build(); - Assert.assertFalse(((VCFWriter) writer).getOutputStream() instanceof BufferedOutputStream, "testBuffering was buffered when unset"); - - writer = builder.setBuffer(8192).build(); - Assert.assertTrue(((VCFWriter) writer).getOutputStream() instanceof BufferedOutputStream, "testBuffering was not buffered when set"); - } - - @Test - public void testMD5() { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputFile(vcf); - - VariantContextWriter writer = builder.build(); - writer.close(); - Assert.assertEquals(vcfMD5.exists(), Defaults.CREATE_MD5, "MD5 default setting not respected"); - - if (vcfMD5.exists()) - vcfMD5.delete(); - - writer = builder.setCreateMD5().build(); - writer.close(); - Assert.assertTrue(vcfMD5.exists(), "MD5 not created when requested"); - vcfMD5.delete(); - - writer = builder.unsetCreateMD5().build(); - writer.close(); - Assert.assertFalse(vcfMD5.exists(), "MD5 created when not requested"); - - writer = builder.setCreateMD5(false).build(); - writer.close(); - Assert.assertFalse(vcfMD5.exists(), "MD5 created when not requested via boolean parameter"); - - writer = builder.setCreateMD5(true).build(); - writer.close(); - Assert.assertTrue(vcfMD5.exists(), "MD5 not created when requested via boolean parameter"); - vcfMD5.delete(); - - for (final File blockCompressed : blockCompressedVCFs) { - final File md5 = new File(blockCompressed + ".md5"); - if (md5.exists()) - md5.delete(); - md5.deleteOnExit(); - writer = builder.setOutputFile(blockCompressed).build(); - writer.close(); - Assert.assertTrue(md5.exists(), "MD5 digest not created for " + blockCompressed); + + @Test + public void testMD5() { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOutputFile(vcf); + + VariantContextWriter writer = builder.build(); + writer.close(); + Assert.assertEquals(vcfMD5.exists(), Defaults.CREATE_MD5, "MD5 default setting not respected"); + + if (vcfMD5.exists()) + vcfMD5.delete(); + + writer = builder.setCreateMD5().build(); + writer.close(); + Assert.assertTrue(vcfMD5.exists(), "MD5 not created when requested"); + vcfMD5.delete(); + + writer = builder.unsetCreateMD5().build(); + writer.close(); + Assert.assertFalse(vcfMD5.exists(), "MD5 created when not requested"); + + writer = builder.setCreateMD5(false).build(); + writer.close(); + Assert.assertFalse(vcfMD5.exists(), "MD5 created when not requested via boolean parameter"); + + writer = builder.setCreateMD5(true).build(); + writer.close(); + Assert.assertTrue(vcfMD5.exists(), "MD5 not created when requested via boolean parameter"); + vcfMD5.delete(); + + for (final File blockCompressed : blockCompressedVCFs) { + final File md5 = new File(blockCompressed + ".md5"); + if (md5.exists()) + md5.delete(); + md5.deleteOnExit(); + writer = builder.setOutputFile(blockCompressed).build(); + writer.close(); + Assert.assertTrue(md5.exists(), "MD5 digest not created for " + blockCompressed); + } } - } - - @Test - public void testIndexingOnTheFly() { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOption(Options.INDEX_ON_THE_FLY); - - if (vcfIdx.exists()) - vcfIdx.delete(); - VariantContextWriter writer = builder.setOutputFile(vcf).build(); - writer.close(); - Assert.assertTrue(vcfIdx.exists(), String.format("VCF index not created for %s / %s", vcf, vcfIdx)); - - if (bcfIdx.exists()) - bcfIdx.delete(); - writer = builder.setOutputFile(bcf).build(); - writer.close(); - Assert.assertTrue(bcfIdx.exists(), String.format("BCF index not created for %s / %s", bcf, bcfIdx)); - - for (int i = 0; i < blockCompressedVCFs.size(); i++) { - final File blockCompressed = blockCompressedVCFs.get(i); - final File index = blockCompressedIndices.get(i); - if (index.exists()) - index.delete(); - writer = builder.setOutputFile(blockCompressed).setReferenceDictionary(dictionary).build(); - writer.close(); - Assert.assertTrue(index.exists(), String.format("Block-compressed index not created for %s / %s", blockCompressed, index)); - - // Tabix does not require a reference dictionary. - // Tribble does: see tests testRefDictRequiredForVCFIndexOnTheFly / testRefDictRequiredForBCFIndexOnTheFly - - index.delete(); - writer = builder.setReferenceDictionary(null).build(); - writer.close(); - Assert.assertTrue(index.exists(), String.format("Block-compressed index not created for %s / %s", blockCompressed, index)); + + @Test + public void testIndexingOnTheFly() { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOption(Options.INDEX_ON_THE_FLY); + + if (vcfIdx.exists()) + vcfIdx.delete(); + VariantContextWriter writer = builder.setOutputFile(vcf).build(); + writer.close(); + Assert.assertTrue(vcfIdx.exists(), String.format("VCF index not created for %s / %s", vcf, vcfIdx)); + + if (bcfIdx.exists()) + bcfIdx.delete(); + writer = builder.setOutputFile(bcf).build(); + writer.close(); + Assert.assertTrue(bcfIdx.exists(), String.format("BCF index not created for %s / %s", bcf, bcfIdx)); + + for (int i = 0; i < blockCompressedVCFs.size(); i++) { + final File blockCompressed = blockCompressedVCFs.get(i); + final File index = blockCompressedIndices.get(i); + if (index.exists()) + index.delete(); + writer = builder.setOutputFile(blockCompressed).setReferenceDictionary(dictionary).build(); + writer.close(); + Assert.assertTrue(index.exists(), String.format("Block-compressed index not created for %s / %s", blockCompressed, index)); + + // Tabix does not require a reference dictionary. + // Tribble does: see tests testRefDictRequiredForVCFIndexOnTheFly / testRefDictRequiredForBCFIndexOnTheFly + + index.delete(); + writer = builder.setReferenceDictionary(null).build(); + writer.close(); + Assert.assertTrue(index.exists(), String.format("Block-compressed index not created for %s / %s", blockCompressed, index)); + } } - } - - @Test - public void testIndexingOnTheFlyForPath() throws IOException { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOption(Options.INDEX_ON_THE_FLY); - - try (FileSystem fs = Jimfs.newFileSystem("test", Configuration.unix())) { - final Path vcfPath = fs.getPath(vcf.getName()); - final Path vcfIdxPath = Tribble.indexPath(vcfPath); - try(final VariantContextWriter writer = builder.setOutputPath(vcfPath).build()) - { - //deliberately empty - } - - Assert.assertTrue(Files.exists(vcfIdxPath), - String.format("VCF index not created for %s / %s", vcfPath, vcfIdxPath)); - - final Path bcfPath = fs.getPath(bcf.getName()); - final Path bcfIdxPath = Tribble.indexPath(bcfPath); - try(final VariantContextWriter writer = builder.setOutputPath(bcfPath).build()){ - //deliberately empty - } - Assert.assertTrue(Files.exists(bcfIdxPath), - String.format("BCF index not created for %s / %s", bcfPath, bcfIdxPath)); - - for (int i = 0; i < blockCompressedVCFs.size(); i++) { - final File blockCompressed = blockCompressedVCFs.get(i); - final File index = blockCompressedIndices.get(i); - - final Path blockCompressedPath = fs.getPath(blockCompressed.getName()); - final Path indexPath = fs.getPath(index.getName()); - - Assert.assertFalse(Files.exists(indexPath)); - try(VariantContextWriter writer = builder.setOutputPath(blockCompressedPath).setReferenceDictionary(dictionary).build()){ - //deliberately empty + + @Test + public void testIndexingOnTheFlyForPath() throws IOException { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOption(Options.INDEX_ON_THE_FLY); + + try (FileSystem fs = Jimfs.newFileSystem("test", Configuration.unix())) { + final Path vcfPath = fs.getPath(vcf.getName()); + final Path vcfIdxPath = Tribble.indexPath(vcfPath); + try(final VariantContextWriter writer = builder.setOutputPath(vcfPath).build()) + { + //deliberately empty + } + + Assert.assertTrue(Files.exists(vcfIdxPath), + String.format("VCF index not created for %s / %s", vcfPath, vcfIdxPath)); + + final Path bcfPath = fs.getPath(bcf.getName()); + final Path bcfIdxPath = Tribble.indexPath(bcfPath); + try(final VariantContextWriter writer = builder.setOutputPath(bcfPath).build()){ + //deliberately empty + } + Assert.assertTrue(Files.exists(bcfIdxPath), + String.format("BCF index not created for %s / %s", bcfPath, bcfIdxPath)); + + for (int i = 0; i < blockCompressedVCFs.size(); i++) { + final File blockCompressed = blockCompressedVCFs.get(i); + final File index = blockCompressedIndices.get(i); + + final Path blockCompressedPath = fs.getPath(blockCompressed.getName()); + final Path indexPath = fs.getPath(index.getName()); + + Assert.assertFalse(Files.exists(indexPath)); + try(VariantContextWriter writer = builder.setOutputPath(blockCompressedPath).setReferenceDictionary(dictionary).build()){ + //deliberately empty + } + Assert.assertTrue(Files.exists(indexPath), String + .format("Block-compressed index not created for %s / %s", blockCompressedPath, indexPath)); + + // Tabix does not require a reference dictionary. + // Tribble does: see tests testRefDictRequiredForVCFIndexOnTheFly / testRefDictRequiredForBCFIndexOnTheFly + Files.delete(indexPath); + try (VariantContextWriter writer = builder.setReferenceDictionary(null).build()){ + //deliberately empty + } + Assert.assertTrue(Files.exists(indexPath), String + .format("Block-compressed index not created for %s / %s", blockCompressedPath, indexPath)); + } } - Assert.assertTrue(Files.exists(indexPath), String - .format("Block-compressed index not created for %s / %s", blockCompressedPath, indexPath)); - - // Tabix does not require a reference dictionary. - // Tribble does: see tests testRefDictRequiredForVCFIndexOnTheFly / testRefDictRequiredForBCFIndexOnTheFly - Files.delete(indexPath); - try (VariantContextWriter writer = builder.setReferenceDictionary(null).build()){ - //deliberately empty + } + + @Test(singleThreaded = true, groups = "unix") + public void testWriteToFifo() throws IOException, InterruptedException, ExecutionException { + long length = testWriteToPipe(this::innerWriteToFifo); + // length>0 means we wrote to the named pipe, so all is well. + Assert.assertTrue(length>0, + "VariantContextWriterBuilder did not write to the named pipe as it should."); + } + + private void innerWriteToFifo(String pathToFifo) { + // Do not enable INDEX_OF_THE_FLY because that is not compatible with writing to a pipe. + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() + .clearOptions() + .setReferenceDictionary(dictionary); + + Path vcfPath = Paths.get(pathToFifo); + VariantContextWriter writer = builder.setOutputPath(vcfPath).build(); + writer.writeHeader(new VCFHeader()); + writer.close(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidImplicitFileType() { + new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOutputFile("test.bam") + .build(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testSetInvalidFileType() { + new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOutputFile("test.bam") + .setOutputFileType(VariantContextWriterBuilder.OutputType.VCF_STREAM) + .build(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testInvalidSetFileTypeForStream() { + new VariantContextWriterBuilder() + .setReferenceDictionary(dictionary) + .setOutputStream(new ByteArrayOutputStream()) + .setOutputFileType(VariantContextWriterBuilder.OutputType.VCF) + .build(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testRefDictRequiredForVCFIndexOnTheFly() { + new VariantContextWriterBuilder() + .setOutputFile(vcf) + .setOption(Options.INDEX_ON_THE_FLY) + .build(); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testRefDictRequiredForBCFIndexOnTheFly() { + new VariantContextWriterBuilder() + .setOutputFile(bcf) + .setOption(Options.INDEX_ON_THE_FLY) + .build(); + } + + @Test + public void testClearOptions() { + // Verify that clearOptions doesn't have a side effect of carrying previously set options + // forward to subsequent builders + VariantContextWriterBuilder vcwb = new VariantContextWriterBuilder(); + vcwb.clearOptions().setOption(Options.INDEX_ON_THE_FLY); + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder().clearOptions(); + Assert.assertTrue(builder.options.isEmpty()); + } + + @Test + public void testModifyOption() { + final VariantContextWriterBuilder builder = new VariantContextWriterBuilder().clearOptions(); + for (final Options option : Options.values()) { + Assert.assertFalse(builder.isOptionSet(option)); // shouldn't be set + builder.modifyOption(option, false); + Assert.assertFalse(builder.isOptionSet(option)); // still shouldn't be set + builder.modifyOption(option, true); + Assert.assertTrue(builder.isOptionSet(option)); // now is set + builder.modifyOption(option, false); + Assert.assertFalse(builder.isOptionSet(option)); // has been unset } - Assert.assertTrue(Files.exists(indexPath), String - .format("Block-compressed index not created for %s / %s", blockCompressedPath, indexPath)); - } } - } - - @Test(singleThreaded = true, groups = "unix") - public void testWriteToFifo() throws IOException, InterruptedException, ExecutionException { - long length = testWriteToPipe(this::innerWriteToFifo); - // length>0 means we wrote to the named pipe, so all is well. - Assert.assertTrue(length>0, - "VariantContextWriterBuilder did not write to the named pipe as it should."); - } - - private void innerWriteToFifo(String pathToFifo) { - // Do not enable INDEX_OF_THE_FLY because that is not compatible with writing to a pipe. - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder() - .clearOptions() - .setReferenceDictionary(dictionary); - - Path vcfPath = Paths.get(pathToFifo); - VariantContextWriter writer = builder.setOutputPath(vcfPath).build(); - writer.writeHeader(new VCFHeader()); - writer.close(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalidImplicitFileType() { - new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputFile("test.bam") - .build(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testSetInvalidFileType() { - new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputFile("test.bam") - .setOutputFileType(VariantContextWriterBuilder.OutputType.VCF_STREAM) - .build(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testInvalidSetFileTypeForStream() { - new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputStream(new ByteArrayOutputStream()) - .setOutputFileType(VariantContextWriterBuilder.OutputType.VCF) - .build(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testUnsupportedIndexOnTheFlyForStreaming() { - new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputStream(new ByteArrayOutputStream()) - .setOption(Options.INDEX_ON_THE_FLY) - .build(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testUnsupportedDefaultIndexOnTheFlyForStreaming() { - new VariantContextWriterBuilder() - .setReferenceDictionary(dictionary) - .setOutputStream(new ByteArrayOutputStream()) - .build(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testRefDictRequiredForVCFIndexOnTheFly() { - new VariantContextWriterBuilder() - .setOutputFile(vcf) - .setOption(Options.INDEX_ON_THE_FLY) - .build(); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testRefDictRequiredForBCFIndexOnTheFly() { - new VariantContextWriterBuilder() - .setOutputFile(bcf) - .setOption(Options.INDEX_ON_THE_FLY) - .build(); - } - - @Test - public void testClearOptions() { - // Verify that clearOptions doesn't have a side effect of carrying previously set options - // forward to subsequent builders - VariantContextWriterBuilder vcwb = new VariantContextWriterBuilder(); - vcwb.clearOptions().setOption(Options.INDEX_ON_THE_FLY); - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder().clearOptions(); - Assert.assertTrue(builder.options.isEmpty()); - } - - @Test - public void testModifyOption() { - final VariantContextWriterBuilder builder = new VariantContextWriterBuilder().clearOptions(); - for (final Options option : Options.values()) { - Assert.assertFalse(builder.isOptionSet(option)); // shouldn't be set - builder.modifyOption(option, false); - Assert.assertFalse(builder.isOptionSet(option)); // still shouldn't be set - builder.modifyOption(option, true); - Assert.assertTrue(builder.isOptionSet(option)); // now is set - builder.modifyOption(option, false); - Assert.assertFalse(builder.isOptionSet(option)); // has been unset + + @Test + public void testStdOut() { + final VariantContextWriter writer = new VariantContextWriterBuilder().setOutputFile("/dev/stdout").clearOptions().build(); + OutputStream s = ((VCFWriter) writer).getOutputStream(); + Assert.assertNotNull(((VCFWriter) writer).getOutputStream()); + Assert.assertNotEquals(((VCFWriter) writer).getStreamName(), IndexingVariantContextWriter.DEFAULT_READER_NAME); + } + + @Test(expectedExceptions = java.util.concurrent.ExecutionException.class) + public void demonstrateTestWriteToPipeDoesNotHang_1() throws Exception { + testWriteToPipe((str) -> { + throw new RuntimeException("oops"); + }); } - } - - @Test - public void testStdOut() { - final VariantContextWriter writer = new VariantContextWriterBuilder().setOutputFile("/dev/stdout").clearOptions().build(); - OutputStream s = ((VCFWriter) writer).getOutputStream(); - Assert.assertNotNull(((VCFWriter) writer).getOutputStream()); - Assert.assertNotEquals(((VCFWriter) writer).getStreamName(), IndexingVariantContextWriter.DEFAULT_READER_NAME); - } - - @Test(expectedExceptions = java.util.concurrent.ExecutionException.class) - public void demonstrateTestWriteToPipeDoesNotHang_1() throws Exception { - testWriteToPipe((str) -> { - throw new RuntimeException("oops"); - }); - } - - @Test(expectedExceptions = java.util.concurrent.ExecutionException.class) - public void demonstrateTestWriteToPipeDoesNotHang_2() throws Exception { - long x = testWriteToPipe((str) -> {try{Files.write(Paths.get(str), "hello world".getBytes());}catch(IOException ex){}; throw new RuntimeException("oops");}); - } - - - /** - * Create a named pipe, call "codeThatWritesToAFilename" with the name as argument, - * consumes the output as it's being run and returns the number of bytes that were output. - * - * This only works on Unix. Use this decoration for the tests that use it: - * @Test(singleThreaded = true, groups = "unix") - */ - private static long testWriteToPipe(final Consumer codeThatWritesToAFilename) throws IOException, InterruptedException, ExecutionException { - final File fifo = makeFifo(); - - // run the code in a separate thread - ExecutorService executor = Executors.newFixedThreadPool(2); - try { - final Future writeResult = executor.submit(() -> { + + @Test(expectedExceptions = java.util.concurrent.ExecutionException.class) + public void demonstrateTestWriteToPipeDoesNotHang_2() throws Exception { + long x = testWriteToPipe((str) -> {try{Files.write(Paths.get(str), "hello world".getBytes());}catch(IOException ex){}; throw new RuntimeException("oops");}); + } + + + /** + * Create a named pipe, call "codeThatWritesToAFilename" with the name as argument, + * consumes the output as it's being run and returns the number of bytes that were output. + * + * This only works on Unix. Use this decoration for the tests that use it: + * @Test(singleThreaded = true, groups = "unix") + */ + private static long testWriteToPipe(final Consumer codeThatWritesToAFilename) throws IOException, InterruptedException, ExecutionException { + final File fifo = makeFifo(); + + // run the code in a separate thread + ExecutorService executor = Executors.newFixedThreadPool(2); try { - codeThatWritesToAFilename.accept(fifo.getAbsolutePath()); - } catch (Exception x) { - // Print to the console to aid debugging, in case the exception doesn't surface. - x.printStackTrace(); - throw(x); + final Future writeResult = executor.submit(() -> { + try { + codeThatWritesToAFilename.accept(fifo.getAbsolutePath()); + } catch (Exception x) { + // Print to the console to aid debugging, in case the exception doesn't surface. + x.printStackTrace(); + throw(x); + } + }); + + // drain the pipe with the output. + final Future readResult = executor.submit(() -> { + try(final InputStream inputStream = Files.newInputStream(fifo.toPath(), StandardOpenOption.READ)) { + int count = 0; + while (inputStream.read() >= 0) { + count++; + } + return count; + } + }); + + // done. If it was in error, the line below will throw the exception. + writeResult.get(); + return readResult.get(); + } finally { + executor.shutdownNow(); } - }); - - // drain the pipe with the output. - final Future readResult = executor.submit(() -> { - try(final InputStream inputStream = Files.newInputStream(fifo.toPath(), StandardOpenOption.READ)) { - int count = 0; - while (inputStream.read() >= 0) { - count++; - } - return count; - } - }); + } - // done. If it was in error, the line below will throw the exception. - writeResult.get(); - return readResult.get(); - } finally { - executor.shutdownNow(); + private static File makeFifo() throws IOException, InterruptedException { + // make the fifo + final File fifo = File.createTempFile("fifo.for.testWriteToPipe", ""); + Assert.assertTrue(fifo.delete()); + fifo.deleteOnExit(); + final Process exec = new ProcessBuilder("mkfifo", fifo.getAbsolutePath()).start(); + exec.waitFor(1, TimeUnit.MINUTES); + Assert.assertEquals(exec.exitValue(), 0, "mkfifo failed with exit code " + 0); + return fifo; } - } - - private static File makeFifo() throws IOException, InterruptedException { - // make the fifo - final File fifo = File.createTempFile("fifo.for.testWriteToPipe", ""); - Assert.assertTrue(fifo.delete()); - fifo.deleteOnExit(); - final Process exec = new ProcessBuilder("mkfifo", fifo.getAbsolutePath()).start(); - exec.waitFor(1, TimeUnit.MINUTES); - Assert.assertEquals(exec.exitValue(), 0, "mkfifo failed with exit code " + 0); - return fifo; - } }