1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.archivers.sevenz;
20
21 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertFalse;
24 import static org.junit.jupiter.api.Assertions.assertNotEquals;
25 import static org.junit.jupiter.api.Assertions.assertNotNull;
26 import static org.junit.jupiter.api.Assertions.assertNull;
27 import static org.junit.jupiter.api.Assertions.assertThrows;
28 import static org.junit.jupiter.api.Assertions.assertTrue;
29
30 import java.io.ByteArrayInputStream;
31 import java.io.File;
32 import java.io.IOException;
33 import java.nio.file.Files;
34 import java.nio.file.Paths;
35 import java.nio.file.attribute.FileTime;
36 import java.time.Instant;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Calendar;
40 import java.util.Collections;
41 import java.util.Date;
42 import java.util.Iterator;
43
44 import org.apache.commons.compress.AbstractTest;
45 import org.apache.commons.compress.PasswordRequiredException;
46 import org.apache.commons.compress.utils.ByteUtils;
47 import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
48 import org.apache.commons.compress.utils.TimeUtilsTest;
49 import org.junit.jupiter.api.Test;
50 import org.tukaani.xz.LZMA2Options;
51
52 class SevenZOutputFileTest extends AbstractTest {
53
54 private static final boolean XZ_BCJ_IS_BUGGY;
55
56 static {
57 final String version = org.tukaani.xz.XZ.class.getPackage().getImplementationVersion();
58
59 XZ_BCJ_IS_BUGGY = version != null && version.equals("1.4");
60 if (XZ_BCJ_IS_BUGGY) {
61 System.out.println("XZ version is " + version + " - skipping BCJ tests");
62 }
63 }
64
65 private static void assertContentMethodsEquals(final Iterable<? extends SevenZMethodConfiguration> expected,
66 final Iterable<? extends SevenZMethodConfiguration> actual) {
67 assertNotNull(actual);
68 final Iterator<? extends SevenZMethodConfiguration> actualIter = actual.iterator();
69 for (final SevenZMethodConfiguration expConfig : expected) {
70 assertTrue(actualIter.hasNext());
71 final SevenZMethodConfiguration actConfig = actualIter.next();
72 assertEquals(expConfig.getMethod(), actConfig.getMethod());
73 }
74 assertFalse(actualIter.hasNext());
75 }
76
77 private void addDir(final SevenZOutputFile archive) throws Exception {
78 final SevenZArchiveEntry entry = archive.createArchiveEntry(getTempDirFile(), "foo/");
79 archive.putArchiveEntry(entry);
80 archive.closeArchiveEntry();
81 }
82
83 private void addFile(final SevenZOutputFile archive, final int index, final boolean nonEmpty) throws Exception {
84 addFile(archive, index, nonEmpty, null);
85 }
86
87 private void addFile(final SevenZOutputFile archive, final int index, final boolean nonEmpty, final Iterable<SevenZMethodConfiguration> methods)
88 throws Exception {
89 addFile(archive, index, nonEmpty ? 1 : 0, methods);
90 }
91
92 private void addFile(final SevenZOutputFile archive, final int index, final int size, final Iterable<SevenZMethodConfiguration> methods) throws Exception {
93 final SevenZArchiveEntry entry = new SevenZArchiveEntry();
94 entry.setName("foo/" + index + ".txt");
95 entry.setContentMethods(methods);
96 archive.putArchiveEntry(entry);
97 archive.write(generateFileData(size));
98 archive.closeArchiveEntry();
99 }
100
101 private void createAndReadBack(final File output, final Iterable<SevenZMethodConfiguration> methods) throws Exception {
102 try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
103 outArchive.setContentMethods(methods);
104 addFile(outArchive, 0, true);
105 }
106
107 try (SevenZFile archive = SevenZFile.builder().setFile(output).get()) {
108 assertEquals(Boolean.TRUE, verifyFile(archive, 0, methods));
109 }
110 }
111
112 private void createAndReadBack(final SeekableInMemoryByteChannel output, final Iterable<SevenZMethodConfiguration> methods) throws Exception {
113 try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
114 outArchive.setContentMethods(methods);
115 addFile(outArchive, 0, true);
116 }
117 try (SevenZFile archive = SevenZFile.builder().setByteArray(output.array()).setDefaultName("in memory").get()) {
118 assertEquals(Boolean.TRUE, verifyFile(archive, 0, methods));
119 }
120 }
121
122 private byte[] generateFileData(final int size) {
123 final byte[] data = new byte[size];
124 for (int i = 0; i < size; i++) {
125 data[i] = (byte) ('A' + i % 26);
126 }
127 return data;
128 }
129
130 private FileTime getHundredNanosFileTime() {
131 final Instant now = Instant.now();
132
133
134 final FileTime fileTime = FileTime.from(Instant.ofEpochSecond(now.getEpochSecond(), now.getNano() + 999900));
135
136
137 return TimeUtilsTest.truncateToHundredNanos(fileTime);
138 }
139
140 @Test
141 void testArchiveWithMixedMethods() throws Exception {
142 final File output = newTempFile("mixed-methods.7z");
143 try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
144 addFile(outArchive, 0, true);
145 addFile(outArchive, 1, true, Arrays.asList(new SevenZMethodConfiguration(SevenZMethod.BZIP2)));
146 }
147
148 try (SevenZFile archive = SevenZFile.builder().setFile(output).get()) {
149 assertEquals(Boolean.TRUE, verifyFile(archive, 0, Arrays.asList(new SevenZMethodConfiguration(SevenZMethod.LZMA2))));
150 assertEquals(Boolean.TRUE, verifyFile(archive, 1, Arrays.asList(new SevenZMethodConfiguration(SevenZMethod.BZIP2))));
151 }
152 }
153
154 @Test
155 void testBCJARMRoundtrip() throws Exception {
156 if (XZ_BCJ_IS_BUGGY) {
157 return;
158 }
159 testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_ARM_FILTER));
160 }
161
162 @Test
163 void testBCJARMThumbRoundtrip() throws Exception {
164 if (XZ_BCJ_IS_BUGGY) {
165 return;
166 }
167 testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_ARM_THUMB_FILTER));
168 }
169
170 @Test
171 void testBCJIA64Roundtrip() throws Exception {
172 if (XZ_BCJ_IS_BUGGY) {
173 return;
174 }
175 testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_IA64_FILTER));
176 }
177
178 @Test
179 void testBCJPPCRoundtrip() throws Exception {
180 if (XZ_BCJ_IS_BUGGY) {
181 return;
182 }
183 testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_PPC_FILTER));
184 }
185
186 @Test
187 void testBCJSparcRoundtrip() throws Exception {
188 if (XZ_BCJ_IS_BUGGY) {
189 return;
190 }
191 testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_SPARC_FILTER));
192 }
193
194 @Test
195 void testBCJX86Roundtrip() throws Exception {
196 if (XZ_BCJ_IS_BUGGY) {
197 return;
198 }
199 testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.BCJ_X86_FILTER));
200 }
201
202 @Test
203 void testBzip2Roundtrip() throws Exception {
204 testRoundTrip(SevenZMethod.BZIP2);
205 }
206
207 @Test
208 void testBzip2WithConfiguration() throws Exception {
209 final File output = newTempFile("bzip2-options.7z");
210
211 createAndReadBack(output, Collections.singletonList(new SevenZMethodConfiguration(SevenZMethod.BZIP2, 4)));
212 }
213
214 @Test
215 void testCantFinishTwice() throws IOException {
216 final File output = newTempFile("finish.7z");
217 try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
218 outArchive.finish();
219 final IOException ex = assertThrows(IOException.class, outArchive::finish, "shouldn't be able to call finish twice");
220 assertEquals("This archive has already been finished", ex.getMessage());
221 }
222 }
223
224 private void testCompress252(final int numberOfFiles, final int numberOfNonEmptyFiles) throws Exception {
225 final int nonEmptyModulus = numberOfNonEmptyFiles != 0 ? numberOfFiles / numberOfNonEmptyFiles : numberOfFiles + 1;
226 int nonEmptyFilesAdded = 0;
227 final File output = newTempFile("COMPRESS252-" + numberOfFiles + "-" + numberOfNonEmptyFiles + ".7z");
228 try (SevenZOutputFile archive = new SevenZOutputFile(output)) {
229 addDir(archive);
230 for (int i = 0; i < numberOfFiles; i++) {
231 addFile(archive, i, (i + 1) % nonEmptyModulus == 0 && nonEmptyFilesAdded++ < numberOfNonEmptyFiles);
232 }
233 }
234 verifyCompress252(output, numberOfFiles, numberOfNonEmptyFiles);
235 }
236
237 @Test
238 void testCopyRoundtrip() throws Exception {
239 testRoundTrip(SevenZMethod.COPY);
240 }
241
242 @Test
243 void testDeflateRoundtrip() throws Exception {
244 testRoundTrip(SevenZMethod.DEFLATE);
245 }
246
247 @Test
248 void testDeflateWithConfiguration() throws Exception {
249 final File output = newTempFile("deflate-options.7z");
250
251 createAndReadBack(output, Collections.singletonList(new SevenZMethodConfiguration(SevenZMethod.DEFLATE, 1)));
252 }
253
254 @Test
255 void testDeltaRoundtrip() throws Exception {
256 testFilterRoundTrip(new SevenZMethodConfiguration(SevenZMethod.DELTA_FILTER));
257 }
258
259 @Test
260 void testDirectoriesAndEmptyFiles() throws Exception {
261 final File output = newTempFile("empties.7z");
262
263 final FileTime accessTime = getHundredNanosFileTime();
264 final Date accessDate = new Date(accessTime.toMillis());
265 final Calendar cal = Calendar.getInstance();
266 cal.add(Calendar.HOUR, -1);
267 final Date creationDate = cal.getTime();
268
269 try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
270 SevenZArchiveEntry entry = outArchive.createArchiveEntry(getTempDirFile(), "foo/");
271 outArchive.putArchiveEntry(entry);
272 outArchive.closeArchiveEntry();
273
274 entry = new SevenZArchiveEntry();
275 entry.setName("foo/bar");
276 entry.setCreationDate(creationDate);
277 entry.setAccessTime(accessTime);
278 outArchive.putArchiveEntry(entry);
279 outArchive.write(ByteUtils.EMPTY_BYTE_ARRAY);
280 outArchive.closeArchiveEntry();
281
282 entry = new SevenZArchiveEntry();
283 entry.setName("foo/bar/boo0");
284 entry.setCreationDate(creationDate);
285 entry.setAccessTime(accessTime);
286 outArchive.putArchiveEntry(entry);
287 outArchive.write(new ByteArrayInputStream(ByteUtils.EMPTY_BYTE_ARRAY));
288 outArchive.closeArchiveEntry();
289
290 entry = new SevenZArchiveEntry();
291 entry.setName("foo/bar/boo1");
292 entry.setCreationDate(creationDate);
293 entry.setAccessTime(accessTime);
294 outArchive.putArchiveEntry(entry);
295 outArchive.write(new ByteArrayInputStream(new byte[] { 'a' }));
296 outArchive.closeArchiveEntry();
297
298 entry = new SevenZArchiveEntry();
299 entry.setName("foo/bar/boo10000");
300 entry.setCreationDate(creationDate);
301 entry.setAccessTime(accessTime);
302 outArchive.putArchiveEntry(entry);
303 outArchive.write(new ByteArrayInputStream(new byte[10000]));
304 outArchive.closeArchiveEntry();
305
306 entry = new SevenZArchiveEntry();
307 entry.setName("foo/bar/test.txt");
308 entry.setCreationDate(creationDate);
309 entry.setAccessTime(accessTime);
310 outArchive.putArchiveEntry(entry);
311 outArchive.write(Paths.get("src/test/resources/test.txt"));
312 outArchive.closeArchiveEntry();
313
314 entry = new SevenZArchiveEntry();
315 entry.setName("xyzzy");
316 outArchive.putArchiveEntry(entry);
317 outArchive.write(0);
318 outArchive.closeArchiveEntry();
319
320 entry = outArchive.createArchiveEntry(getTempDirFile(), "baz/");
321 entry.setAntiItem(true);
322 outArchive.putArchiveEntry(entry);
323 outArchive.closeArchiveEntry();
324
325 entry = outArchive.createArchiveEntry(getTempDirFile().toPath(), "baz2/");
326 entry.setAntiItem(true);
327 outArchive.putArchiveEntry(entry);
328 outArchive.closeArchiveEntry();
329
330 entry = new SevenZArchiveEntry();
331 entry.setName("dada");
332 entry.setHasWindowsAttributes(true);
333 entry.setWindowsAttributes(17);
334 outArchive.putArchiveEntry(entry);
335 outArchive.write(5);
336 outArchive.write(42);
337 outArchive.closeArchiveEntry();
338
339 outArchive.finish();
340 }
341
342 try (SevenZFile archive = SevenZFile.builder().setFile(output).get()) {
343 SevenZArchiveEntry entry = archive.getNextEntry();
344 assertNotNull(entry, "Entry should not be null");
345 assertEquals("foo/", entry.getName());
346 assertTrue(entry.isDirectory());
347 assertFalse(entry.isAntiItem());
348
349 entry = archive.getNextEntry();
350 assertNotNull(entry, "Entry should not be null");
351 assertEquals("foo/bar", entry.getName());
352 assertFalse(entry.isDirectory());
353 assertFalse(entry.isAntiItem());
354 assertEquals(0, entry.getSize());
355 assertFalse(entry.getHasLastModifiedDate());
356 assertEquals(accessTime, entry.getAccessTime());
357 assertEquals(accessDate, entry.getAccessDate());
358 assertEquals(creationDate, entry.getCreationDate());
359
360 entry = archive.getNextEntry();
361 assertNotNull(entry, "Entry should not be null");
362 assertEquals("foo/bar/boo0", entry.getName());
363 assertFalse(entry.isDirectory());
364 assertFalse(entry.isAntiItem());
365 assertEquals(0, entry.getSize());
366 assertFalse(entry.getHasLastModifiedDate());
367 assertEquals(accessTime, entry.getAccessTime());
368 assertEquals(accessDate, entry.getAccessDate());
369 assertEquals(creationDate, entry.getCreationDate());
370
371 entry = archive.getNextEntry();
372 assertNotNull(entry, "Entry should not be null");
373 assertEquals("foo/bar/boo1", entry.getName());
374 assertFalse(entry.isDirectory());
375 assertFalse(entry.isAntiItem());
376 assertEquals(1, entry.getSize());
377 assertFalse(entry.getHasLastModifiedDate());
378 assertEquals(accessTime, entry.getAccessTime());
379 assertEquals(accessDate, entry.getAccessDate());
380 assertEquals(creationDate, entry.getCreationDate());
381
382 entry = archive.getNextEntry();
383 assertNotNull(entry, "Entry should not be null");
384 assertEquals("foo/bar/boo10000", entry.getName());
385 assertFalse(entry.isDirectory());
386 assertFalse(entry.isAntiItem());
387 assertEquals(10000, entry.getSize());
388 assertFalse(entry.getHasLastModifiedDate());
389 assertEquals(accessTime, entry.getAccessTime());
390 assertEquals(accessDate, entry.getAccessDate());
391 assertEquals(creationDate, entry.getCreationDate());
392
393 entry = archive.getNextEntry();
394 assertNotNull(entry, "Entry should not be null");
395 assertEquals("foo/bar/test.txt", entry.getName());
396 assertFalse(entry.isDirectory());
397 assertFalse(entry.isAntiItem());
398 assertEquals(Files.size(Paths.get("src/test/resources/test.txt")), entry.getSize());
399 assertFalse(entry.getHasLastModifiedDate());
400 assertEquals(accessTime, entry.getAccessTime());
401 assertEquals(accessDate, entry.getAccessDate());
402 assertEquals(creationDate, entry.getCreationDate());
403
404 entry = archive.getNextEntry();
405 assertNotNull(entry, "Entry should not be null");
406 assertEquals("xyzzy", entry.getName());
407 assertEquals(1, entry.getSize());
408 assertFalse(entry.getHasAccessDate());
409 assertFalse(entry.getHasCreationDate());
410 assertEquals(0, archive.read());
411
412 entry = archive.getNextEntry();
413 assertNotNull(entry, "Entry should not be null");
414 assertEquals("baz/", entry.getName());
415 assertTrue(entry.isDirectory());
416 assertTrue(entry.isAntiItem());
417
418 entry = archive.getNextEntry();
419 assertNotNull(entry, "Entry should not be null");
420 assertEquals("baz2/", entry.getName());
421 assertTrue(entry.isDirectory());
422 assertTrue(entry.isAntiItem());
423
424 entry = archive.getNextEntry();
425 assertNotNull(entry, "Entry should not be null");
426 assertEquals("dada", entry.getName());
427 assertEquals(2, entry.getSize());
428 final byte[] content = new byte[2];
429 assertEquals(2, archive.read(content));
430 assertEquals(5, content[0]);
431 assertEquals(42, content[1]);
432 assertEquals(17, entry.getWindowsAttributes());
433
434 assertNull(archive.getNextEntry(), "getNextEntry should return null");
435 }
436
437 }
438
439 @Test
440 void testDirectoriesOnly() throws Exception {
441 final File output = newTempFile("dirs.7z");
442 try (SevenZOutputFile outArchive = new SevenZOutputFile(output)) {
443 final SevenZArchiveEntry entry = new SevenZArchiveEntry();
444 entry.setName("foo/");
445 entry.setDirectory(true);
446 outArchive.putArchiveEntry(entry);
447 outArchive.closeArchiveEntry();
448 }
449
450 try (SevenZFile archive = SevenZFile.builder().setFile(output).get()) {
451 final SevenZArchiveEntry entry = archive.getNextEntry();
452 assertNotNull(entry, "entry should not be null");
453 assertEquals("foo/", entry.getName());
454 assertTrue(entry.isDirectory());
455 assertFalse(entry.isAntiItem());
456
457 assertNull(archive.getNextEntry(), "getnextEntry should return null");
458 }
459
460 }
461
462 @Test
463 void testEightEmptyFiles() throws Exception {
464 testCompress252(8, 0);
465 }
466
467 @Test
468 void testEightFilesSomeNotEmpty() throws Exception {
469 testCompress252(8, 2);
470 }
471
472
473
474
475
476
477
478
479
480 @Test
481 void testEncrypt() throws Exception {
482 final File output = newTempFile("encrypted.7z");
483 try (SevenZOutputFile outArchive = new SevenZOutputFile(output, "foo".toCharArray())) {
484 addFile(outArchive, 0, 1, null);
485 addFile(outArchive, 1, 16, null);
486 addFile(outArchive, 2, 32, null);
487 addFile(outArchive, 3, 33, null);
488 addFile(outArchive, 4, 10000, null);
489 }
490
491
492 try (SevenZFile archive = SevenZFile.builder().setFile(output).get()) {
493 assertThrows(
494 PasswordRequiredException.class, () -> verifyFile(archive, 0), "A password should be needed");
495 }
496
497 try (SevenZFile archive = SevenZFile.builder().setFile(output).setPassword("foo").get()) {
498 assertEquals(Boolean.TRUE, verifyFile(archive, 0, 1, null));
499 assertEquals(Boolean.TRUE, verifyFile(archive, 1, 16, null));
500 assertEquals(Boolean.TRUE, verifyFile(archive, 2, 32, null));
501 assertEquals(Boolean.TRUE, verifyFile(archive, 3, 33, null));
502 assertEquals(Boolean.TRUE, verifyFile(archive, 4, 10000, null));
503 }
504 }
505
506 private void testFilterRoundTrip(final SevenZMethodConfiguration method) throws Exception {
507 final File output = newTempFile(method.getMethod() + "-roundtrip.7z");
508 final ArrayList<SevenZMethodConfiguration> methods = new ArrayList<>();
509 methods.add(method);
510 methods.add(new SevenZMethodConfiguration(SevenZMethod.LZMA2));
511 createAndReadBack(output, methods);
512 }
513
514 @Test
515 void testLzma2Roundtrip() throws Exception {
516 testRoundTrip(SevenZMethod.LZMA2);
517 }
518
519 @Test
520 void testLzma2WithIntConfiguration() throws Exception {
521 final File output = newTempFile("lzma2-options.7z");
522
523 createAndReadBack(output, Collections.singletonList(new SevenZMethodConfiguration(SevenZMethod.LZMA2, 1 << 20)));
524 }
525
526 @Test
527 void testLzma2WithOptionsConfiguration() throws Exception {
528 final File output = newTempFile("lzma2-options2.7z");
529 final LZMA2Options opts = new LZMA2Options(1);
530 createAndReadBack(output, Collections.singletonList(new SevenZMethodConfiguration(SevenZMethod.LZMA2, opts)));
531 }
532
533 @Test
534 void testLzmaWithIntConfiguration() throws Exception {
535 final File output = newTempFile("lzma-options.7z");
536
537 createAndReadBack(output, Collections.singletonList(new SevenZMethodConfiguration(SevenZMethod.LZMA, 1 << 20)));
538 }
539
540 @Test
541 void testLzmaWithOptionsConfiguration() throws Exception {
542 final File output = newTempFile("lzma-options2.7z");
543 final LZMA2Options opts = new LZMA2Options(1);
544 createAndReadBack(output, Collections.singletonList(new SevenZMethodConfiguration(SevenZMethod.LZMA, opts)));
545 }
546
547 @Test
548 void testNineEmptyFiles() throws Exception {
549 testCompress252(9, 0);
550 }
551
552 @Test
553 void testNineFilesSomeNotEmpty() throws Exception {
554 testCompress252(9, 2);
555 }
556
557 private void testRoundTrip(final SevenZMethod method) throws Exception {
558 final File output = newTempFile(method + "-roundtrip.7z");
559 final ArrayList<SevenZMethodConfiguration> methods = new ArrayList<>();
560 methods.add(new SevenZMethodConfiguration(method));
561 createAndReadBack(output, methods);
562 }
563
564 @Test
565 void testSevenEmptyFiles() throws Exception {
566 testCompress252(7, 0);
567 }
568
569 @Test
570 void testSevenFilesSomeNotEmpty() throws Exception {
571 testCompress252(7, 2);
572 }
573
574 @Test
575 void testSixEmptyFiles() throws Exception {
576 testCompress252(6, 0);
577 }
578
579 @Test
580 void testSixFilesSomeNotEmpty() throws Exception {
581 testCompress252(6, 2);
582 }
583
584 @Test
585 void testStackOfContentCompressions() throws Exception {
586 final File output = newTempFile("multiple-methods.7z");
587 final ArrayList<SevenZMethodConfiguration> methods = new ArrayList<>();
588 methods.add(new SevenZMethodConfiguration(SevenZMethod.LZMA2));
589 methods.add(new SevenZMethodConfiguration(SevenZMethod.COPY));
590 methods.add(new SevenZMethodConfiguration(SevenZMethod.DEFLATE));
591 methods.add(new SevenZMethodConfiguration(SevenZMethod.BZIP2));
592 createAndReadBack(output, methods);
593 }
594
595 @Test
596 void testStackOfContentCompressionsInMemory() throws Exception {
597 final ArrayList<SevenZMethodConfiguration> methods = new ArrayList<>();
598 methods.add(new SevenZMethodConfiguration(SevenZMethod.LZMA2));
599 methods.add(new SevenZMethodConfiguration(SevenZMethod.COPY));
600 methods.add(new SevenZMethodConfiguration(SevenZMethod.DEFLATE));
601 methods.add(new SevenZMethodConfiguration(SevenZMethod.BZIP2));
602 try (SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel()) {
603 createAndReadBack(channel, methods);
604 }
605 }
606
607 @Test
608 void testTwentyNineEmptyFiles() throws Exception {
609 testCompress252(29, 0);
610 }
611
612 @Test
613 void testTwentyNineFilesSomeNotEmpty() throws Exception {
614 testCompress252(29, 7);
615 }
616
617 private void verifyCompress252(final File output, final int numberOfFiles, final int numberOfNonEmptyFiles) throws Exception {
618 int filesFound = 0;
619 int nonEmptyFilesFound = 0;
620 try (SevenZFile archive = SevenZFile.builder().setFile(output).get()) {
621 verifyDir(archive);
622 Boolean b = verifyFile(archive, filesFound++);
623 while (b != null) {
624 if (Boolean.TRUE.equals(b)) {
625 nonEmptyFilesFound++;
626 }
627 b = verifyFile(archive, filesFound++);
628 }
629 }
630 assertEquals(numberOfFiles + 1, filesFound);
631 assertEquals(numberOfNonEmptyFiles, nonEmptyFilesFound);
632 }
633
634 private void verifyDir(final SevenZFile archive) throws Exception {
635 final SevenZArchiveEntry entry = archive.getNextEntry();
636 assertNotNull(entry);
637 assertEquals("foo/", entry.getName());
638 assertTrue(entry.isDirectory());
639 }
640
641 private Boolean verifyFile(final SevenZFile archive, final int index) throws Exception {
642 return verifyFile(archive, index, null);
643 }
644
645 private Boolean verifyFile(final SevenZFile archive, final int index, final int size, final Iterable<SevenZMethodConfiguration> methods) throws Exception {
646 final SevenZArchiveEntry entry = archive.getNextEntry();
647 if (entry == null) {
648 return null;
649 }
650 assertEquals("foo/" + index + ".txt", entry.getName());
651 assertFalse(entry.isDirectory());
652 if (entry.getSize() == 0) {
653 return Boolean.FALSE;
654 }
655 assertEquals(size, entry.getSize());
656
657 final byte[] actual = new byte[size];
658 int count = 0;
659 while (count < size) {
660 final int read = archive.read(actual, count, actual.length - count);
661 assertNotEquals(-1, read, "EOF reached before reading all expected data");
662 count += read;
663 }
664 assertArrayEquals(generateFileData(size), actual);
665 assertEquals(-1, archive.read());
666 if (methods != null) {
667 assertContentMethodsEquals(methods, entry.getContentMethods());
668 }
669 return Boolean.TRUE;
670 }
671
672 private Boolean verifyFile(final SevenZFile archive, final int index, final Iterable<SevenZMethodConfiguration> methods) throws Exception {
673 return verifyFile(archive, index, 1, methods);
674 }
675 }