blob: ff3d39fdc249656d1b91cb664c305a62acb587c9 [file] [log] [blame]
// 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);
}
}