Skip to content

Commit

Permalink
working on adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lbergelson committed Dec 1, 2022
1 parent 1239e98 commit 6c059a6
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 40 deletions.
11 changes: 6 additions & 5 deletions src/main/java/htsjdk/tribble/index/AbstractIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
Expand Down Expand Up @@ -302,10 +303,10 @@ private void writeHeader(final LittleEndianOutputStream dos) throws IOException
private void readHeader(final LittleEndianInputStream dis) throws IOException {

version = dis.readInt();
indexedPath = IOUtil.getPath(dis.readString());
indexedPath = IOUtil.getPath(dis.readString(StandardCharsets.US_ASCII));
indexedFileSize = dis.readLong();
indexedFileTS = dis.readLong();
indexedFileMD5 = dis.readString();
indexedFileMD5 = dis.readString(StandardCharsets.US_ASCII);
flags = dis.readInt();
if (version < 3 && (flags & SEQUENCE_DICTIONARY_FLAG) == SEQUENCE_DICTIONARY_FLAG) {
readSequenceDictionary(dis);
Expand All @@ -314,8 +315,8 @@ private void readHeader(final LittleEndianInputStream dis) throws IOException {
if (version >= 3) {
int nProperties = dis.readInt();
while (nProperties-- > 0) {
final String key = dis.readString();
final String value = dis.readString();
final String key = dis.readString(StandardCharsets.US_ASCII);
final String value = dis.readString(StandardCharsets.US_ASCII);
properties.put(key, value);
}
}
Expand All @@ -332,7 +333,7 @@ private void readSequenceDictionary(final LittleEndianInputStream dis) throws IO
final int size = dis.readInt();
if (size < 0) throw new IllegalStateException("Size of the sequence dictionary entries is negative");
for (int x = 0; x < size; x++) {
dis.readString();
dis.readString(StandardCharsets.US_ASCII);
dis.readInt();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -210,7 +211,7 @@ public void read(final LittleEndianInputStream dis) throws IOException {

tree = new IntervalTree();

name = dis.readString();
name = dis.readString(StandardCharsets.US_ASCII);
int nIntervals = dis.readInt();
while (nIntervals-- > 0) {

Expand Down
27 changes: 20 additions & 7 deletions src/main/java/htsjdk/tribble/util/LittleEndianInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;


/**
Expand Down Expand Up @@ -105,22 +107,33 @@ public final float readFloat() throws IOException {
}

/**
* Read a null terminated byte array and return result as a string
*
* @return
* @throws IOException
* Read a null terminated byte array and return result as a String
* This method decodes theh bytes as UTF-8 string
* @throws IOException if reading from the stream fails for some reason
* @throws EOFException if the stream ends without encountering a null terminator.
* @deprecated Prefer the {@link #readString(Charset)} which allows specifying a charset explicitly
*/

@Deprecated
public String readString() throws IOException {
ByteArrayOutputStream bis = new ByteArrayOutputStream(100);
return readString(StandardCharsets.UTF_8);
}

/**
* Read a null terminated byte array and return result as a String
* @param charset the Charset to use when decoding the bytes to a String
* @throws IOException if reading from the stream fails for some reason
* @throws EOFException if the stream ends without encountering a null terminator.
*/
public String readString(final Charset charset) throws IOException {
final ByteArrayOutputStream bis = new ByteArrayOutputStream(100);
int b;
while ((b = in.read()) != 0) {
if(b < 0) {
throw new EOFException();
}
bis.write((byte)b);
}
return bis.toString();
return bis.toString(charset.name());
}


Expand Down
48 changes: 48 additions & 0 deletions src/test/java/htsjdk/testutil/TestCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package htsjdk.testutil;

import org.testng.Assert;

public interface TestCase<T> {
void test(ThrowingSupplier<T> functionToTest);


interface ThrowingConsumer<T> {
void test(T a) throws Exception;
}

static <T> TestCase<T> match(final T expected) {
return new ComparisonTestCase<>((T actual) -> Assert.assertEquals(actual, expected));
}

static <T> TestCase<T> mismatch(final T expected) {
return new ComparisonTestCase<>((T actual) -> Assert.assertNotEquals(actual, expected));
}

static <T> TestCase<T> exception(final Class<? extends Exception> exceptionClass) {
return functionToTest -> Assert.assertThrows(exceptionClass, functionToTest::produce);
}

interface ThrowingSupplier<T> {
T produce() throws Exception;
}
}

final class ComparisonTestCase<T> implements TestCase<T> {
private final ThrowingConsumer<T> test;

@Override
public void test(ThrowingSupplier<T> supplier) {
try {
test.test(supplier.produce());
} catch (AssertionError e) {
throw e;
} catch (Exception e) {
throw new AssertionError(e);
}
}

ComparisonTestCase(ThrowingConsumer<T> test) {
this.test = test;
}

}
55 changes: 28 additions & 27 deletions src/test/java/htsjdk/tribble/util/LittleEndianInputStreamTest.java
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
package htsjdk.tribble.util;

import com.google.common.io.LittleEndianDataOutputStream;
import htsjdk.HtsjdkTest;
import org.testng.Assert;
import htsjdk.testutil.TestCase;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;

import static org.testng.Assert.*;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

public class LittleEndianInputStreamTest extends HtsjdkTest {

@Test(expectedExceptions = EOFException.class)
public void testReadStringEOF() throws IOException {
final String emptyFile = "src/test/resources/htsjdk/tribble/util/string_with_extended_ascii_no_terminator.bin";
try(final LittleEndianInputStream in = new LittleEndianInputStream(new BufferedInputStream(new FileInputStream(emptyFile)))){
in.readString();
}
}

@Test
public void testReadStringWithExtendedCharacters() throws IOException {
final String emptyFile = "src/test/resources/htsjdk/tribble/util/string_with_extended_ascii_and_null_terminator.bin";
try(final LittleEndianInputStream in = new LittleEndianInputStream(new BufferedInputStream(new FileInputStream(emptyFile)))){
Assert.assertEquals(in.readString(), "very dràààààmatic and null terminated");
}
@DataProvider
public Object[][] testCases() {
final String missingTerminator = "src/test/resources/htsjdk/tribble/util/string_with_extended_ascii_no_terminator.bin";
final String extendedAsciiFile = "src/test/resources/htsjdk/tribble/util/string_with_extended_ascii_and_null_terminator.bin";
final Object utf8File = "src/test/resources/htsjdk/tribble/util/string_with_utf8_emoji_and_null_terminator.txt";
return new Object[][]{
{missingTerminator, StandardCharsets.ISO_8859_1, TestCase.exception(EOFException.class)},
{missingTerminator, StandardCharsets.US_ASCII, TestCase.exception(EOFException.class)},
{missingTerminator, StandardCharsets.UTF_8, TestCase.exception(EOFException.class)},
{extendedAsciiFile, StandardCharsets.ISO_8859_1, TestCase.match("very dràààààmatic and null terminated")},
{extendedAsciiFile, StandardCharsets.US_ASCII, TestCase.mismatch("very dràààààmatic and null terminated")},
{extendedAsciiFile, StandardCharsets.UTF_8, TestCase.mismatch("very dràààààmatic and null terminated")},
{utf8File, StandardCharsets.UTF_8, TestCase.match("🐋 UTF8 is Great 🐋")},
{utf8File, StandardCharsets.ISO_8859_1, TestCase.mismatch("🐋 UTF8 is Great 🐋")}
};
}


@Test(expectedExceptions = EOFException.class)
public void write() throws IOException {
final String emptyFile = "src/test/resources/htsjdk/tribble/util/string_with_extended_ascii_and_null_terminator.bin";
try(final LittleEndianDataOutputStream out = new LittleEndianDataOutputStream(new FileOutputStream(emptyFile))){
out.writeBytes("very dràààààmatic and null terminated\0");
}
@Test(dataProvider = "testCases")
public void testAllCases(String filename, Charset charset, TestCase<String> expected) {
expected.test(() -> {
try(final LittleEndianInputStream in = new LittleEndianInputStream(new BufferedInputStream(new FileInputStream(filename)))){
return in.readString(charset);
}
});
}

}

0 comments on commit 6c059a6

Please sign in to comment.