blob: 989aa4ddf5737a65f84571e4109b0b59cc3dfed3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.compress.archivers.sevenz;
import static org.junit.Assert.*;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import org.apache.commons.compress.AbstractTestCase;
import org.tukaani.xz.LZMA2Options;
public class SevenZOutputFileTest extends AbstractTestCase {
private static final boolean XZ_BCJ_IS_BUGGY;
static {
final String version = org.tukaani.xz.XZ.class.getPackage().getImplementationVersion();
XZ_BCJ_IS_BUGGY=version.equals("1.4");
if (XZ_BCJ_IS_BUGGY) {
System.out.println("XZ version is " + version + " - skipping BCJ tests");
}
}
private File output;
@Override
public void tearDown() throws Exception {
if (output != null && !output.delete()) {
output.deleteOnExit();
}
super.tearDown();
}
@Test
public void testDirectoriesAndEmptyFiles() throws Exception {
output = new File(dir, "empties.7z");
final Date accessDate = new Date();
final Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, -1);
final Date creationDate = cal.getTime();
try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
SevenZArchiveEntry entry = outArchive.createArchiveEntry(dir, "foo/");
outArchive.putArchiveEntry(entry);
outArchive.closeArchiveEntry();
entry = new SevenZArchiveEntry();
entry.setName("foo/bar");
entry.setCreationDate(creationDate);
entry.setAccessDate(accessDate);
outArchive.putArchiveEntry(entry);
outArchive.write(new byte[0]);
outArchive.closeArchiveEntry();
entry = new SevenZArchiveEntry();
entry.setName("xyzzy");
outArchive.putArchiveEntry(entry);
outArchive.write(0);
outArchive.closeArchiveEntry();
entry = outArchive.createArchiveEntry(dir, "baz/");
entry.setAntiItem(true);
outArchive.putArchiveEntry(entry);
outArchive.closeArchiveEntry();
entry = new SevenZArchiveEntry();
entry.setName("dada");
entry.setHasWindowsAttributes(true);
entry.setWindowsAttributes(17);
outArchive.putArchiveEntry(entry);
outArchive.write(5);
outArchive.write(42);
outArchive.closeArchiveEntry();
outArchive.finish();
}
try (SevenZFile archive = new SevenZFile(output)) {
SevenZArchiveEntry entry = archive.getNextEntry();
assert (entry != null);
assertEquals("foo/", entry.getName());
assertTrue(entry.isDirectory());
assertFalse(entry.isAntiItem());
entry = archive.getNextEntry();
assert (entry != null);
assertEquals("foo/bar", entry.getName());
assertFalse(entry.isDirectory());
assertFalse(entry.isAntiItem());
assertEquals(0, entry.getSize());
assertFalse(entry.getHasLastModifiedDate());
assertEquals(accessDate, entry.getAccessDate());
assertEquals(creationDate, entry.getCreationDate());
entry = archive.getNextEntry();
assert (entry != null);
assertEquals("xyzzy", entry.getName());
assertEquals(1, entry.getSize());
assertFalse(entry.getHasAccessDate());
assertFalse(entry.getHasCreationDate());
assertEquals(0, archive.read());
entry = archive.getNextEntry();
assert (entry != null);
assertEquals("baz/", entry.getName());
assertTrue(entry.isDirectory());
assertTrue(entry.isAntiItem());
entry = archive.getNextEntry();
assert (entry != null);
assertEquals("dada", entry.getName());
assertEquals(2, entry.getSize());
final byte[] content = new byte[2];
assertEquals(2, archive.read(content));
assertEquals(5, content[0]);
assertEquals(42, content[1]);
assertEquals(17, entry.getWindowsAttributes());
assert (archive.getNextEntry() == null);
}
}
@Test
public void testDirectoriesOnly() throws Exception {
output = new File(dir, "dirs.7z");
try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
final SevenZArchiveEntry entry = new SevenZArchiveEntry();
entry.setName("foo/");
entry.setDirectory(true);
outArchive.putArchiveEntry(entry);
outArchive.closeArchiveEntry();
}
try (SevenZFile archive = new SevenZFile(output)) {
final SevenZArchiveEntry entry = archive.getNextEntry();
assert (entry != null);
assertEquals("foo/", entry.getName());
assertTrue(entry.isDirectory());
assertFalse(entry.isAntiItem());
assert (archive.getNextEntry() == null);
}
}
@Test
public void testCantFinishTwice() throws Exception {
output = new File(dir, "finish.7z");
try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
outArchive.finish();
outArchive.finish();
fail("shouldn't be able to call finish twice");
} catch (final IOException ex) {
assertEquals("This archive has already been finished", ex.getMessage());
}
}
@Test
public void testSixEmptyFiles() throws Exception {
testCompress252(6, 0);
}
@Test
public void testSixFilesSomeNotEmpty() throws Exception {
testCompress252(6, 2);
}
@Test
public void testSevenEmptyFiles() throws Exception {
testCompress252(7, 0);
}
@Test
public void testSevenFilesSomeNotEmpty() throws Exception {
testCompress252(7, 2);
}
@Test
public void testEightEmptyFiles() throws Exception {
testCompress252(8, 0);
}
@Test
public void testEightFilesSomeNotEmpty() throws Exception {
testCompress252(8, 2);
}
@Test
public void testNineEmptyFiles() throws Exception {
testCompress252(9, 0);
}
@Test
public void testNineFilesSomeNotEmpty() throws Exception {
testCompress252(9, 2);
}
@Test
public void testTwentyNineEmptyFiles() throws Exception {
testCompress252(29, 0);
}
@Test
public void testTwentyNineFilesSomeNotEmpty() throws Exception {
testCompress252(29, 7);
}
@Test
public void testCopyRoundtrip() throws Exception {
testRoundTrip(SevenZMethod.COPY);
}
@Test
public void testBzip2Roundtrip() throws Exception {
testRoundTrip(SevenZMethod.BZIP2);
}
@Test
public void testLzma2Roundtrip() throws Exception {
testRoundTrip(SevenZMethod.LZMA2);
}
@Test
public void testDeflateRoundtrip() throws Exception {
testRoundTrip(SevenZMethod.DEFLATE);
}
@Test
public void testBCJX86Roundtrip() throws Exception {
if (XZ_BCJ_IS_BUGGY) { return; }
testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_X86_FILTER));
}
@Test
public void testBCJARMRoundtrip() throws Exception {
if (XZ_BCJ_IS_BUGGY) { return; }
testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_ARM_FILTER));
}
@Test
public void testBCJARMThumbRoundtrip() throws Exception {
if (XZ_BCJ_IS_BUGGY) { return; }
testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_ARM_THUMB_FILTER));
}
@Test
public void testBCJIA64Roundtrip() throws Exception {
if (XZ_BCJ_IS_BUGGY) { return; }
testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_IA64_FILTER));
}
@Test
public void testBCJPPCRoundtrip() throws Exception {
if (XZ_BCJ_IS_BUGGY) { return; }
testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_PPC_FILTER));
}
@Test
public void testBCJSparcRoundtrip() throws Exception {
if (XZ_BCJ_IS_BUGGY) { return; }
testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_SPARC_FILTER));
}
@Test
public void testDeltaRoundtrip() throws Exception {
testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.DELTA_FILTER));
}
@Test
public void testStackOfContentCompressions() throws Exception {
output = new File(dir, "multiple-methods.7z");
final ArrayList<SevenZMethodConfiguration> methods = new ArrayList<>();
methods.add(new SevenZMethodConfiguration(SevenZMethod.LZMA2));
methods.add(new SevenZMethodConfiguration(SevenZMethod.COPY));
methods.add(new SevenZMethodConfiguration(SevenZMethod.DEFLATE));
methods.add(new SevenZMethodConfiguration(SevenZMethod.BZIP2));
createAndReadBack(output, methods);
}
@Test
public void testDeflateWithConfiguration() throws Exception {
output = new File(dir, "deflate-options.7z");
// Deflater.BEST_SPEED
createAndReadBack(output, Collections
.singletonList(new SevenZMethodConfiguration(SevenZMethod.DEFLATE, 1)));
}
@Test
public void testBzip2WithConfiguration() throws Exception {
output = new File(dir, "bzip2-options.7z");
// 400k block size
createAndReadBack(output, Collections
.singletonList(new SevenZMethodConfiguration(SevenZMethod.BZIP2, 4)));
}
@Test
public void testLzma2WithIntConfiguration() throws Exception {
output = new File(dir, "lzma2-options.7z");
// 1 MB dictionary
createAndReadBack(output, Collections
.singletonList(new SevenZMethodConfiguration(SevenZMethod.LZMA2, 1 << 20)));
}
@Test
public void testLzma2WithOptionsConfiguration() throws Exception {
output = new File(dir, "lzma2-options2.7z");
final LZMA2Options opts = new LZMA2Options(1);
createAndReadBack(output, Collections
.singletonList(new SevenZMethodConfiguration(SevenZMethod.LZMA2, opts)));
}
@Test
public void testArchiveWithMixedMethods() throws Exception {
output = new File(dir, "mixed-methods.7z");
try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
addFile(outArchive, 0, true);
addFile(outArchive, 1, true, Arrays.asList(new SevenZMethodConfiguration(SevenZMethod.BZIP2)));
}
try (SevenZFile archive = new SevenZFile(output)) {
assertEquals(Boolean.TRUE,
verifyFile(archive, 0, Arrays.asList(new SevenZMethodConfiguration(SevenZMethod.LZMA2))));
assertEquals(Boolean.TRUE,
verifyFile(archive, 1, Arrays.asList(new SevenZMethodConfiguration(SevenZMethod.BZIP2))));
}
}
private void testCompress252(final int numberOfFiles, final int numberOfNonEmptyFiles)
throws Exception {
final int nonEmptyModulus = numberOfNonEmptyFiles != 0
? numberOfFiles / numberOfNonEmptyFiles
: numberOfFiles + 1;
int nonEmptyFilesAdded = 0;
output = new File(dir, "COMPRESS252-" + numberOfFiles + "-" + numberOfNonEmptyFiles + ".7z");
try (SevenZOutputFile archive = new SevenZOutputFile(output)) {
addDir(archive);
for (int i = 0; i < numberOfFiles; i++) {
addFile(archive, i,
(i + 1) % nonEmptyModulus == 0 && nonEmptyFilesAdded++ < numberOfNonEmptyFiles);
}
}
verifyCompress252(output, numberOfFiles, numberOfNonEmptyFiles);
}
private void verifyCompress252(final File output, final int numberOfFiles, final int numberOfNonEmptyFiles)
throws Exception {
int filesFound = 0;
int nonEmptyFilesFound = 0;
try (SevenZFile archive = new SevenZFile(output)) {
verifyDir(archive);
Boolean b = verifyFile(archive, filesFound++);
while (b != null) {
if (Boolean.TRUE.equals(b)) {
nonEmptyFilesFound++;
}
b = verifyFile(archive, filesFound++);
}
}
assertEquals(numberOfFiles + 1, filesFound);
assertEquals(numberOfNonEmptyFiles, nonEmptyFilesFound);
}
private void addDir(final SevenZOutputFile archive) throws Exception {
final SevenZArchiveEntry entry = archive.createArchiveEntry(dir, "foo/");
archive.putArchiveEntry(entry);
archive.closeArchiveEntry();
}
private void verifyDir(final SevenZFile archive) throws Exception {
final SevenZArchiveEntry entry = archive.getNextEntry();
assertNotNull(entry);
assertEquals("foo/", entry.getName());
assertTrue(entry.isDirectory());
}
private void addFile(final SevenZOutputFile archive, final int index, final boolean nonEmpty)
throws Exception {
addFile(archive, index, nonEmpty, null);
}
private void addFile(final SevenZOutputFile archive, final int index, final boolean nonEmpty, final Iterable<SevenZMethodConfiguration> methods)
throws Exception {
final SevenZArchiveEntry entry = new SevenZArchiveEntry();
entry.setName("foo/" + index + ".txt");
entry.setContentMethods(methods);
archive.putArchiveEntry(entry);
archive.write(nonEmpty ? new byte[] { 'A' } : new byte[0]);
archive.closeArchiveEntry();
}
private Boolean verifyFile(final SevenZFile archive, final int index) throws Exception {
return verifyFile(archive, index, null);
}
private Boolean verifyFile(final SevenZFile archive, final int index,
final Iterable<SevenZMethodConfiguration> methods) throws Exception {
final SevenZArchiveEntry entry = archive.getNextEntry();
if (entry == null) {
return null;
}
assertEquals("foo/" + index + ".txt", entry.getName());
assertEquals(false, entry.isDirectory());
if (entry.getSize() == 0) {
return Boolean.FALSE;
}
assertEquals(1, entry.getSize());
assertEquals('A', archive.read());
assertEquals(-1, archive.read());
if (methods != null) {
assertContentMethodsEquals(methods, entry.getContentMethods());
}
return Boolean.TRUE;
}
private void testRoundTrip(final SevenZMethod method) throws Exception {
output = new File(dir, method + "-roundtrip.7z");
final ArrayList<SevenZMethodConfiguration> methods = new ArrayList<>();
methods.add(new SevenZMethodConfiguration(method));
createAndReadBack(output, methods);
}
private void testFilterRoundTrip(final SevenZMethodConfiguration method) throws Exception {
output = new File(dir, method.getMethod() + "-roundtrip.7z");
final ArrayList<SevenZMethodConfiguration> methods = new ArrayList<>();
methods.add(method);
methods.add(new SevenZMethodConfiguration(SevenZMethod.LZMA2));
createAndReadBack(output, methods);
}
private void createAndReadBack(final File output, final Iterable<SevenZMethodConfiguration> methods) throws Exception {
final SevenZOutputFile outArchive = new SevenZOutputFile(output);
outArchive.setContentMethods(methods);
try {
addFile(outArchive, 0, true);
} finally {
outArchive.close();
}
try (SevenZFile archive = new SevenZFile(output)) {
assertEquals(Boolean.TRUE, verifyFile(archive, 0, methods));
}
}
private static void assertContentMethodsEquals(final Iterable<? extends SevenZMethodConfiguration> expected,
final Iterable<? extends SevenZMethodConfiguration> actual) {
assertNotNull(actual);
final Iterator<? extends SevenZMethodConfiguration> expectedIter = expected.iterator();
final Iterator<? extends SevenZMethodConfiguration> actualIter = actual.iterator();
while (expectedIter.hasNext()) {
assertTrue(actualIter.hasNext());
final SevenZMethodConfiguration expConfig = expectedIter.next();
final SevenZMethodConfiguration actConfig = actualIter.next();
assertEquals(expConfig.getMethod(), actConfig.getMethod());
}
assertFalse(actualIter.hasNext());
}
}