View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.changes;
20  
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.io.BufferedInputStream;
25  import java.io.BufferedReader;
26  import java.io.File;
27  import java.io.InputStream;
28  import java.io.OutputStream;
29  import java.nio.file.Files;
30  import java.nio.file.Path;
31  import java.util.ArrayList;
32  import java.util.List;
33  import java.util.Set;
34  
35  import org.apache.commons.compress.AbstractTest;
36  import org.apache.commons.compress.archivers.ArchiveEntry;
37  import org.apache.commons.compress.archivers.ArchiveInputStream;
38  import org.apache.commons.compress.archivers.ArchiveOutputStream;
39  import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
40  import org.apache.commons.compress.archivers.cpio.CpioArchiveEntry;
41  import org.apache.commons.compress.archivers.jar.JarArchiveEntry;
42  import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
43  import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
44  import org.apache.commons.compress.archivers.zip.ZipFile;
45  import org.junit.jupiter.api.Test;
46  import org.junit.jupiter.params.ParameterizedTest;
47  import org.junit.jupiter.params.provider.MethodSource;
48  
49  /**
50   * Tests {@link ChangeSet} using raw generics for public code.
51   *
52   * @see ChangeSetSafeTypesTest
53   */
54  public final class ChangeSetRawTypesTest extends AbstractTest {
55  
56      // Delete a single file
57      private void archiveListDelete(final String prefix) {
58          archiveList.removeIf(entry -> entry.equals(prefix));
59      }
60  
61      // Delete a directory tree
62      private void archiveListDeleteDir(final String prefix) {
63          // TODO won't work with folders
64          archiveList.removeIf(entry -> entry.startsWith(prefix + "/"));
65      }
66  
67      /**
68       * Adds a file with the same file name as an existing file from the stream. Should lead to a replacement.
69       *
70       * @param archiverName archiver name.
71       * @throws Exception Thrown on test failure. Thrown on test failure.
72       */
73      @ParameterizedTest
74      @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
75      @SuppressWarnings({ "unchecked", "rawtypes" })
76      public void testAddAlreadyExistingWithReplaceFalse(final String archiverName) throws Exception {
77          final Path inputPath = createArchive(archiverName);
78          final Path result = Files.createTempFile("test", "." + archiverName);
79          try (InputStream inputStream = Files.newInputStream(inputPath);
80                  ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
81                  OutputStream newOutputStream = Files.newOutputStream(result);
82                  ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
83                  InputStream csInputStream = Files.newInputStream(getPath("test.txt"));) {
84              setLongFileMode(archiveOutputStream);
85              final ChangeSet changeSet = new ChangeSet();
86              final ArchiveEntry entry = new ZipArchiveEntry("testdata/test1.xml");
87              changeSet.add(entry, csInputStream, false);
88              final ChangeSetResults results = new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
89              assertTrue(results.getAddedFromStream().contains("testdata/test1.xml"));
90              assertTrue(results.getAddedFromChangeSet().isEmpty());
91              assertTrue(results.getDeleted().isEmpty());
92          } finally {
93              checkArchiveContent(result, archiveList);
94              forceDelete(inputPath);
95              forceDelete(result);
96          }
97      }
98  
99      /**
100      * Adds a file with the same file name as an existing file from the stream. Should lead to a replacement.
101      *
102      * @param archiverName archiver name.
103      * @throws Exception Thrown on test failure. Thrown on test failure.
104      */
105     @ParameterizedTest
106     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getZipOutputArchiveNames")
107     @SuppressWarnings({ "unchecked", "rawtypes" })
108     public void testAddAlreadyExistingWithReplaceTrue(final String archiverName) throws Exception {
109         final Path inputPath = createArchive(archiverName);
110         final Path result = Files.createTempFile("test", "." + archiverName);
111         try (InputStream inputStream = Files.newInputStream(inputPath);
112                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
113                 OutputStream newOutputStream = Files.newOutputStream(result);
114                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
115                 InputStream csInputStream = Files.newInputStream(getPath("test.txt"))) {
116             setLongFileMode(archiveOutputStream);
117             final ChangeSet changeSet = new ChangeSet();
118             final ArchiveEntry entry = new ZipArchiveEntry("testdata/test1.xml");
119             changeSet.add(entry, csInputStream, true);
120             final ChangeSetResults results = new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
121             assertTrue(results.getAddedFromChangeSet().contains("testdata/test1.xml"));
122         } finally {
123             checkArchiveContent(result, archiveList);
124             forceDelete(result);
125         }
126     }
127 
128     /**
129      * Adds an ArchiveEntry with the same name two times. Only the latest addition should be found in the ChangeSet, the first add should be replaced.
130      *
131      * @throws Exception Thrown on test failure. Thrown on test failure.
132      */
133     @Test
134     @SuppressWarnings({ "unchecked", "rawtypes" })
135     public void testAddChangeTwice() throws Exception {
136         try (InputStream inputStream = newInputStream("test.txt");
137                 InputStream inputStream2 = newInputStream("test2.xml")) {
138             final ArchiveEntry e = new ZipArchiveEntry("test.txt");
139             final ArchiveEntry e2 = new ZipArchiveEntry("test.txt");
140             final ChangeSet changeSet = new ChangeSet();
141             changeSet.add(e, inputStream);
142             changeSet.add(e2, inputStream2);
143             final Set<Change> changeSet2 = changeSet.getChanges();
144             assertEquals(1, changeSet2.size());
145             final Change change = changeSet2.iterator().next();
146             @SuppressWarnings("resource") // Not allocated here
147             final InputStream csInputStream = change.getInputStream();
148             assertEquals(inputStream2, csInputStream);
149         }
150     }
151 
152     /**
153      * Adds an ArchiveEntry with the same name two times. Only the first addition should be found in the ChangeSet, the second add should never be added since
154      * replace = false
155      *
156      * @throws Exception Thrown on test failure. Thrown on test failure.
157      */
158     @Test
159     @SuppressWarnings({ "unchecked", "rawtypes" })
160     public void testAddChangeTwiceWithoutReplace() throws Exception {
161         try (InputStream inputStream = newInputStream("test.txt");
162                 InputStream inputStream2 = newInputStream("test2.xml")) {
163             final ArchiveEntry e = new ZipArchiveEntry("test.txt");
164             final ArchiveEntry e2 = new ZipArchiveEntry("test.txt");
165             final ChangeSet changeSet = new ChangeSet();
166             changeSet.add(e, inputStream, true);
167             changeSet.add(e2, inputStream2, false);
168             final Set<Change> changes = changeSet.getChanges();
169             assertEquals(1, changes.size());
170             final Change c = changes.iterator().next();
171             @SuppressWarnings("resource")
172             final InputStream csInputStream = c.getInputStream();
173             assertEquals(inputStream, csInputStream);
174         }
175     }
176 
177     /**
178      * add blub/test.txt + delete blub Should add blub/test.txt and delete it afterwards. In this example, the archive should stay untouched.
179      *
180      * @throws Exception Thrown on test failure. Thrown on test failure.
181      */
182     @Test
183     @SuppressWarnings({ "unchecked", "rawtypes" })
184     public void testAddDeleteAdd() throws Exception {
185         final String archiverName = "cpio";
186         final Path inputPath = createArchive(archiverName);
187         final Path result = Files.createTempFile("test", "." + archiverName);
188         try (InputStream inputStream = Files.newInputStream(inputPath);
189                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
190                 OutputStream newOutputStream = Files.newOutputStream(result);
191                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
192                 InputStream csInputStream = Files.newInputStream(getPath("test.txt"))) {
193             setLongFileMode(archiveOutputStream);
194             final ChangeSet changeSet = new ChangeSet();
195             final ArchiveEntry entry = new CpioArchiveEntry("blub/test.txt");
196             changeSet.add(entry, csInputStream);
197             archiveList.add("blub/test.txt");
198             changeSet.deleteDir("blub");
199             archiveListDeleteDir("blub");
200             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
201         } finally {
202             checkArchiveContent(result, archiveList);
203             forceDelete(result);
204         }
205 
206     }
207 
208     /**
209      * Check can add and delete a file to an archive with a single file
210      *
211      * @param archiverName archiver name.
212      * @throws Exception Thrown on test failure. Thrown on test failure.
213      */
214     @ParameterizedTest
215     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
216     @SuppressWarnings({ "unchecked", "rawtypes" })
217     public void testAddDeleteToOneFileArchive(final String archiverName) throws Exception {
218         final Path inputPath = createSingleEntryArchive(archiverName);
219         final Path result = Files.createTempFile("test", "." + archiverName);
220         final ChangeSet changeSet = new ChangeSet();
221         final File file = getFile("test.txt");
222         try (InputStream inputStream = Files.newInputStream(inputPath);
223                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
224                 OutputStream newOutputStream = Files.newOutputStream(result);
225                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
226                 InputStream csInputStream = Files.newInputStream(file.toPath())) {
227             setLongFileMode(archiveOutputStream);
228             final ArchiveEntry entry = archiveOutputStream.createArchiveEntry(file, "bla/test.txt");
229             changeSet.add(entry, csInputStream);
230             archiveList.add("bla/test.txt");
231             changeSet.delete("test1.xml");
232             archiveListDelete("test1.xml");
233             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
234         } finally {
235             checkArchiveContent(result, archiveList);
236             forceDelete(result);
237         }
238     }
239 
240     /**
241      * TODO: Move operations are not supported currently
242      *
243      * add dir1/bla.txt + mv dir1/test.text dir2/test.txt + delete dir1
244      *
245      * Add dir1/bla.txt should be suppressed. All other dir1 files will be deleted, except dir1/test.text will be moved
246      *
247      * @throws Exception Thrown on test failure. Thrown on test failure.
248      */
249     @Test
250     public void testAddMoveDelete() throws Exception {
251     }
252 
253     /**
254      * Check can add a file to an empty archive.
255      *
256      * @param archiverName archiver name.
257      * @throws Exception Thrown on test failure. Thrown on test failure.
258      */
259     @ParameterizedTest
260     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getEmptyOutputArchiveNames")
261     @SuppressWarnings({ "unchecked", "rawtypes" })
262     public void testAddToEmptyArchive(final String archiverName) throws Exception {
263         final Path inputPath = createEmptyArchive(archiverName);
264         final Path result = Files.createTempFile("test", "." + archiverName);
265         final ChangeSet changeSet = new ChangeSet();
266         try (InputStream inputStream = Files.newInputStream(inputPath);
267                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
268                 OutputStream newOutputStream = Files.newOutputStream(result);
269                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
270                 InputStream csInputStream = Files.newInputStream(getPath("test.txt"))) {
271             setLongFileMode(archiveOutputStream);
272             final ArchiveEntry entry = new ZipArchiveEntry("bla/test.txt");
273             changeSet.add(entry, csInputStream);
274             archiveList.add("bla/test.txt");
275             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
276         } finally {
277             checkArchiveContent(result, archiveList);
278             forceDelete(result);
279         }
280     }
281 
282     /**
283      * Checks for the correct ChangeSetResults
284      *
285      * @param archiverName archiver name.
286      * @throws Exception Thrown on test failure. Thrown on test failure.
287      */
288     @ParameterizedTest
289     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
290     @SuppressWarnings({ "unchecked", "rawtypes" })
291     public void testChangeSetResults(final String archiverName) throws Exception {
292         final Path inputPath = createArchive(archiverName);
293         final Path result = Files.createTempFile("test", "." + archiverName);
294         final File file1 = getFile("test.txt");
295         try (InputStream inputStream = Files.newInputStream(inputPath);
296                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
297                 OutputStream newOutputStream = Files.newOutputStream(result);
298                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
299                 InputStream csInputStream = Files.newInputStream(file1.toPath())) {
300             setLongFileMode(archiveOutputStream);
301             final ChangeSet changeSet = new ChangeSet();
302             changeSet.deleteDir("bla");
303             archiveListDeleteDir("bla");
304             // Add a file
305             final ArchiveEntry entry = archiveOutputStream.createArchiveEntry(file1, "bla/test.txt");
306             changeSet.add(entry, csInputStream);
307             archiveList.add("bla/test.txt");
308             final ChangeSetResults results = new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
309             inputStream.close();
310             // Checks
311             assertEquals(1, results.getAddedFromChangeSet().size());
312             assertEquals("bla/test.txt", results.getAddedFromChangeSet().iterator().next());
313             assertEquals(3, results.getDeleted().size());
314             assertTrue(results.getDeleted().contains("bla/test4.xml"));
315             assertTrue(results.getDeleted().contains("bla/test5.xml"));
316             assertTrue(results.getDeleted().contains("bla/blubber/test6.xml"));
317 
318             assertTrue(results.getAddedFromStream().contains("testdata/test1.xml"));
319             assertTrue(results.getAddedFromStream().contains("testdata/test2.xml"));
320             assertTrue(results.getAddedFromStream().contains("test/test3.xml"));
321             assertTrue(results.getAddedFromStream().contains("test.txt"));
322             assertTrue(results.getAddedFromStream().contains("something/bla"));
323             assertTrue(results.getAddedFromStream().contains("test with spaces.txt"));
324             assertEquals(6, results.getAddedFromStream().size());
325         } finally {
326             checkArchiveContent(result, archiveList);
327             forceDelete(result);
328         }
329 
330     }
331 
332     /**
333      * delete bla + add bla/test.txt + delete bla Deletes dir1/* first, then suppresses the add of bla.txt because there is a delete operation later.
334      *
335      * @throws Exception Thrown on test failure. Thrown on test failure.
336      */
337     @Test
338     @SuppressWarnings({ "unchecked", "rawtypes" })
339     public void testDeleteAddDelete() throws Exception {
340         final String archiverName = "cpio";
341         final Path inputPath = createArchive(archiverName);
342         final Path result = Files.createTempFile("test", "." + archiverName);
343         try (InputStream inputStream = Files.newInputStream(inputPath);
344                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
345                 OutputStream newOutputStream = Files.newOutputStream(result);
346                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
347                 InputStream csInputStream = Files.newInputStream(getPath("test.txt"))) {
348             setLongFileMode(archiveOutputStream);
349             final ChangeSet changeSet = new ChangeSet();
350             changeSet.deleteDir("bla");
351             final ArchiveEntry entry = new CpioArchiveEntry("bla/test.txt");
352             changeSet.add(entry, csInputStream);
353             archiveList.add("bla/test.txt");
354             changeSet.deleteDir("bla");
355             archiveListDeleteDir("bla");
356             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
357         } finally {
358             checkArchiveContent(result, archiveList);
359             forceDelete(result);
360         }
361 
362     }
363 
364     /**
365      * Check can delete and add a file to an archive with a single file
366      *
367      * @param archiverName archiver name.
368      * @throws Exception Thrown on test failure. Thrown on test failure.
369      */
370     @ParameterizedTest
371     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
372     @SuppressWarnings({ "unchecked", "rawtypes" })
373     public void testDeleteAddToOneFileArchive(final String archiverName) throws Exception {
374         final Path inputPath = createSingleEntryArchive(archiverName);
375         final Path result = Files.createTempFile("test", "." + archiverName);
376         final ChangeSet changeSet = new ChangeSet();
377         final File file = getFile("test.txt");
378         try (InputStream inputStream = Files.newInputStream(inputPath);
379                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
380                 OutputStream newOutputStream = Files.newOutputStream(result);
381                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
382                 InputStream csInputStream = Files.newInputStream(file.toPath())) {
383             setLongFileMode(archiveOutputStream);
384             changeSet.delete("test1.xml");
385             archiveListDelete("test1.xml");
386             final ArchiveEntry entry = archiveOutputStream.createArchiveEntry(file, "bla/test.txt");
387             changeSet.add(entry, csInputStream);
388             archiveList.add("bla/test.txt");
389             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
390         } finally {
391             checkArchiveContent(result, archiveList);
392             forceDelete(result);
393         }
394 
395     }
396 
397     /**
398      * Tries to delete the folder "bla" from an archive file. This should result in the deletion of bla/*, which actually means bla/test4.xml should be removed
399      * from the archive. The file something/bla (without ending, named like the folder) should not be deleted.
400      *
401      * @param archiverName archiver name.
402      * @throws Exception Thrown on test failure. Thrown on test failure.
403      */
404     @ParameterizedTest
405     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
406     @SuppressWarnings({ "unchecked", "rawtypes" })
407     public void testDeleteDir(final String archiverName) throws Exception {
408         final Path inputPath = createArchive(archiverName);
409         final Path result = Files.createTempFile("test", "." + archiverName);
410         try (InputStream inputStream = Files.newInputStream(inputPath);
411                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
412                 OutputStream newOutputStream = Files.newOutputStream(result);
413                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
414             setLongFileMode(archiveOutputStream);
415             final ChangeSet changeSet = new ChangeSet();
416             changeSet.deleteDir("bla");
417             archiveListDeleteDir("bla");
418             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
419         } finally {
420             checkArchiveContent(result, archiveList);
421             forceDelete(result);
422         }
423     }
424 
425     /**
426      * Tries to delete the folder "la" from an archive file. This should result in the deletion of la/*, which should not match any files/folders.
427      *
428      * @param archiverName archiver name.
429      * @throws Exception Thrown on test failure. Thrown on test failure.
430      */
431     @ParameterizedTest
432     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
433     @SuppressWarnings({ "unchecked", "rawtypes" })
434     public void testDeleteDir2(final String archiverName) throws Exception {
435         final Path inputPath = createArchive(archiverName);
436         final Path result = Files.createTempFile("test", "." + archiverName);
437         try (InputStream inputStream = Files.newInputStream(inputPath);
438                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
439                 OutputStream newOutputStream = Files.newOutputStream(result);
440                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
441             setLongFileMode(archiveOutputStream);
442             final ChangeSet changeSet = new ChangeSet();
443             changeSet.deleteDir("la");
444             archiveListDeleteDir("la");
445             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
446         } finally {
447             checkArchiveContent(result, archiveList);
448             forceDelete(result);
449         }
450     }
451 
452     /**
453      * Tries to delete the folder "test.txt" from an archive file. This should not match any files/folders.
454      *
455      * @param archiverName archiver name.
456      * @throws Exception Thrown on test failure. Thrown on test failure.
457      */
458     @ParameterizedTest
459     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
460     @SuppressWarnings({ "unchecked", "rawtypes" })
461     public void testDeleteDir3(final String archiverName) throws Exception {
462         final Path inputPath = createArchive(archiverName);
463         final Path result = Files.createTempFile("test", "." + archiverName);
464         try (InputStream inputStream = Files.newInputStream(inputPath);
465                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
466                 OutputStream newOutputStream = Files.newOutputStream(result);
467                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
468             setLongFileMode(archiveOutputStream);
469             final ChangeSet changeSet = new ChangeSet();
470             changeSet.deleteDir("test.txt");
471             archiveListDeleteDir("test.txt");
472             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
473         } finally {
474             checkArchiveContent(result, archiveList);
475             forceDelete(result);
476         }
477     }
478 
479     /**
480      * Tries to delete the file "bla/test5.xml" from an archive. This should result in the deletion of "bla/test5.xml".
481      *
482      * @param archiverName archiver name.
483      * @throws Exception Thrown on test failure. Thrown on test failure.
484      */
485     @ParameterizedTest
486     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
487     @SuppressWarnings({ "unchecked", "rawtypes" })
488     public void testDeleteFile(final String archiverName) throws Exception {
489         final Path inputPath = createArchive(archiverName);
490         final Path result = Files.createTempFile("test", "." + archiverName);
491         try (InputStream inputStream = Files.newInputStream(inputPath);
492                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
493                 OutputStream newOutputStream = Files.newOutputStream(result);
494                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
495             setLongFileMode(archiveOutputStream);
496             final ChangeSet changeSet = new ChangeSet();
497             changeSet.delete("bla/test5.xml");
498             archiveListDelete("bla/test5.xml");
499             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
500         } finally {
501             checkArchiveContent(result, archiveList);
502             forceDelete(result);
503         }
504     }
505 
506     /**
507      * Tries to delete the file "bla" from an archive. This should result in the deletion of nothing.
508      *
509      * @param archiverName archiver name.
510      * @throws Exception Thrown on test failure. Thrown on test failure.
511      */
512     @ParameterizedTest
513     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
514     @SuppressWarnings({ "unchecked", "rawtypes" })
515     public void testDeleteFile2(final String archiverName) throws Exception {
516         final Path inputPath = createArchive(archiverName);
517         final Path result = Files.createTempFile("test", "." + archiverName);
518         try (InputStream inputStream = Files.newInputStream(inputPath);
519                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
520                 OutputStream newOutputStream = Files.newOutputStream(result);
521                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
522             setLongFileMode(archiveOutputStream);
523             final ChangeSet changeSet = new ChangeSet();
524             changeSet.delete("bla");
525             // archiveListDelete("bla");
526             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
527         } finally {
528             checkArchiveContent(result, archiveList);
529             forceDelete(result);
530         }
531     }
532 
533     /**
534      * Deletes a file from an AR-archive and adds another
535      *
536      * @throws Exception Thrown on test failure. Thrown on test failure.
537      */
538     @Test
539     @SuppressWarnings({ "unchecked", "rawtypes" })
540     public void testDeleteFromAndAddToAr() throws Exception {
541         final ChangeSet changeSet = new ChangeSet();
542         changeSet.delete("test2.xml");
543         final File file1 = getFile("test.txt");
544         final ArArchiveEntry entry = new ArArchiveEntry("test.txt", file1.length());
545         final Path result = getTempDirFile().toPath().resolve("bla.ar");
546         final String archiverName = "ar";
547         try (InputStream inputStream = Files.newInputStream(getPath("bla.ar"));
548                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
549                 OutputStream newOutputStream = Files.newOutputStream(result);
550                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
551                 InputStream csInputStream = Files.newInputStream(file1.toPath())) {
552             changeSet.add(entry, csInputStream);
553             setLongFileMode(archiveOutputStream);
554             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
555         }
556         final List<String> expected = new ArrayList<>();
557         expected.add("test1.xml");
558         expected.add("test.txt");
559         checkArchiveContent(result, expected);
560     }
561 
562     /**
563      * Delete from a jar file and add another file
564      *
565      * @throws Exception Thrown on test failure. Thrown on test failure.
566      */
567     @Test
568     @SuppressWarnings({ "unchecked", "rawtypes" })
569     public void testDeleteFromAndAddToJar() throws Exception {
570         final ChangeSet changeSet = new ChangeSet();
571         changeSet.delete("test2.xml");
572         changeSet.deleteDir("META-INF");
573         changeSet.delete(".classpath");
574         changeSet.delete(".project");
575         final File input = getFile("bla.jar");
576         final Path result = getTempDirFile().toPath().resolve("bla.jar");
577         final String archiverName = "jar";
578         try (InputStream inputStream = Files.newInputStream(input.toPath());
579                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
580                 OutputStream newOutputStream = Files.newOutputStream(result);
581                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
582                 InputStream csInputStream = Files.newInputStream(getPath("test.txt"))) {
583             changeSet.add(new JarArchiveEntry("testdata/test.txt"), csInputStream);
584             setLongFileMode(archiveOutputStream);
585             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
586         }
587         final List<String> expected = new ArrayList<>();
588         expected.add("test1.xml");
589         expected.add("testdata/test.txt");
590         checkArchiveContent(result, expected);
591     }
592 
593     @Test
594     @SuppressWarnings({ "unchecked", "rawtypes" })
595     public void testDeleteFromAndAddToTar() throws Exception {
596         final ChangeSet changeSet = new ChangeSet();
597         changeSet.delete("test2.xml");
598         final File file1 = getFile("test.txt");
599         final TarArchiveEntry entry = new TarArchiveEntry("testdata/test.txt");
600         entry.setModTime(0);
601         entry.setSize(file1.length());
602         entry.setUserId(0);
603         entry.setGroupId(0);
604         entry.setUserName("avalon");
605         entry.setGroupName("excalibur");
606         entry.setMode(0100000);
607         final File result = newTempFile("bla.tar");
608         final String archiverName = "tar";
609         try (InputStream inputStream = Files.newInputStream(getPath("bla.tar"));
610                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
611                 OutputStream newOutputStream = Files.newOutputStream(result.toPath());
612                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
613                 InputStream csInputStream = Files.newInputStream(file1.toPath())) {
614             changeSet.add(entry, csInputStream);
615             setLongFileMode(archiveOutputStream);
616             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
617         }
618         final List<String> expected = new ArrayList<>();
619         expected.add("test1.xml");
620         expected.add("testdata/test.txt");
621         try (InputStream inputStream = Files.newInputStream(result.toPath());
622                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream)) {
623             checkArchiveContent(archiveInputStream, expected);
624         }
625     }
626 
627     /**
628      * Adds a file to a ZIP archive. Deletes another file.
629      *
630      * @throws Exception Thrown on test failure. Thrown on test failure.
631      */
632     @Test
633     @SuppressWarnings({ "unchecked", "rawtypes" })
634     public void testDeleteFromAndAddToZip() throws Exception {
635         final String archiverName = "zip";
636         final Path input = createArchive(archiverName);
637         final Path result = Files.createTempFile("test", "." + archiverName);
638         try (InputStream inputStream = Files.newInputStream(input);
639                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
640                 OutputStream newOutputStream = Files.newOutputStream(result);
641                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
642                 InputStream csInputStream = Files.newInputStream(getPath("test.txt"))) {
643             setLongFileMode(archiveOutputStream);
644             final ChangeSet changeSet = new ChangeSet();
645 
646             final ArchiveEntry entry = new ZipArchiveEntry("blub/test.txt");
647             changeSet.add(entry, csInputStream);
648             archiveList.add("blub/test.txt");
649             changeSet.delete("testdata/test1.xml");
650             archiveListDelete("testdata/test1.xml");
651             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
652         } finally {
653             checkArchiveContent(result, archiveList);
654             forceDelete(result);
655         }
656     }
657 
658     /**
659      * Adds a file to a ZIP archive. Deletes another file.
660      *
661      * @throws Exception Thrown on test failure. Thrown on test failure.
662      */
663     @Test
664     @SuppressWarnings({ "unchecked", "rawtypes" })
665     public void testDeleteFromAndAddToZipUsingZipFilePerform() throws Exception {
666         final String archiverName = "zip";
667         final Path input = createArchive(archiverName);
668         final Path result = Files.createTempFile("test", "." + archiverName);
669         try (ZipFile archiveInputStream = ZipFile.builder().setPath(input).get();
670                 OutputStream newOutputStream = Files.newOutputStream(result);
671                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
672                 InputStream csInputStream = Files.newInputStream(getPath("test.txt"))) {
673             setLongFileMode(archiveOutputStream);
674             final ChangeSet changeSet = new ChangeSet();
675             final ArchiveEntry entry = new ZipArchiveEntry("blub/test.txt");
676             changeSet.add(entry, csInputStream);
677             archiveList.add("blub/test.txt");
678             changeSet.delete("testdata/test1.xml");
679             archiveListDelete("testdata/test1.xml");
680             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
681         } finally {
682             checkArchiveContent(result, archiveList);
683             forceDelete(result);
684         }
685     }
686 
687     /**
688      * Simple delete from an ar file
689      *
690      * @throws Exception Thrown on test failure. Thrown on test failure.
691      */
692     @Test
693     @SuppressWarnings({ "unchecked", "rawtypes" })
694     public void testDeleteFromAr() throws Exception {
695         final ChangeSet changeSet = new ChangeSet();
696         changeSet.delete("test2.xml");
697         final File input = getFile("bla.ar");
698         final File result = newTempFile("bla.ar");
699         final String archiverName = "ar";
700         try (InputStream inputStream = Files.newInputStream(input.toPath());
701                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
702                 OutputStream newOutputStream = Files.newOutputStream(result.toPath());
703                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
704             setLongFileMode(archiveOutputStream);
705             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
706         }
707         final List<String> expected = new ArrayList<>();
708         expected.add("test1.xml");
709         checkArchiveContent(result, expected);
710     }
711 
712     /**
713      * Simple delete from a jar file
714      *
715      * @param archiverName archiver name.
716      * @throws Exception Thrown on test failure.
717      */
718     @ParameterizedTest
719     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getZipOutputArchiveNames")
720     @SuppressWarnings({ "unchecked", "rawtypes" })
721     public void testDeleteFromJar(final String archiverName) throws Exception {
722         final ChangeSet changeSet = new ChangeSet();
723         changeSet.delete("test2.xml");
724         changeSet.deleteDir("META-INF");
725         changeSet.delete(".classpath");
726         changeSet.delete(".project");
727         final File input = getFile("bla.jar");
728         final File result = newTempFile("bla.jar");
729         try (InputStream inputStream = Files.newInputStream(input.toPath());
730                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
731                 OutputStream newOutputStream = Files.newOutputStream(result.toPath());
732                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
733             setLongFileMode(archiveOutputStream);
734             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
735         }
736         final List<String> expected = new ArrayList<>();
737         expected.add("test1.xml");
738         checkArchiveContent(result, expected);
739     }
740 
741     /**
742      * Simple delete from a tar file
743      *
744      * @throws Exception Thrown on test failure.
745      */
746     @Test
747     @SuppressWarnings({ "unchecked", "rawtypes" })
748     public void testDeleteFromTar() throws Exception {
749         final ChangeSet changeSet = new ChangeSet();
750         changeSet.delete("test2.xml");
751         final File result = newTempFile("bla.tar");
752         final String archiverName = "tar";
753         try (InputStream inputStream = Files.newInputStream(getFile("bla.tar").toPath());
754                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
755                 OutputStream newOutputStream = Files.newOutputStream(result.toPath());
756                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
757             setLongFileMode(archiveOutputStream);
758             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
759         }
760         final List<String> expected = new ArrayList<>();
761         expected.add("test1.xml");
762         checkArchiveContent(result, expected);
763     }
764 
765     /**
766      * Simple Delete from a ZIP file.
767      *
768      * @param archiverName archiver name.
769      * @throws Exception Thrown on test failure.
770      */
771     @ParameterizedTest
772     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getZipOutputArchiveNames")
773     @SuppressWarnings({ "unchecked", "rawtypes" })
774     public void testDeleteFromZip(final String archiverName) throws Exception {
775         final ChangeSet changeSet = new ChangeSet();
776         changeSet.delete("test2.xml");
777         final File inputFile = getFile("bla.zip");
778         final Path result = Files.createTempFile("test", ".zip");
779         try (InputStream inputStream = Files.newInputStream(inputFile.toPath());
780                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
781                 OutputStream newOutputStream = Files.newOutputStream(result);
782                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream)) {
783             setLongFileMode(archiveOutputStream);
784             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
785         } finally {
786             final List<String> expected = new ArrayList<>();
787             expected.add("test1.xml");
788             checkArchiveContent(result, expected);
789             forceDelete(result);
790         }
791     }
792 
793     /**
794      * Tries to delete a directory with a file and adds a new directory with a new file and with the same name. Should delete dir1/* and add dir1/test.txt at
795      * the end
796      *
797      * @param archiverName archiver name.
798      * @throws Exception Thrown on test failure.
799      */
800     @ParameterizedTest
801     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
802     @SuppressWarnings({ "unchecked", "rawtypes" })
803     public void testDeletePlusAdd(final String archiverName) throws Exception {
804         final Path inputPath = createArchive(archiverName);
805         final Path result = Files.createTempFile("test", "." + archiverName);
806         final File file1 = getFile("test.txt");
807         try (InputStream inputStream = Files.newInputStream(inputPath);
808                 ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
809                 OutputStream newOutputStream = Files.newOutputStream(result);
810                 ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
811                 InputStream csInputStream = Files.newInputStream(file1.toPath())) {
812             setLongFileMode(archiveOutputStream);
813             final ChangeSet changeSet = new ChangeSet();
814             changeSet.deleteDir("bla");
815             archiveListDeleteDir("bla");
816             // Add a file
817             final ArchiveEntry entry = archiveOutputStream.createArchiveEntry(file1, "bla/test.txt");
818             changeSet.add(entry, csInputStream);
819             archiveList.add("bla/test.txt");
820             new ChangeSetPerformer(changeSet).perform(archiveInputStream, archiveOutputStream);
821         } finally {
822             checkArchiveContent(result, archiveList);
823             forceDelete(result);
824         }
825     }
826 
827     /**
828      * Tries to delete and then add a file with the same name. Should delete test/test3.xml and adds test.txt with the name test/test3.xml
829      *
830      * @param archiverName archiver name.
831      * @throws Exception Thrown on test failure.
832      */
833     @ParameterizedTest
834     @MethodSource("org.apache.commons.compress.changes.TestFixtures#getOutputArchiveNames")
835     @SuppressWarnings({ "unchecked", "rawtypes" })
836     public void testDeletePlusAddSame(final String archiverName) throws Exception {
837         final Path inputPath = createArchive(archiverName);
838         final File testTxt = getFile("test.txt");
839         final Path result = Files.createTempFile("test", "." + archiverName);
840         try {
841             try (InputStream inputStream = Files.newInputStream(inputPath);
842                     ArchiveInputStream archiveInputStream = factory.createArchiveInputStream(archiverName, inputStream);
843                     OutputStream newOutputStream = Files.newOutputStream(result);
844                     ArchiveOutputStream archiveOutputStream = factory.createArchiveOutputStream(archiverName, newOutputStream);
845                     InputStream csInputStream = Files.newInputStream(testTxt.toPath())) {
846                 setLongFileMode(archiveOutputStream);
847                 final ChangeSet changes = new ChangeSet();
848                 changes.delete("test/test3.xml");
849                 archiveListDelete("test/test3.xml");
850                 // Add a file
851                 final ArchiveEntry entry = archiveOutputStream.createArchiveEntry(testTxt, "test/test3.xml");
852                 changes.add(entry, csInputStream);
853                 archiveList.add("test/test3.xml");
854                 new ChangeSetPerformer(changes).perform(archiveInputStream, archiveOutputStream);
855             }
856             // Checks
857             try (BufferedInputStream buf = new BufferedInputStream(Files.newInputStream(result));
858                     ArchiveInputStream in = factory.createArchiveInputStream(buf)) {
859                 final File check = checkArchiveContent(in, archiveList, false);
860                 final File test3xml = new File(check, "result/test/test3.xml");
861                 assertEquals(testTxt.length(), test3xml.length());
862 
863                 try (BufferedReader reader = new BufferedReader(Files.newBufferedReader(test3xml.toPath()))) {
864                     String str;
865                     while ((str = reader.readLine()) != null) {
866                         // All lines look like this
867                         "111111111111111111111111111000101011".equals(str);
868                     }
869                 }
870                 forceDelete(check);
871             }
872         } finally {
873             forceDelete(result);
874         }
875     }
876 
877     /**
878      * TODO: Move operations are not supported currently
879      *
880      * mv dir1/test.text dir2/test.txt + delete dir1 Moves the file to dir2 and deletes everything in dir1
881      */
882     @Test
883     public void testRenameAndDelete() {
884     }
885 
886 }