View Javadoc
1   package org.codehaus.plexus.archiver.zip;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.io.UncheckedIOException;
6   import java.util.Collections;
7   import java.util.Map;
8   import java.util.function.Consumer;
9   import java.util.function.Function;
10  import java.util.stream.Collectors;
11  
12  import org.apache.commons.compress.archivers.ArchiveEntry;
13  import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
14  import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
15  import org.apache.commons.compress.archivers.zip.ZipFile;
16  import org.codehaus.plexus.archiver.tar.TarFile;
17  
18  import static org.assertj.core.api.Assertions.assertThat;
19  
20  /**
21   * A utility class, which allows to compare archive files.
22   */
23  public final class ArchiveFileComparator {
24  
25      /**
26       * Iterate over the TarFile and run the consumer on each TarArchiveEntry.
27       */
28      public static void forEachTarArchiveEntry(TarFile file, Consumer<TarArchiveEntry> consumer) {
29          try {
30              Collections.list(file.getEntries()).stream()
31                      .filter(entry -> !entry.isDirectory())
32                      .map(TarArchiveEntry.class::cast)
33                      .forEachOrdered(consumer);
34          } catch (IOException ioe) {
35              throw new UncheckedIOException(ioe);
36          }
37      }
38  
39      private static void forEachZipArchiveEntry(ZipFile file, Consumer<ZipArchiveEntry> consumer) {
40          Collections.list(file.getEntries()).stream()
41                  .filter(entry -> !entry.isDirectory())
42                  .forEachOrdered(consumer);
43      }
44  
45      /**
46       * Creates a map with the archive files contents. The map keys are the names of file entries in the archive file.
47       * The map values are the respective archive entries.
48       */
49      private static Map<String, TarArchiveEntry> getFileEntries(TarFile file) {
50          try {
51              return Collections.list(file.getEntries()).stream()
52                      .filter(entry -> !entry.isDirectory())
53                      .map(TarArchiveEntry.class::cast)
54                      .collect(Collectors.toMap(ArchiveEntry::getName, Function.identity()));
55          } catch (IOException e) {
56              throw new UncheckedIOException(e);
57          }
58      }
59  
60      /**
61       * Creates a map with the archive files contents. The map keys are the names of file entries in the archive file.
62       * The map values are the respective archive entries.
63       */
64      private static Map<String, ZipArchiveEntry> getFileEntries(ZipFile file) {
65          return Collections.list(file.getEntries()).stream()
66                  .filter(entry -> !entry.isDirectory())
67                  .collect(Collectors.toMap(ArchiveEntry::getName, Function.identity()));
68      }
69  
70      private static void assertTarEquals(TarFile file1, TarArchiveEntry entry1, TarFile file2, TarArchiveEntry entry2) {
71          assertThat(entry1.isDirectory()).isEqualTo(entry2.isDirectory());
72          assertThat(entry1.isSymbolicLink()).isEqualTo(entry2.isSymbolicLink());
73          assertThat(entry1.getLastModifiedDate()).isEqualTo(entry2.getLastModifiedDate());
74          assertThat(entry1.getUserName()).isEqualTo(entry2.getUserName());
75          assertThat(entry1.getGroupName()).isEqualTo(entry2.getGroupName());
76  
77          try (InputStream is1 = file1.getInputStream(entry1);
78                  InputStream is2 = file2.getInputStream(entry2); ) {
79              assertThat(is1)
80                      .as("Content of the entry1 %s is different of entry2 %s", entry1.getName(), entry2.getName())
81                      .hasSameContentAs(is2);
82          } catch (IOException ioe) {
83              throw new UncheckedIOException(ioe);
84          }
85      }
86  
87      private static void assertTarZipEquals(
88              TarFile file1, TarArchiveEntry entry1, ZipFile file2, ZipArchiveEntry entry2) {
89          assertThat(entry1.isDirectory()).isEqualTo(entry2.isDirectory());
90          assertThat(entry1.getLastModifiedDate()).isCloseTo(entry2.getLastModifiedDate(), 1000);
91  
92          try (InputStream is1 = file1.getInputStream(entry1);
93                  InputStream is2 = file2.getInputStream(entry2); ) {
94              assertThat(is1)
95                      .as("Content of the entry1 %s is different of entry2 %s", entry1.getName(), entry2.getName())
96                      .hasSameContentAs(is2);
97          } catch (IOException ioe) {
98              throw new UncheckedIOException(ioe);
99          }
100     }
101 
102     private static void assertZipEquals(ZipFile file1, ZipArchiveEntry entry1, ZipFile file2, ZipArchiveEntry entry2) {
103         assertThat(entry1.isDirectory()).isEqualTo(entry2.isDirectory());
104         assertThat(entry1.isUnixSymlink()).isEqualTo(entry2.isUnixSymlink());
105         assertThat(entry1.getLastModifiedDate()).isCloseTo(entry2.getLastModifiedDate(), 1000);
106 
107         try (InputStream is1 = file1.getInputStream(entry1);
108                 InputStream is2 = file2.getInputStream(entry2); ) {
109             assertThat(is1)
110                     .as("Content of the entry1 %s is different of entry2 %s", entry1.getName(), entry2.getName())
111                     .hasSameContentAs(is2);
112         } catch (IOException ioe) {
113             throw new UncheckedIOException(ioe);
114         }
115     }
116 
117     /**
118      * Called to compare the given Tar files.
119      */
120     public static void assertTarEquals(final TarFile file1, final TarFile file2, final String prefix) {
121         final Map<String, TarArchiveEntry> map2 = getFileEntries(file2);
122 
123         forEachTarArchiveEntry(file1, entry1 -> {
124             final String name2 = getNameWithPrefix(prefix, entry1.getName());
125             final TarArchiveEntry entry2 = map2.remove(name2);
126             assertThat(entry2).as("Missing entry in file2: %s", name2).isNotNull();
127             assertTarEquals(file1, entry1, file2, entry2);
128         });
129 
130         assertThat(map2).as("Found additional entries in file2").isEmpty();
131     }
132 
133     /**
134      * Called to compare the given Tar and Zip files.
135      */
136     public static void assertTarZipEquals(final TarFile file1, final ZipFile file2, final String prefix) {
137         final Map<String, ZipArchiveEntry> map2 = getFileEntries(file2);
138 
139         forEachTarArchiveEntry(file1, entry1 -> {
140             final String name2 = getNameWithPrefix(prefix, entry1.getName());
141             final ZipArchiveEntry entry2 = map2.remove(name2);
142             assertThat(entry2).as("Missing entry in file2: %s", name2).isNotNull();
143             assertTarZipEquals(file1, entry1, file2, entry2);
144         });
145 
146         assertThat(map2).as("Found additional entries in file2").isEmpty();
147     }
148 
149     /**
150      * Called to compare the given Zip files.
151      */
152     public static void assertZipEquals(final ZipFile file1, final ZipFile file2, final String prefix) {
153         final Map<String, ZipArchiveEntry> map2 = getFileEntries(file2);
154 
155         forEachZipArchiveEntry(file1, entry1 -> {
156             final String name2 = getNameWithPrefix(prefix, entry1.getName());
157             final ZipArchiveEntry entry2 = map2.remove(name2);
158             assertThat(entry2).as("Missing entry in file2: %s", name2).isNotNull();
159             assertZipEquals(file1, entry1, file2, entry2);
160         });
161 
162         assertThat(map2).as("Found additional entries in file2").isEmpty();
163     }
164 
165     private static String getNameWithPrefix(String prefix, String name) {
166         return prefix == null ? name : prefix + name;
167     }
168 }