Package net.jpountz.lz4

Source Code of net.jpountz.lz4.AbstractLZ4RoundtripTest$ByteArrayTester

package net.jpountz.lz4;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.Arrays;
import java.util.List;

import org.junit.Assert;

public abstract class AbstractLZ4RoundtripTest extends AbstractLZ4Test {

  protected static abstract class Tester<T> {
      LZ4Compressor compressor;
      LZ4FastDecompressor decompressor;
      LZ4SafeDecompressor decompressor2;
     
      abstract T copy(byte[] src);
      abstract T allocate(int len);
      abstract T slice(T src, int start, int end);
      abstract int size(T src);
      abstract void fillBuffer(T buf, byte data);
     
      abstract int compress(T src, int srcOff, int srcLen, T dst, int dstOff, int dstLen);
      abstract int decompress(T src, int srcOff, T dst, int dstOff, int dstLen);
      abstract int decompress2(T src, int srcOff, int srcLen, T dst, int dstOff);
      abstract LZ4Compressor refCompressor();
      abstract byte[] bytes(T src, int len);
    }

  protected static class ByteArrayTester extends Tester<byte[]> {
      ByteArrayTester(LZ4Compressor compressor, LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
        this.compressor = compressor;
        this.decompressor = decompressor;
        this.decompressor2 = decompressor2;
      }
     
      byte[] copy(byte[] src) {
        return Arrays.copyOf(src, src.length);
      }
 
      byte[] allocate(int len) {
        return new byte[len];
      }
 
      byte[] slice(byte[] src, int start, int end) {
        return Arrays.copyOfRange(src, start, end);
      }
 
      int size(byte[] src) {
        return src.length;
      }
 
      void fillBuffer(byte[] buf, byte data) {
        Arrays.fill(buf, data);
      }
 
      byte[] bytes(byte[] src, int len) {
        return Arrays.copyOf(src, len);
      }
 
      int compress(byte[] src, int srcOff, int srcLen, byte[] dst, int dstOff, int dstLen) {
        return compressor.compress(src, srcOff, srcLen, dst, dstOff, dstLen);
      }
      int decompress(byte[] src, int srcOff, byte[] dst, int dstOff, int dstLen) {
        return decompressor.decompress(src, srcOff, dst, dstOff, dstLen);
      }
      int decompress2(byte[] src, int srcOff, int srcLen, byte[] dst, int dstOff) {
        return decompressor2.decompress(src, srcOff, srcLen, dst, dstOff);
      }
      LZ4Compressor refCompressor() {
        if (compressor == LZ4Factory.unsafeInstance().fastCompressor()
            || compressor == LZ4Factory.safeInstance().fastCompressor()) {
          return LZ4Factory.nativeInstance().fastCompressor();
        } else if (compressor == LZ4Factory.unsafeInstance().highCompressor()
            || compressor == LZ4Factory.safeInstance().highCompressor()) {
          return LZ4Factory.nativeInstance().highCompressor();
        } else if (compressor instanceof LZ4HCJavaSafeCompressor) {
          return LZ4Factory.nativeInstance().highCompressor(((LZ4HCJavaSafeCompressor)compressor).compressionLevel);
        } else if (compressor instanceof LZ4HCJavaUnsafeCompressor) {
          return LZ4Factory.nativeInstance().highCompressor(((LZ4HCJavaUnsafeCompressor)compressor).compressionLevel);
        }
        return null;
      }
    }

  protected static abstract class ByteBufferTester extends Tester<ByteBuffer> {
      abstract ByteBuffer allocate(int len);
 
      ByteBuffer copy(byte[] src) {
        return allocate(src.length).put(src);
      }
 
      ByteBuffer slice(ByteBuffer src, int start, int end) {
        return (ByteBuffer) src.duplicate().limit(end).position(start);
      }
 
      int size(ByteBuffer src) {
        return src.capacity();
      }
 
      void fillBuffer(ByteBuffer buf, byte v) {
        for (int i = 0; i < buf.capacity(); ++i) buf.put(i, v);
      }
 
      byte[] bytes(ByteBuffer src, int len) {
        byte[] dst = new byte[len];
        slice(src, 0, len).get(dst);
        return dst;
      }
 
      int compress(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dst, int dstOff, int dstLen) {
        return compressor.compress(src, srcOff, srcLen, dst, dstOff, dstLen);
      }
      int decompress(ByteBuffer src, int srcOff, ByteBuffer dst, int dstOff, int dstLen) {
        return decompressor.decompress(src, srcOff, dst, dstOff, dstLen);
      }
      int decompress2(ByteBuffer src, int srcOff, int srcLen, ByteBuffer dst, int dstOff) {
        return decompressor2.decompress(src, srcOff, srcLen, dst, dstOff);
      }
      LZ4Compressor refCompressor() {
        return compressor;    // Will be used on byte arrays.
      }
    }

  protected static class HeapBufferTester extends ByteBufferTester {
      HeapBufferTester(LZ4Compressor compressor, LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
        this.compressor = compressor;
        this.decompressor = decompressor;
        this.decompressor2 = decompressor2;
      }
     
      ByteBuffer allocate(int size) {
        return ByteBuffer.allocate(size);
      }
    }

  protected static class DirectBufferTester extends ByteBufferTester {
      DirectBufferTester(LZ4Compressor compressor, LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
        this.compressor = compressor;
        this.decompressor = decompressor;
        this.decompressor2 = decompressor2;
      }
     
      ByteBuffer allocate(int size) {
        return ByteBuffer.allocateDirect(size);
      }
    }

  protected static class ReadOnlyHeapBufferTester extends HeapBufferTester {
    ReadOnlyHeapBufferTester(LZ4Compressor compressor, LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
      super(compressor, decompressor, decompressor2);
    }

    @Override
    ByteBuffer copy(byte[] src) {
      return super.copy(src).asReadOnlyBuffer();
    }
  }

  protected static class ReadOnlyDirectBufferTester extends DirectBufferTester {
    ReadOnlyDirectBufferTester(LZ4Compressor compressor, LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
      super(compressor, decompressor, decompressor2);
    }

    @Override
    ByteBuffer copy(byte[] src) {
      return super.copy(src).asReadOnlyBuffer();
    }
  }

  protected static class MappedBufferTester extends DirectBufferTester {
    MappedBufferTester(LZ4Compressor compressor, LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
      super(compressor, decompressor, decompressor2);
    }

    @Override
    ByteBuffer copy(byte[] src) {
      try {
        if (src.length == 0) {
          return allocate(0);
        }
        File tmp = File.createTempFile("test", ".tmp");
        tmp.deleteOnExit();
        FileOutputStream os = new FileOutputStream(tmp);
        os.write(src);
        os.close();

        @SuppressWarnings("resource")
        FileChannel channel = new RandomAccessFile(tmp, "r").getChannel();
        MappedByteBuffer buf = channel.map(MapMode.READ_ONLY, 0L, tmp.length());
        return buf;
      } catch (IOException e) {
        throw new AssertionError(e);
      }
    }
  }

  protected List<Tester<?>> getTesters(LZ4Compressor compressor,
      LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
    return Arrays.asList(
        new ByteArrayTester(compressor, decompressor, decompressor2),
        new HeapBufferTester(compressor, decompressor, decompressor2),
        new DirectBufferTester(compressor, decompressor, decompressor2),
        new ReadOnlyHeapBufferTester(compressor, decompressor, decompressor2),
        new ReadOnlyDirectBufferTester(compressor, decompressor, decompressor2),
        new MappedBufferTester(compressor, decompressor, decompressor2));
  }

  public static void assertEquals(Object expected, Object actual) {
    if (expected instanceof byte[]) {
      assertArrayEquals((byte[]) expected, (byte[]) actual);
    } else {
      Assert.assertEquals(expected, actual);
    }
  }

  public <T> void testRoundTrip(byte[] dataBytes, int off, int len,
      Tester<T> tester) {
        final T data = tester.copy(dataBytes);
        final T compressed = tester.allocate(LZ4Utils.maxCompressedLength(len));
        final int compressedLen = tester.compress(
            data, off, len,
            compressed, 0, tester.size(compressed));
     
        // try to compress with the exact compressed size
        final T compressed2 = tester.allocate(compressedLen);
        final int compressedLen2 = tester.compress(data, off, len, compressed2, 0, tester.size(compressed2));
        assertEquals(compressedLen, compressedLen2);
        assertEquals(tester.slice(compressed, 0, compressedLen), compressed2);
     
        // make sure it fails if the dest is not large enough
        final T compressed3 = tester.allocate(compressedLen-1);
        try {
          tester.compress(data, off, len, compressed3, 0, tester.size(compressed3));
          assertTrue(false);
        } catch (LZ4Exception e) {
          // OK
        }
     
        // test decompression
        final T restored = tester.allocate(len);
        assertEquals(compressedLen, tester.decompress(compressed, 0, restored, 0, len));
        assertEquals(tester.slice(data, off, off + len), restored);
     
        if (len > 0) {
          // dest is too small
          try {
            tester.decompress(compressed, 0, restored, 0, len - 1);
            assertTrue(false);
          } catch (LZ4Exception e) {
            // OK
          }
        }
     
        // dest is too large
        final T restored2 = tester.allocate(len+1);
        try {
          final int cpLen = tester.decompress(compressed, 0, restored2, 0, len + 1);
          fail("compressedLen=" + cpLen);
        } catch (LZ4Exception e) {
          // OK
        }
     
        // try decompression when only the size of the compressed buffer is known
        if (len > 0) {
          tester.fillBuffer(restored, randomByte());
          assertEquals(len, tester.decompress2(compressed, 0, compressedLen, restored, 0));
        } else {
          assertEquals(0, tester.decompress2(compressed, 0, compressedLen, tester.allocate(1), 0));
        }
     
        // over-estimated compressed length
        try {
          final int decompressedLen = tester.decompress2(compressed, 0, compressedLen + 1, tester.allocate(len + 100), 0);
          fail("decompressedLen=" + decompressedLen);
        } catch (LZ4Exception e) {
          // OK
        }
     
        // under-estimated compressed length
        try {
          final int decompressedLen = tester.decompress2(compressed, 0, compressedLen - 1, tester.allocate(len + 100), 0);
          if (!(tester.decompressor2 instanceof LZ4JNISafeDecompressor)) {
            fail("decompressedLen=" + decompressedLen);
          }
        } catch (LZ4Exception e) {
          // OK
        }
     
        // compare compression against the reference
        LZ4Compressor refCompressor = tester.refCompressor();
        if (refCompressor != null) {
          final byte[] compressed4 = new byte[refCompressor.maxCompressedLength(len)];
          final int compressedLen4 = refCompressor.compress(dataBytes, off, len, compressed4, 0, compressed4.length);
          assertCompressedArrayEquals(tester.compressor.toString(),
              Arrays.copyOf(compressed4, compressedLen4),
              tester.bytes(compressed, compressedLen));
        }
      }

  public void testRoundTrip(byte[] data, int off, int len,
      LZ4Compressor compressor, LZ4FastDecompressor decompressor, LZ4SafeDecompressor decompressor2) {
        for (Tester<?> allocator : getTesters(compressor, decompressor, decompressor2)) {
          testRoundTrip(data, off, len, allocator);
        }
      }

  public void testRoundTrip(byte[] data, int off, int len,
      LZ4Factory lz4) {
        testRoundTrip(data, off, len, lz4.fastCompressor(), lz4.fastDecompressor(), lz4.safeDecompressor());
        for (int level : Arrays.asList(1, 5, 9, 13)) { //Test compression level 1, 5, 9(default) and 13 only. Should be ok.
          testRoundTrip(data, off, len, lz4.highCompressor(level), lz4.fastDecompressor(), lz4.safeDecompressor());
        }
      }

  public void testRoundTrip(byte[] data, int off, int len) {
    for (LZ4Factory lz4 : Arrays.asList(
        LZ4Factory.nativeInstance(),
        LZ4Factory.unsafeInstance(),
        LZ4Factory.safeInstance())) {
      testRoundTrip(data, off, len, lz4);
    }
  }

  public void testRoundTrip(byte[] data) {
    testRoundTrip(data, 0, data.length);
  }

  public void testRoundTrip(String resource) throws IOException {
    final byte[] data = readResource(resource);
    testRoundTrip(data);
  }

  private static void assertCompressedArrayEquals(String message, byte[] expected,
      byte[] actual) {
        int off = 0;
        int decompressedOff = 0;
        while (true) {
          if (off == expected.length) {
            break;
          }
          final Sequence sequence1 = readSequence(expected, off);
          final Sequence sequence2 = readSequence(actual, off);
          assertEquals(message + ", off=" + off + ", decompressedOff=" + decompressedOff, sequence1, sequence2);
          off += sequence1.length;
          decompressedOff += sequence1.literalLen + sequence1.matchLen;
        }
      }

  private static Sequence readSequence(byte[] buf, int off) {
    final int start = off;
    final int token = buf[off++] & 0xFF;
    int literalLen = token >>> 4;
    if (literalLen >= 0x0F) {
      int len;
      while ((len = buf[off++] & 0xFF) == 0xFF) {
        literalLen += 0xFF;
      }
      literalLen += len;
    }
    off += literalLen;
    if (off == buf.length) {
      return new Sequence(literalLen, -1, -1, off - start);
    }
    int matchDec = (buf[off++] & 0xFF) | ((buf[off++] & 0xFF) << 8);
    int matchLen = token & 0x0F;
    if (matchLen >= 0x0F) {
      int len;
      while ((len = buf[off++] & 0xFF) == 0xFF) {
        matchLen += 0xFF;
      }
      matchLen += len;
    }
    matchLen += 4;
    return new Sequence(literalLen, matchDec, matchLen, off - start);
  }

  protected static class Sequence {
      final int literalLen, matchDec, matchLen, length;
 
      public Sequence(int literalLen, int matchDec, int matchLen, int length) {
        this.literalLen = literalLen;
        this.matchDec = matchDec;
        this.matchLen = matchLen;
        this.length = length;
      }
 
      @Override
      public String toString() {
        return "Sequence [literalLen=" + literalLen + ", matchDec=" + matchDec
            + ", matchLen=" + matchLen + "]";
      }
 
      @Override
      public int hashCode() {
        return 42;
      }
 
      @Override
      public boolean equals(Object obj) {
        if (this == obj)
          return true;
        if (obj == null)
          return false;
        if (getClass() != obj.getClass())
          return false;
        Sequence other = (Sequence) obj;
        if (literalLen != other.literalLen)
          return false;
        if (matchDec != other.matchDec)
          return false;
        if (matchLen != other.matchLen)
          return false;
        return true;
      }
 
    }

  public AbstractLZ4RoundtripTest() {
    super();
  }
}
TOP

Related Classes of net.jpountz.lz4.AbstractLZ4RoundtripTest$ByteArrayTester

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.