diff --git a/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java b/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java index 71a050b3..9e3bd504 100644 --- a/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java +++ b/src/test/java/io/usethesource/vallang/basic/BinaryIoSmokeTest.java @@ -42,6 +42,7 @@ import io.usethesource.vallang.io.binary.message.IValueWriter; import io.usethesource.vallang.io.binary.stream.IValueInputStream; import io.usethesource.vallang.io.binary.stream.IValueOutputStream; +import io.usethesource.vallang.io.binary.stream.IValueOutputStream.CompressionRate; import io.usethesource.vallang.io.binary.util.WindowSizes; import io.usethesource.vallang.io.binary.wire.IWireInputStream; import io.usethesource.vallang.io.binary.wire.IWireOutputStream; @@ -54,6 +55,16 @@ public final class BinaryIoSmokeTest extends BooleanStoreProvider { + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSingleValueIO(IValueFactory vf, TypeStore ts) throws IOException { + ioRoundTrip(vf, ts, vf.integer(1)); + } + + @ParameterizedTest @ArgumentsSource(ValueProvider.class) + public void testSingleValue2IO(IValueFactory vf, TypeStore ts) throws IOException { + ioRoundTrip(vf, ts, vf.string("a")); + } + @ParameterizedTest @ArgumentsSource(ValueProvider.class) public void testSmallBinaryIO(IValueFactory vf, TypeStore ts, IValue value) throws IOException { ioRoundTrip(vf, ts, value); @@ -203,9 +214,22 @@ public void iopRoundTrip(IValueFactory vf, TypeStore ts, Type tp) throws IOExcep } } + private final CompressionRate[] RATES_TO_TESTS = {CompressionRate.Normal, CompressionRate.Extreme, CompressionRate.None, CompressionRate.NoSharing}; + private void ioRoundTrip(IValueFactory vf, TypeStore ts, IValue value) throws IOException { + for (var rate: RATES_TO_TESTS) { + try { + ioRoundTrip(vf, ts, value, rate); + } + catch (Throwable e) { + throw new RuntimeException("Error with "+ rate + " compression", e); + } + } + } + + private void ioRoundTrip(IValueFactory vf, TypeStore ts, IValue value, IValueOutputStream.CompressionRate compression) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - try (IValueOutputStream w = new IValueOutputStream(buffer, vf, IValueOutputStream.CompressionRate.Normal)) { + try (IValueOutputStream w = new IValueOutputStream(buffer, vf, compression)) { w.write(value); } try (IValueInputStream read = new IValueInputStream(new ByteArrayInputStream(buffer.toByteArray()), vf, () -> ts)) { @@ -239,10 +263,20 @@ else if (value instanceof IConstructor) { } private void ioRoundTripFile(IValueFactory vf, TypeStore ts, IValue value) throws IOException { + for (var rate: RATES_TO_TESTS) { + try { + ioRoundTripFile(vf, ts, value, rate); + } + catch (Throwable e) { + throw new RuntimeException("Error with "+ rate + " compression", e); + } + } + } + private void ioRoundTripFile(IValueFactory vf, TypeStore ts, IValue value, IValueOutputStream.CompressionRate compression) throws IOException { long fileSize = 0; File target = File.createTempFile("valllang-test-file", "something"); target.deleteOnExit(); - try (IValueOutputStream w = new IValueOutputStream(FileChannel.open(target.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE), vf, IValueOutputStream.CompressionRate.Normal)) { + try (IValueOutputStream w = new IValueOutputStream(FileChannel.open(target.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE), vf, compression)) { w.write(value); } fileSize = Files.size(target.toPath()); @@ -261,10 +295,20 @@ private void ioRoundTripFile(IValueFactory vf, TypeStore ts, IValue value) throw } private void ioRoundTripFile2(IValueFactory vf, TypeStore ts, IValue value) throws FileNotFoundException, IOException { + for (var rate: RATES_TO_TESTS) { + try { + ioRoundTripFile2(vf, ts, value, rate); + } + catch (Throwable e) { + throw new RuntimeException("Error with "+ rate + " compression", e); + } + } + } + private void ioRoundTripFile2(IValueFactory vf, TypeStore ts, IValue value, IValueOutputStream.CompressionRate compression) throws FileNotFoundException, IOException { long fileSize = 0; File target = File.createTempFile("valllang-test-file", "something"); target.deleteOnExit(); - try (IValueOutputStream w = new IValueOutputStream(new FileOutputStream(target), vf, IValueOutputStream.CompressionRate.Normal)) { + try (IValueOutputStream w = new IValueOutputStream(new FileOutputStream(target), vf, compression)) { w.write(value); } fileSize = Files.size(target.toPath()); diff --git a/src/test/java/io/usethesource/vallang/io/FileChannelOutputStreamTest.java b/src/test/java/io/usethesource/vallang/io/FileChannelOutputStreamTest.java new file mode 100644 index 00000000..c2c8dd60 --- /dev/null +++ b/src/test/java/io/usethesource/vallang/io/FileChannelOutputStreamTest.java @@ -0,0 +1,105 @@ +package io.usethesource.vallang.io; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Random; +import org.junit.jupiter.api.Test; +import io.usethesource.vallang.io.binary.util.FileChannelDirectInputStream; +import io.usethesource.vallang.io.binary.util.FileChannelDirectOutputStream; + +class FileChannelOutputStreamTest { + private static final Path targetFile; + static { + Path file = null; + try { + file = Files.createTempFile("file-channel-test", "bin"); + } catch (IOException e) { + System.err.println(e); + } + targetFile = file; + } + + private FileChannel openWriteChannel() throws IOException { + return FileChannel.open(targetFile, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING); + } + + private FileChannel openReadChannel() throws IOException { + return FileChannel.open(targetFile, StandardOpenOption.READ); + } + + @Test + void testSimpleWrite() throws IOException { + roundTripChannel(new byte[][]{{42}}); + } + + @Test + void testBigWrite() throws IOException { + byte[] buffer = new byte[1024*1024]; + new Random().nextBytes(buffer); + roundTripChannel(new byte[][]{buffer}); + } + + @Test + void testChunkedBigWrite() throws IOException { + byte[][] buffers = new byte[1024][]; + var r = new Random(); + for (int i = 0; i < buffers.length; i++) { + buffers[i] = new byte[i * 128]; + r.nextBytes(buffers[i]); + } + roundTripChannel(buffers); + } + + + private void roundTripChannel(byte[][] buffers) throws IOException { + writeChannelInBulk(buffers); + verifyChannelInBulk(buffers); + writeChannelBytePerByte(buffers); + verifyChannelBytePerByte(buffers); + } + + private void verifyChannelBytePerByte(byte[][] buffers) throws IOException { + try (var reader = new FileChannelDirectInputStream(openReadChannel())) { + for (byte[] expected: buffers) { + for (byte expect: expected) { + assertEquals(expect & 0xFF, reader.read()); + } + } + } + } + + + private void verifyChannelInBulk(byte[][] buffers) throws IOException { + try (var reader = new FileChannelDirectInputStream(openReadChannel())) { + for (byte[] expected: buffers) { + byte[] actual = new byte[expected.length]; + reader.read(actual); + assertArrayEquals(expected, actual); + } + } + } + + private void writeChannelBytePerByte(byte[][] buffers) throws IOException { + try (var writer = new FileChannelDirectOutputStream(openWriteChannel(), 1)) { + for (byte[] buf: buffers) { + for (byte b: buf) { + writer.write(b); + } + } + } + } + + private void writeChannelInBulk(byte[][] buffers) throws IOException { + try (var writer = new FileChannelDirectOutputStream(openWriteChannel(), 1)) { + for (byte[] buf: buffers) { + writer.write(buf); + } + } + } + +}