blob: 057c790f22eedc153d1a39e6dbc33cdaa7d13dee [file] [log] [blame]
// Copyright 2016 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.generator;
import com.google.archivepatcher.generator.DefaultDeflateCompressionDiviner.DivinationResult;
import com.google.archivepatcher.shared.DefaultDeflateCompatibilityWindow;
import com.google.archivepatcher.shared.DeflateCompressor;
import com.google.archivepatcher.shared.JreDeflateParameters;
import com.google.archivepatcher.shared.MultiViewInputStreamFactory;
import com.google.archivepatcher.shared.UnitTestZipArchive;
import com.google.archivepatcher.shared.UnitTestZipEntry;
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.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* Tests for {@link DefaultDeflateCompressionDiviner}.
*/
@RunWith(JUnit4.class)
@SuppressWarnings("javadoc")
public class DefaultDeflateCompressionDivinerTest {
/**
* The object under test.
*/
private DefaultDeflateCompressionDiviner diviner = null;
/**
* Test data written to the file.
*/
private byte[] testData = null;
@Before
public void setup() {
testData = new DefaultDeflateCompatibilityWindow().getCorpus();
diviner = new DefaultDeflateCompressionDiviner();
}
/**
* Deflates the test data using the specified parameters, storing them in a temp file and
* returns the temp file created.
* @param parameters the parameters to use for deflating
* @return the temp file with the data
*/
private byte[] deflate(JreDeflateParameters parameters) throws IOException {
DeflateCompressor compressor = new DeflateCompressor();
compressor.setNowrap(parameters.nowrap);
compressor.setStrategy(parameters.strategy);
compressor.setCompressionLevel(parameters.level);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
compressor.compress(new ByteArrayInputStream(testData), buffer);
return buffer.toByteArray();
}
private static class ByteArrayInputStreamFactory
implements MultiViewInputStreamFactory<ByteArrayInputStream> {
private final byte[] data;
private final boolean supportMark;
private final boolean dieOnClose;
/**
* Create a factory the returns streams on the specified data buffer, optionally supporting
* {@link InputStream#mark(int)}.
* @param data the data buffer to return streams for
* @param supportMark whether or not to support marking
* @param dieOnClose whether or not to throw nasty exceptions on close()
*/
public ByteArrayInputStreamFactory(byte[] data, boolean supportMark, boolean dieOnClose) {
this.data = data;
this.supportMark = supportMark;
this.dieOnClose = dieOnClose;
}
@Override
public ByteArrayInputStream newStream() throws IOException {
return new ByteArrayInputStream(data) {
@Override
public boolean markSupported() {
return supportMark;
}
@Override
public void close() throws IOException {
if (dieOnClose) {
throw new IOException("brainnnnnnnnnnssssss!");
}
super.close();
}
};
}
}
@Test
public void testDivineDeflateParameters_NoMarkInputStreamFactory() throws IOException {
final JreDeflateParameters parameters = JreDeflateParameters.of(1, 0, true);
final byte[] buffer = deflate(parameters);
try {
// The factory here will NOT support mark(int), which should cause failure. Also, throw
// exceptions on close() to be extra rude.
diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(buffer, false, true));
Assert.fail("operating without a markable stream");
} catch (IllegalArgumentException expected) {
// Correct!
}
}
@Test
public void testDivineDeflateParameters_BadCloseInputStreamFactory() throws IOException {
final JreDeflateParameters parameters = JreDeflateParameters.of(1, 0, true);
final byte[] buffer = deflate(parameters);
// The factory here will produce streams that throw exceptions when close() is called.
// These exceptions should be ignored.
JreDeflateParameters result =
diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(buffer, true, true));
Assert.assertEquals(result, parameters);
}
@Test
public void testDivineDeflateParameters_JunkData() throws IOException {
final byte[] junk = new byte[] {0, 1, 2, 3, 4};
Assert.assertNull(
diviner.divineDeflateParameters(new ByteArrayInputStreamFactory(junk, true, false)));
}
@Test
public void testDivineDeflateParameters_AllValidSettings() throws IOException {
for (boolean nowrap : new boolean[] {true, false}) {
for (int strategy : new int[] {0, 1, 2}) {
for (int level : new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9}) {
JreDeflateParameters trueParameters = JreDeflateParameters.of(level, strategy, nowrap);
final byte[] buffer = deflate(trueParameters);
ByteArrayInputStreamFactory factory =
new ByteArrayInputStreamFactory(buffer, true, false);
JreDeflateParameters divinedParameters = diviner.divineDeflateParameters(factory);
Assert.assertNotNull(divinedParameters);
// TODO(andrewhayden) make *CERTAIN 100%( that strategy doesn't matter for level < 4.
if (strategy == 1 && level <= 3) {
// Strategy 1 produces identical output at levels 1, 2 and 3.
Assert.assertEquals(JreDeflateParameters.of(level, 0, nowrap), divinedParameters);
} else if (strategy == 2) {
// All levels are the same with strategy 2.
// TODO: Assert only one test gets done for this, should be the first level always.
Assert.assertEquals(nowrap, divinedParameters.nowrap);
Assert.assertEquals(strategy, divinedParameters.strategy);
} else {
Assert.assertEquals(trueParameters, divinedParameters);
}
} // End of iteration on level
} // End of iteration on strategy
} // End of iteration on nowrap
}
@Test
public void testDivineDeflateParameters_File() throws IOException {
File tempFile = File.createTempFile("ddcdt", "tmp");
tempFile.deleteOnExit();
try {
UnitTestZipArchive.saveTestZip(tempFile);
List<DivinationResult> results = diviner.divineDeflateParameters(tempFile);
Assert.assertEquals(UnitTestZipArchive.allEntriesInFileOrder.size(), results.size());
for (int x = 0; x < results.size(); x++) {
UnitTestZipEntry expected = UnitTestZipArchive.allEntriesInFileOrder.get(x);
DivinationResult actual = results.get(x);
Assert.assertEquals(expected.path, actual.minimalZipEntry.getFileName());
int expectedLevel = expected.level;
if (expectedLevel > 0) {
// Compressed entry
Assert.assertTrue(actual.minimalZipEntry.isDeflateCompressed());
Assert.assertNotNull(actual.divinedParameters);
Assert.assertEquals(expectedLevel, actual.divinedParameters.level);
Assert.assertEquals(0, actual.divinedParameters.strategy);
Assert.assertTrue(actual.divinedParameters.nowrap);
} else {
// Uncompressed entry
Assert.assertFalse(actual.minimalZipEntry.isDeflateCompressed());
Assert.assertNull(actual.divinedParameters);
}
}
} finally {
try {
tempFile.delete();
} catch (Exception ignoreD) {
// Nothing
}
}
}
}