Fix IndexFactory.writeIndex for tabix indexes #683

Merged
merged 5 commits into from Sep 16, 2016
@@ -343,13 +343,16 @@ public void write(final LittleEndianOutputStream stream) throws IOException {
}
@Override
+ public void write(final File idxFile) throws IOException {
@lbergelson

lbergelson Sep 15, 2016

Contributor

@magicDGS Sorry, I didn't notice this before, but this would probably be cleaner as a try-with-resources instead of a try/finally, could you change it?

@magicDGS

magicDGS Sep 16, 2016

Contributor

Done

+ try(final LittleEndianOutputStream idxStream = new LittleEndianOutputStream(new BufferedOutputStream(new FileOutputStream(idxFile)))) {
+ write(idxStream);
+ }
+ }
+
+ @Override
public void writeBasedOnFeatureFile(final File featureFile) throws IOException {
if (!featureFile.isFile()) return;
- final LittleEndianOutputStream idxStream =
- new LittleEndianOutputStream(new BufferedOutputStream(new FileOutputStream(Tribble.indexFile(featureFile))));
- write(idxStream);
- idxStream.close();
-
+ write(Tribble.indexFile(featureFile));
}
public void read(final LittleEndianInputStream dis) throws IOException {
@@ -70,6 +70,14 @@
public void write(LittleEndianOutputStream stream) throws IOException;
/**
+ * Writes the index into a file.
+ *
+ * @param idxFile Where to write the index.
+ * @throws IOException if the index is unable to write to the specified file
+ */
+ public void write(final File idxFile) throws IOException;
+
+ /**
* Write an appropriately named and located Index file based on the name and location of the featureFile.
* If featureFile is not a normal file, the index will silently not be written.
* @param featureFile
@@ -41,16 +41,13 @@
import htsjdk.tribble.index.tabix.TabixIndexCreator;
import htsjdk.tribble.readers.PositionalBufferedStream;
import htsjdk.tribble.util.LittleEndianInputStream;
-import htsjdk.tribble.util.LittleEndianOutputStream;
import htsjdk.tribble.util.ParsingUtils;
import htsjdk.tribble.util.TabixUtils;
import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
@@ -288,18 +285,11 @@ public static LinearIndex createLinearIndex(final File inputFile, final FeatureC
* @param idx
* @param idxFile
* @throws IOException
+ * @deprecated use {@link Index#write(File)} instead
*/
+ @Deprecated
public static void writeIndex(final Index idx, final File idxFile) throws IOException {
- LittleEndianOutputStream stream = null;
- try {
- stream = new LittleEndianOutputStream(new BufferedOutputStream(new FileOutputStream(idxFile)));
- idx.write(stream);
- }
- finally {
- if(stream != null) {
- stream.close();
- }
- }
+ idx.write(idxFile);
}
/**
@@ -201,13 +201,10 @@ public TabixFormat getFormatSpec() {
*
* @param tabixFile Where to write the index.
*/
- public void write(final File tabixFile) {
- final LittleEndianOutputStream los = new LittleEndianOutputStream(new BlockCompressedOutputStream(tabixFile));
- try {
+ @Override
+ public void write(final File tabixFile) throws IOException {
+ try(final LittleEndianOutputStream los = new LittleEndianOutputStream(new BlockCompressedOutputStream(tabixFile))) {
write(los);
- los.close();
- } catch (final IOException e) {
- throw new TribbleException("Exception writing " + tabixFile.getAbsolutePath(), e);
}
}
@@ -134,7 +134,7 @@ public void testBedNames(final File featureFile, final IndexFactory.IndexType in
idxFile.delete();
}
final Index idx = IndexFactory.createIndex(featureFile, codec, indexType);
- IndexFactory.writeIndex(idx, idxFile);
+ idx.write(idxFile);
idxFile.deleteOnExit();
} // else let's just hope the index exists, and if so use it
@@ -25,18 +25,23 @@
import htsjdk.samtools.SAMSequenceDictionary;
import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.samtools.util.IOUtil;
import htsjdk.tribble.TestUtils;
import htsjdk.tribble.TribbleException;
import htsjdk.tribble.bed.BEDCodec;
+import htsjdk.tribble.index.linear.LinearIndex;
import htsjdk.tribble.index.tabix.TabixFormat;
import htsjdk.tribble.index.tabix.TabixIndex;
+import htsjdk.tribble.util.LittleEndianOutputStream;
import htsjdk.variant.vcf.VCFCodec;
import htsjdk.variant.vcf.VCFFileReader;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
import java.util.List;
/**
@@ -1,13 +1,23 @@
package htsjdk.tribble.index;
+import htsjdk.samtools.util.IOUtil;
+import htsjdk.tribble.FeatureCodec;
import htsjdk.tribble.TestUtils;
+import htsjdk.tribble.Tribble;
+import htsjdk.tribble.bed.BEDCodec;
import htsjdk.tribble.index.linear.LinearIndex;
+import htsjdk.tribble.index.tabix.TabixFormat;
+import htsjdk.tribble.index.tabix.TabixIndex;
+import htsjdk.tribble.util.LittleEndianOutputStream;
+import htsjdk.tribble.util.TabixUtils;
+import htsjdk.variant.vcf.VCFCodec;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -47,4 +57,41 @@ public void testMassiveQuery(final int start, final int mid, final int mid2, fin
Assert.assertTrue(allSize >= Math.max(leftSize,rightSize), "Expected size of joint query " + allSize + " to be at least >= max of left " + leftSize + " and right queries " + rightSize);
}
+
+
+ @DataProvider(name = "writeIndexData")
+ public Object[][] writeIndexData() {
+ return new Object[][]{
+ {new File("src/test/resources/htsjdk/tribble/tabix/testTabixIndex.vcf"), IndexFactory.IndexType.LINEAR, new VCFCodec()},
+ {new File("src/test/resources/htsjdk/tribble/tabix/testTabixIndex.vcf.gz"), IndexFactory.IndexType.TABIX, new VCFCodec()},
+ {new File("src/test/resources/htsjdk/tribble/test.bed"), IndexFactory.IndexType.LINEAR, new BEDCodec()}
+ };
+ }
+
+ private final static OutputStream nullOutputStrem = new OutputStream() {
+ @Override
+ public void write(int b) throws IOException { }
+ };
+
+ @Test(dataProvider = "writeIndexData")
+ public void testWriteIndex(final File inputFile, final IndexFactory.IndexType type, final FeatureCodec codec) throws Exception {
+ // temp index file for this test
+ final File tempIndex = File.createTempFile("index", (type == IndexFactory.IndexType.TABIX) ? TabixUtils.STANDARD_INDEX_EXTENSION : Tribble.STANDARD_INDEX_EXTENSION);
+ tempIndex.delete();
+ tempIndex.deleteOnExit();
+ // create the index
+ final Index index = IndexFactory.createIndex(inputFile, codec, type);
+ Assert.assertFalse(tempIndex.exists());
+ // write the index to a file
+ index.write(tempIndex);
+ Assert.assertTrue(tempIndex.exists());
+ // load the generated index
+ final Index loadedIndex = IndexFactory.loadIndex(tempIndex.getAbsolutePath());
+ // tess that the sequences and properties are the same
+ Assert.assertEquals(loadedIndex.getSequenceNames(), index.getSequenceNames());
+ Assert.assertEquals(loadedIndex.getProperties(), index.getProperties());
+ // test that write to a stream does not blows ip
+ index.write(new LittleEndianOutputStream(nullOutputStrem));
+ }
+
}
@@ -37,6 +37,7 @@
import org.testng.annotations.Test;
import java.io.File;
+import java.io.IOException;
import java.util.Iterator;
public class TabixIndexTest {
@@ -71,7 +72,7 @@ public void readWriteTest(final File tabixFile) throws Exception {
}
@Test
- public void testQueryProvidedItemsAmount() {
+ public void testQueryProvidedItemsAmount() throws IOException {
final String VCF = "src/test/resources/htsjdk/tribble/tabix/YRI.trio.2010_07.indel.sites.vcf";
// Note that we store only compressed files
final File plainTextVcfInputFile = new File(VCF);