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