Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions src/test/net/jpountz/lz4/LZ4BlockStreamingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.zip.Adler32;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
Expand All @@ -39,20 +40,28 @@

public class LZ4BlockStreamingTest extends AbstractLZ4Test {

private final LZ4BlockInputStream.Builder preInitializedBuilder;
private final Consumer<LZ4BlockInputStream.Builder> decompressorConfigurer;

public LZ4BlockStreamingTest(LZ4BlockInputStream.Builder preInitializedBuilder) {
this.preInitializedBuilder = preInitializedBuilder;
public LZ4BlockStreamingTest(Consumer<LZ4BlockInputStream.Builder> decompressorConfigurer) {
this.decompressorConfigurer = decompressorConfigurer;
}

@ParametersFactory
public static Iterable<Object[]> preInitializedBuilders() {
public static Iterable<Object[]> decompressorConfigurers() {
return Arrays.asList(new Object[][] {
{ LZ4BlockInputStream.newBuilder().withDecompressor(LZ4Factory.fastestInstance().fastDecompressor()) },
{ LZ4BlockInputStream.newBuilder().withDecompressor(LZ4Factory.fastestInstance().safeDecompressor()) }
// Don't create Builder here, otherwise the same Builder instance would be used for all tests, and the
// tests would interfere with each other due to the modifications to the builder
{ (Consumer<LZ4BlockInputStream.Builder>) builder -> builder.withDecompressor(LZ4Factory.fastestInstance().fastDecompressor()) },
{ (Consumer<LZ4BlockInputStream.Builder>) builder -> builder.withDecompressor(LZ4Factory.fastestInstance().safeDecompressor()) }
Copy link
Author

@Marcono1234 Marcono1234 Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this because the previous implementation was quite error-prone: It looks like all test methods in this class used the same LZ4BlockStreamingTest instance, and therefore also the same preInitializedBuilder. Therefore tests could affect each other if they forgot to overwrite / reset all builder configurations.

This happened to me while adding this new test, and due to the usage of randomizedtesting it made the resulting test failures even non-deterministic (unless you reran with the same seed I guess?).

An alternative might be to configure this test to create a new LZ4BlockStreamingTest per test method / test execution (in case that is possible).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with junit 5 we could use @TestInstance for this… but i guess this approach is more clear, and also allows tests to create multiple streams in one test call

});
}

private LZ4BlockInputStream.Builder lz4BlockInputStreamBuilder() {
var builder = LZ4BlockInputStream.newBuilder();
decompressorConfigurer.accept(builder);
return builder;
}

// An input stream that might read less data than it is able to
class MockInputStream extends FilterInputStream {

Expand Down Expand Up @@ -220,7 +229,7 @@ public void testRoundTrip(byte[] data) throws IOException {
}
os.close();

final LZ4BlockInputStream.Builder builder = preInitializedBuilder
final LZ4BlockInputStream.Builder builder = lz4BlockInputStreamBuilder()
.withStopOnEmptyBlock(true)
.withChecksum(checksum);
InputStream is = builder.build(open(compressed.toByteArray()));
Expand Down Expand Up @@ -258,7 +267,7 @@ public void testRoundTrip(byte[] data) throws IOException {
// test skip
final int offset = data.length <= 1 ? 0 : randomInt(data.length - 1);
final int length = randomInt(data.length - offset);
is = preInitializedBuilder.build(open(compressed.toByteArray()));
is = builder.build(open(compressed.toByteArray()));
restored = new byte[length + 1000];
read = 0;
while (read < offset) {
Expand Down Expand Up @@ -301,8 +310,7 @@ public void testDoubleClose() throws IOException {
out.close();
out.close();

LZ4BlockInputStream in = preInitializedBuilder
.withChecksum(null)
LZ4BlockInputStream in = lz4BlockInputStreamBuilder()
.withStopOnEmptyBlock(true)
.build(new ByteArrayInputStream(bytes.toByteArray()));
byte[] actual = new byte[testBytes.length];
Expand Down Expand Up @@ -351,8 +359,7 @@ public void testConcatenationOfSerializedStreams() throws IOException {
System.arraycopy(bytes2, 0, concatenatedBytes, bytes1.length, bytes2.length);

// In a default behaviour, we can read the first block of the concatenated bytes only
LZ4BlockInputStream in1 = preInitializedBuilder
.withChecksum(null)
LZ4BlockInputStream in1 = lz4BlockInputStreamBuilder()
.withStopOnEmptyBlock(true)
.build(new ByteArrayInputStream(concatenatedBytes));
byte[] actual1 = new byte[128];
Expand All @@ -361,7 +368,7 @@ public void testConcatenationOfSerializedStreams() throws IOException {
in1.close();

// Check if we can read concatenated byte stream
LZ4BlockInputStream in2 = preInitializedBuilder
LZ4BlockInputStream in2 = lz4BlockInputStreamBuilder()
.withStopOnEmptyBlock(false)
.build(new ByteArrayInputStream(concatenatedBytes));
byte[] actual2 = new byte[128];
Expand All @@ -371,4 +378,29 @@ public void testConcatenationOfSerializedStreams() throws IOException {

assertArrayEquals(expected, actual2);
}

@Test
public void testCorruptedStream() {
byte[] bytesWrongCompressed = {
76, 90, 52, 66, 108, 111, 99, 107, 32,
// Compressed length
6, 0, 0, 0, // malformed, should be 5
// Decompressed length
4, 0, 0, 0,
-125, -47, -30, 10, 64, 0, 1, 2, 3, 76, 90, 52, 66, 108, 111, 99, 107, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
var e = assertThrows(IOException.class, () -> lz4BlockInputStreamBuilder().build(new ByteArrayInputStream(bytesWrongCompressed)).readAllBytes());
assertEquals("Stream is corrupted", e.getMessage());

byte[] bytesWrongDecompressed = {
76, 90, 52, 66, 108, 111, 99, 107, 32,
// Compressed length
5, 0, 0, 0,
// Decompressed length
5, 0, 0, 0, // malformed, should be 4
-125, -47, -30, 10, 64, 0, 1, 2, 3, 76, 90, 52, 66, 108, 111, 99, 107, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
e = assertThrows(IOException.class, () -> lz4BlockInputStreamBuilder().build(new ByteArrayInputStream(bytesWrongDecompressed)).readAllBytes());
assertEquals("Stream is corrupted", e.getMessage());
}
}