| // Copyright 2015 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.archivepatcher.shared; |
| |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.zip.Deflater; |
| import java.util.zip.Inflater; |
| import java.util.zip.InflaterInputStream; |
| |
| /** |
| * Tests for {@link DeflateCompressor}. |
| */ |
| @RunWith(JUnit4.class) |
| @SuppressWarnings("javadoc") |
| public class DeflateCompressorTest { |
| /** |
| * Test data for compression. Uses the {@link DefaultDeflateCompatibilityWindow}'s corpus because |
| * it is already set up to produce different outputs for each compression level. |
| */ |
| private final static byte[] CONTENT = new DefaultDeflateCompatibilityWindow().getCorpus(); |
| |
| /** |
| * Helper class for storing the compressed and uncompressed form of something together. |
| */ |
| private static class Content { |
| public byte[] compressed; |
| public byte[] uncompressed; |
| } |
| |
| private DeflateCompressor compressor; |
| private ByteArrayInputStream rawContentIn; |
| private ByteArrayOutputStream compressedContentOut; |
| |
| /** |
| * Uncompress some content with Java's built-in {@link Inflater} as a sanity check against our own |
| * code. |
| * @param nowrap value to set for the nowrap parameter for the {@link Inflater} |
| * @param compressedData |
| * @return the uncompressed data as a byte array |
| * @throws IOException if anything goes wrong |
| */ |
| private byte[] uncompressWithJavaInflater(boolean nowrap, byte[] compressedData) |
| throws IOException { |
| Inflater inflater = new Inflater(nowrap); |
| InflaterInputStream inflaterIn = |
| new InflaterInputStream(new ByteArrayInputStream(compressedData), inflater); |
| byte[] buffer = new byte[32768]; |
| ByteArrayOutputStream uncompressedOut = new ByteArrayOutputStream(); |
| int numRead = 0; |
| while ((numRead = inflaterIn.read(buffer)) >= 0) { |
| uncompressedOut.write(buffer, 0, numRead); |
| } |
| return uncompressedOut.toByteArray(); |
| } |
| |
| @Before |
| public void setUp() { |
| compressor = new DeflateCompressor(); |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| } |
| |
| @Test |
| public void testCompress() throws IOException { |
| compressor.compress(rawContentIn, compressedContentOut); |
| Assert.assertTrue(compressedContentOut.size() > 0); |
| Assert.assertTrue(compressedContentOut.size() < CONTENT.length); |
| byte[] uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| } |
| |
| @Test |
| public void testCorrectDefaults() { |
| // Sanity check to ensure that defaults are as we want them to be. Arguably crufty but nobody |
| // should change these without some thought, particularly the wrapping choice should not be |
| // changed in the compressor without also changing it in the *un*compressor. |
| Assert.assertTrue(compressor.isNowrap()); |
| Assert.assertEquals(Deflater.DEFAULT_COMPRESSION, compressor.getCompressionLevel()); |
| Assert.assertEquals(Deflater.DEFAULT_STRATEGY, compressor.getStrategy()); |
| } |
| |
| @Test |
| public void testNowrap() throws IOException { |
| // Start with nowrap 'on' (should be the default) |
| Assert.assertTrue(compressor.isNowrap()); |
| compressor.compress(rawContentIn, compressedContentOut); |
| byte[] compressedWithNowrapOn = compressedContentOut.toByteArray(); |
| byte[] uncompressedWithNowrapOn = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedWithNowrapOn); |
| Assert.assertArrayEquals(CONTENT, uncompressedWithNowrapOn); |
| |
| // Now twiddle nowrap to 'off' and do it again. |
| compressor.setNowrap(false); |
| Assert.assertFalse(compressor.isNowrap()); |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| compressor.compress(rawContentIn, compressedContentOut); |
| byte[] compressedWithNowrapOff = compressedContentOut.toByteArray(); |
| Assert.assertFalse(compressedWithNowrapOn.length == compressedWithNowrapOff.length); |
| byte[] uncompressedWithNowrapOff = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedWithNowrapOff); |
| Assert.assertArrayEquals(CONTENT, uncompressedWithNowrapOff); |
| } |
| |
| @Test |
| public void testStrategy() throws IOException { |
| // Compression level has to be > 2 to get different output out of strategies 0 and 1. |
| compressor.setCompressionLevel(9); |
| |
| // Compress with all valid strategies to ensure they all work. |
| Content[] content = new Content[3]; |
| for (int strategy = 0; strategy <= 2; strategy++) { |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| compressor.setStrategy(strategy); |
| Assert.assertEquals(strategy, compressor.getStrategy()); |
| compressor.compress(rawContentIn, compressedContentOut); |
| content[strategy] = new Content(); |
| content[strategy].compressed = compressedContentOut.toByteArray(); |
| content[strategy].uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), content[strategy].compressed); |
| Assert.assertArrayEquals(CONTENT, content[strategy].uncompressed); |
| } |
| |
| // No two outputs should be the same. |
| for (int outer = 0; outer < content.length; outer++) { |
| for (int inner = 0; inner < content.length; inner++) { |
| if (inner != outer) { |
| Assert.assertFalse( |
| "strategy " + outer + " == " + inner, |
| Arrays.equals(content[outer].compressed, content[inner].compressed)); |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testCompressionLevel() throws IOException { |
| // Compress at all levels to ensure they all work. |
| Content[] content = new Content[10]; // Note that level 0 (store) is not used. |
| for (int level = 1; level <= 9; level++) { |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| compressor.setCompressionLevel(level); |
| Assert.assertEquals(level, compressor.getCompressionLevel()); |
| compressor.compress(rawContentIn, compressedContentOut); |
| content[level] = new Content(); |
| content[level].compressed = compressedContentOut.toByteArray(); |
| content[level].uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), content[level].compressed); |
| Assert.assertArrayEquals(CONTENT, content[level].uncompressed); |
| } |
| |
| // No two outputs should be the same. Again note that level 0 (store) is unused, so start at 1. |
| for (int outer = 1; outer < content.length; outer++) { |
| for (int inner = 1; inner < content.length; inner++) { |
| if (inner != outer) { |
| Assert.assertFalse( |
| "strategy " + outer + " == " + inner, |
| Arrays.equals(content[outer].compressed, content[inner].compressed)); |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testSetInputBufferSize() throws IOException { |
| Assert.assertNotEquals(17, compressor.getInputBufferSize()); // Ensure test is valid |
| compressor.setInputBufferSize(17); // Arbitrary non-default value |
| Assert.assertEquals(17, compressor.getInputBufferSize()); |
| compressor.compress(rawContentIn, compressedContentOut); |
| byte[] uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| } |
| |
| @Test |
| public void testSetOutputBufferSize() throws IOException { |
| Assert.assertNotEquals(17, compressor.getOutputBufferSize()); // Ensure test is valid |
| compressor.setOutputBufferSize(17); // Arbitrary non-default value |
| Assert.assertEquals(17, compressor.getOutputBufferSize()); |
| compressor.compress(rawContentIn, compressedContentOut); |
| byte[] uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| } |
| |
| @Test |
| public void testCreateOrResetDeflater_Uncached() { |
| compressor.setCaching(false); |
| Deflater deflater1 = compressor.createOrResetDeflater(); |
| Deflater deflater2 = compressor.createOrResetDeflater(); |
| Assert.assertNotSame(deflater1, deflater2); |
| } |
| |
| @Test |
| public void testCreateOrResetDeflater_Cached() { |
| compressor.setCaching(true); |
| Deflater deflater1 = compressor.createOrResetDeflater(); |
| Deflater deflater2 = compressor.createOrResetDeflater(); |
| Assert.assertSame(deflater1, deflater2); |
| } |
| |
| @Test |
| public void testRelease() { |
| compressor.setCaching(true); |
| Deflater deflater1 = compressor.createOrResetDeflater(); |
| compressor.release(); |
| Deflater deflater2 = compressor.createOrResetDeflater(); |
| Assert.assertNotSame(deflater1, deflater2); |
| } |
| |
| @Test |
| public void testReusability() throws IOException { |
| // Checks that the compressor produces correct output when cached, i.e. that it is being |
| // properly reset between runs. |
| compressor.setCaching(true); |
| compressor.compress(rawContentIn, compressedContentOut); |
| byte[] uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| |
| // Caching is on, try to reuse it without any changes. |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| compressor.compress(rawContentIn, compressedContentOut); |
| uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| |
| // Caching is still on, tweak the compression level and try again. |
| Assert.assertNotEquals(7, compressor.getCompressionLevel()); // Ensure test is valid |
| compressor.setCompressionLevel(7); |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| compressor.compress(rawContentIn, compressedContentOut); |
| uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| |
| // Caching is still on, tweak the strategy and try again. |
| Assert.assertNotEquals(1, compressor.getStrategy()); // Ensure test is valid |
| compressor.setStrategy(Deflater.FILTERED); |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| compressor.compress(rawContentIn, compressedContentOut); |
| uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| |
| // Caching is still on, reverse the wrapping style and try again. Changing the wrapping style |
| // invalidates the cached compressor because the wrapping style cannot be changed, this is a |
| // special code path we need to exercise. |
| compressor.setNowrap(!compressor.isNowrap()); |
| rawContentIn = new ByteArrayInputStream(CONTENT); |
| compressedContentOut = new ByteArrayOutputStream(); |
| compressor.compress(rawContentIn, compressedContentOut); |
| uncompressed = |
| uncompressWithJavaInflater(compressor.isNowrap(), compressedContentOut.toByteArray()); |
| Assert.assertArrayEquals(CONTENT, uncompressed); |
| } |
| } |