1   package com.atlassian.maven.plugins.amps.util;
2   
3   import org.apache.commons.io.FileUtils;
4   import org.junit.After;
5   import org.junit.Before;
6   import org.junit.Test;
7   
8   import com.google.inject.internal.util.Lists;
9   
10  import java.io.File;
11  import java.io.IOException;
12  import java.net.URISyntaxException;
13  import java.net.URL;
14  import java.util.Enumeration;
15  import java.util.List;
16  import java.util.UUID;
17  import java.util.zip.ZipEntry;
18  import java.util.zip.ZipFile;
19  
20  import static org.hamcrest.core.IsEqual.equalTo;
21  import static org.hamcrest.core.IsNot.not;
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertThat;
24  import static org.junit.Assert.assertTrue;
25  
26  public class TestZipUtils
27  {
28      public static final int NUM_FILES = 2;
29      public static final int NUM_FOLDERS = 4;
30      public static final int NUM_FOLDERS_NESTED_PREFIX = NUM_FOLDERS + 1;
31  
32      public static final String ROOT_DIR = "test-zip-dir";
33      public static final String FIRST_PREFIX = "prefix1";
34      public static final String SECOND_PREFIX = "prefix2";
35      public static final String NESTED_PREFIX = FIRST_PREFIX + "/" + SECOND_PREFIX;
36  
37      private File tempDir;
38      private File sourceZipDir;
39      private ZipFile zip;
40  
41      @Before
42      public void ensureDirsExist() throws IOException
43      {
44  
45          // Create the temp dir
46          final File sysTempDir = new File(System.getProperty("java.io.tmpdir"));
47          String dirName = UUID.randomUUID().toString();
48          tempDir = new File(sysTempDir, dirName);
49          tempDir.mkdirs();
50  
51          // Create our test source tree
52          sourceZipDir = new File(tempDir, ROOT_DIR);
53          File level2sub1 = new File(sourceZipDir, "level2sub1");
54          File level2sub2 = new File(sourceZipDir, "level2sub2");
55          File level3sub1 = new File(level2sub2, "level3sub1");
56  
57          File level2TextFile = new File(level2sub2, "level2sub2.txt");
58          File level3TextFile = new File(level3sub1, "level3sub1.txt");
59  
60          level2sub1.mkdirs();
61          level3sub1.mkdirs();
62  
63          FileUtils.writeStringToFile(level2TextFile, "level2sub2");
64          FileUtils.writeStringToFile(level3TextFile, "level3sub1");
65      }
66  
67      @After
68      public void removeTempDir() throws IOException
69      {
70          // make sure zip is closed, else delete fails on windows
71          if (zip != null)
72          {
73              try
74              {
75                  zip.close();
76              }
77              catch (IOException e)
78              {
79                  // ignore
80              }
81              zip = null;
82          }
83          FileUtils.deleteDirectory(tempDir);
84      }
85  
86      @Test
87      public void zipContainsSinglePrefix() throws IOException
88      {
89          File zipFile = new File(tempDir, "zip-with-prefix.zip");
90          ZipUtils.zipDir(zipFile, sourceZipDir, FIRST_PREFIX);
91  
92          zip = new ZipFile(zipFile);
93          final Enumeration<? extends ZipEntry> entries = zip.entries();
94  
95          while (entries.hasMoreElements())
96          {
97              final ZipEntry zipEntry = entries.nextElement();
98              String zipPath = zipEntry.getName();
99              String testPrefix = zipPath.substring(0, zipPath.indexOf("/"));
100 
101             assertEquals(FIRST_PREFIX, testPrefix);
102         }
103     }
104 
105     @Test
106     public void zipContainsNestedPrefix() throws IOException
107     {
108         File zipFile = new File(tempDir, "zip-nested-prefix.zip");
109         ZipUtils.zipDir(zipFile, sourceZipDir, NESTED_PREFIX);
110 
111         zip = new ZipFile(zipFile);
112         final Enumeration<? extends ZipEntry> entries = zip.entries();
113 
114         while (entries.hasMoreElements())
115         {
116             final ZipEntry zipEntry = entries.nextElement();
117             String zipPath = zipEntry.getName();
118             String[] segments = zipPath.split("/");
119             if (segments.length > 1)
120             {
121                 String testPrefix = segments[0] + "/" + segments[1];
122 
123                 assertEquals(NESTED_PREFIX, testPrefix);
124             }
125         }
126     }
127 
128     @Test
129     public void prefixedZipDoesNotContainRootDir() throws IOException
130     {
131         File zipFile = new File(tempDir, "zip-with-prefix-no-root.zip");
132         ZipUtils.zipDir(zipFile, sourceZipDir, FIRST_PREFIX);
133 
134         zip = new ZipFile(zipFile);
135         final Enumeration<? extends ZipEntry> entries = zip.entries();
136 
137         while (entries.hasMoreElements())
138         {
139             final ZipEntry zipEntry = entries.nextElement();
140             String zipPath = zipEntry.getName();
141             String[] segments = zipPath.split("/");
142             if (segments.length > 1)
143             {
144                 String rootPath = segments[1];
145 
146                 assertThat(rootPath, not(equalTo(ROOT_DIR)));
147             }
148         }
149     }
150 
151     @Test
152     public void nestedPrefixedZipDoesNotContainRootDir() throws IOException
153     {
154         File zipFile = new File(tempDir, "zip-nested-prefix-no-root.zip");
155         ZipUtils.zipDir(zipFile, sourceZipDir, NESTED_PREFIX);
156 
157         zip = new ZipFile(zipFile);
158         final Enumeration<? extends ZipEntry> entries = zip.entries();
159 
160         while (entries.hasMoreElements())
161         {
162             final ZipEntry zipEntry = entries.nextElement();
163             String zipPath = zipEntry.getName();
164             String[] segments = zipPath.split("/");
165             if (segments.length > 2)
166             {
167                 String rootPath = segments[2];
168 
169                 assertThat(rootPath, not(equalTo(ROOT_DIR)));
170             }
171         }
172     }
173 
174     @Test
175     public void emptyPrefixedZipContainsRootDir() throws IOException
176     {
177         File zipFile = new File(tempDir, "zip-empty-prefix.zip");
178         ZipUtils.zipDir(zipFile, sourceZipDir, "");
179 
180         zip = new ZipFile(zipFile);
181         final Enumeration<? extends ZipEntry> entries = zip.entries();
182 
183         while (entries.hasMoreElements())
184         {
185             final ZipEntry zipEntry = entries.nextElement();
186             String zipPath = zipEntry.getName();
187             String rootPath = zipPath.substring(0, zipPath.indexOf("/"));
188 
189             assertEquals(ROOT_DIR, rootPath);
190         }
191     }
192 
193     @Test
194     public void nullPrefixedZipContainsRootDir() throws IOException
195     {
196         File zipFile = new File(tempDir, "zip-null-prefix.zip");
197         ZipUtils.zipDir(zipFile, sourceZipDir, null);
198 
199         zip = new ZipFile(zipFile);
200         final Enumeration<? extends ZipEntry> entries = zip.entries();
201 
202         while (entries.hasMoreElements())
203         {
204             final ZipEntry zipEntry = entries.nextElement();
205             String zipPath = zipEntry.getName();
206             String rootPath = zipPath.substring(0, zipPath.indexOf("/"));
207 
208             assertEquals(ROOT_DIR, rootPath);
209         }
210     }
211 
212     @Test
213     public void emptyPrefixedZipFolderCountMatches() throws IOException
214     {
215         File zipFile = new File(tempDir, "zip-empty-prefix.zip");
216         ZipUtils.zipDir(zipFile, sourceZipDir, "");
217 
218         zip = new ZipFile(zipFile);
219         final Enumeration<? extends ZipEntry> entries = zip.entries();
220 
221         int numFolders = 0;
222 
223         while (entries.hasMoreElements())
224         {
225             final ZipEntry zipEntry = entries.nextElement();
226             if (zipEntry.isDirectory())
227             {
228                 numFolders++;
229             }
230         }
231 
232         assertEquals(NUM_FOLDERS, numFolders);
233     }
234 
235     @Test
236     public void singlePrefixedZipFolderCountMatches() throws IOException
237     {
238         File zipFile = new File(tempDir, "zip-single-prefix.zip");
239         ZipUtils.zipDir(zipFile, sourceZipDir, FIRST_PREFIX);
240 
241         zip = new ZipFile(zipFile);
242         final Enumeration<? extends ZipEntry> entries = zip.entries();
243 
244         int numFolders = 0;
245 
246         while (entries.hasMoreElements())
247         {
248             final ZipEntry zipEntry = entries.nextElement();
249             if (zipEntry.isDirectory())
250             {
251                 numFolders++;
252             }
253         }
254 
255         assertEquals(NUM_FOLDERS, numFolders);
256     }
257 
258     @Test
259     public void nestedPrefixedZipFolderCountMatches() throws IOException
260     {
261         File zipFile = new File(tempDir, "zip-nested-prefix.zip");
262         ZipUtils.zipDir(zipFile, sourceZipDir, NESTED_PREFIX);
263 
264         zip = new ZipFile(zipFile);
265         final Enumeration<? extends ZipEntry> entries = zip.entries();
266 
267         int numFolders = 0;
268 
269         while (entries.hasMoreElements())
270         {
271             final ZipEntry zipEntry = entries.nextElement();
272             if (zipEntry.isDirectory())
273             {
274                 numFolders++;
275             }
276         }
277 
278         assertEquals(NUM_FOLDERS_NESTED_PREFIX, numFolders);
279     }
280 
281     @Test
282     public void zipFileCountMatches() throws IOException
283     {
284         File zipFile = new File(tempDir, "zip-single-prefix.zip");
285         ZipUtils.zipDir(zipFile, sourceZipDir, FIRST_PREFIX);
286 
287         zip = new ZipFile(zipFile);
288         final Enumeration<? extends ZipEntry> entries = zip.entries();
289 
290         int numFiles = 0;
291 
292         while (entries.hasMoreElements())
293         {
294             final ZipEntry zipEntry = entries.nextElement();
295             if (!zipEntry.isDirectory())
296             {
297                 numFiles++;
298             }
299         }
300 
301         assertEquals(NUM_FILES, numFiles);
302     }
303 
304     @Test
305     public void unzipNonPrefixed() throws IOException
306     {
307         File zipFile = new File(tempDir, "zip-empty-prefix.zip");
308         ZipUtils.zipDir(zipFile, sourceZipDir, "");
309 
310         File unzipDir = new File(tempDir, "unzip-empty-prefix");
311         ZipUtils.unzip(zipFile, unzipDir.getAbsolutePath());
312 
313         File rootUnzip = new File(unzipDir, ROOT_DIR);
314 
315         assertTrue("root folder in zip was not unzipped", (rootUnzip.exists() && rootUnzip.isDirectory()));
316     }
317 
318     @Test
319     public void unzipSinglePrefix() throws IOException
320     {
321         File zipFile = new File(tempDir, "zip-single-prefix.zip");
322         ZipUtils.zipDir(zipFile, sourceZipDir, FIRST_PREFIX);
323 
324         File unzipDir = new File(tempDir, "unzip-single-prefix");
325         ZipUtils.unzip(zipFile, unzipDir.getAbsolutePath());
326 
327         File rootUnzip = new File(unzipDir, FIRST_PREFIX);
328 
329         assertTrue("single prefix folder in zip was not unzipped", (rootUnzip.exists() && rootUnzip.isDirectory()));
330     }
331 
332     @Test
333     public void unzipNestedPrefix() throws IOException
334     {
335         File zipFile = new File(tempDir, "zip-nested-prefix.zip");
336         ZipUtils.zipDir(zipFile, sourceZipDir, NESTED_PREFIX);
337 
338         File unzipDir = new File(tempDir, "unzip-nested-prefix");
339         ZipUtils.unzip(zipFile, unzipDir.getAbsolutePath());
340 
341         File rootUnzip = new File(unzipDir, FIRST_PREFIX);
342         File nestedUnzip = new File(rootUnzip, SECOND_PREFIX);
343 
344         assertTrue("nested prefix folder in zip was not unzipped", (nestedUnzip.exists() && nestedUnzip.isDirectory()));
345     }
346 
347     @Test
348     public void detectPrefix() throws IOException
349     {
350         File zipFile = new File(tempDir, "zip-single-prefix.zip");
351         // zipDir will use the foldername as a prefix
352         ZipUtils.zipDir(zipFile, sourceZipDir, "");
353 
354         int nestedRoots = ZipUtils.countNestingLevel(zipFile);
355 
356         assertEquals("One level of nesting should be detected", 1, nestedRoots);
357     }
358 
359     @Test
360     public void detectDoublePrefix() throws IOException
361     {
362         File zipFile = new File(tempDir, "zip-double-prefix.zip");
363         ZipUtils.zipDir(zipFile, sourceZipDir, NESTED_PREFIX);
364 
365         int nestedRoots = ZipUtils.countNestingLevel(zipFile);
366 
367         assertEquals("Two levels of nesting should be detected", 2, nestedRoots);
368     }
369 
370     @Test
371     public void detectNoPrefix() throws IOException, URISyntaxException
372     {
373         // zip-no-root.zip is a zip with no root folder.
374         // We can't use ZipUtils#zipDir() to create it (zipDir() always puts a root folder),
375         // so we need to provide one in src/test/resources.
376         URL zipPath = TestZipUtils.class.getResource("zip-no-root.zip");
377         File zipFile = new File(zipPath.toURI());
378 
379         int nestedRoots = ZipUtils.countNestingLevel(zipFile);
380 
381         assertEquals("No nesting should be detected", 0, nestedRoots);
382     }
383 
384     @Test
385     public void unzipSinglePrefixTrimmed() throws IOException
386     {
387         File zipFile = new File(tempDir, "zip-single-prefix.zip");
388         ZipUtils.zipDir(zipFile, sourceZipDir, FIRST_PREFIX);
389 
390         File unzipDir = new File(tempDir, "unzip-single-prefix");
391         ZipUtils.unzip(zipFile, unzipDir.getAbsolutePath(), 1);
392 
393         File rootUnzip = new File(unzipDir, FIRST_PREFIX);
394 
395         assertTrue("single prefix folder in zip should have been trimmed", !rootUnzip.exists());
396     }
397 
398     @Test
399     public void unzipNestedPrefixTrimmed() throws IOException
400     {
401         File zipFile = new File(tempDir, "zip-nested-prefix.zip");
402         ZipUtils.zipDir(zipFile, sourceZipDir, NESTED_PREFIX);
403 
404         File unzipDir = new File(tempDir, "unzip-nested-prefix");
405         ZipUtils.unzip(zipFile, unzipDir.getAbsolutePath(), 2);
406 
407         File nestedUnzip = new File(unzipDir, SECOND_PREFIX);
408 
409         assertTrue("nested prefix folder in zip should have been trimmed", !nestedUnzip.exists());
410     }
411 
412 
413     @Test
414     public void countNoNestingLevel()
415     {
416         List<String> filenames = Lists.newArrayList(
417                 "file1.txt",
418                 "file2.txt");
419 
420         int nestedRoots = ZipUtils.countNestingLevel(filenames);
421         assertEquals("The number of nested roots should be detected", 0, nestedRoots);
422     }
423 
424     @Test
425     public void countOneNestingLevel()
426     {
427         List<String> filenames = Lists.newArrayList(
428                 "root/folder1/file.txt",
429                 "root/folder2/file.txt");
430 
431         int nestedRoots = ZipUtils.countNestingLevel(filenames);
432         assertEquals("The number of nested roots should be detected", 1, nestedRoots);
433     }
434 
435     @Test
436     public void countNestingLevelWithEmptyList()
437     {
438         List<String> filenames = Lists.newArrayList();
439 
440         int nestedRoots = ZipUtils.countNestingLevel(filenames);
441         assertEquals("Should work with an empty list", 0, nestedRoots);
442     }
443 
444     @Test
445     public void countTwoNestingLevel()
446     {
447         List<String> filenames = Lists.newArrayList(
448                 "root/otherRoot/file1.txt",
449                 "root/otherRoot/file2.txt");
450         int nestedRoots = ZipUtils.countNestingLevel(filenames);
451         assertEquals("The number of nested roots should be detected", 2, nestedRoots);
452     }
453 
454     @Test
455     public void countTwoNestingLevelWithEmptyDirs()
456     {
457         List<String> filenames = Lists.newArrayList(
458                 "root/",
459                 "root/otherRoot/",
460                 "root/otherRoot/file1.txt",
461                 "root/otherRoot/file2.txt");
462 
463         int nestedRoots = ZipUtils.countNestingLevel(filenames);
464         assertEquals("The number of nested roots should be detected", 2, nestedRoots);
465     }
466 
467     @Test
468     public void countTwoNestingLevelWithEmptyDirsInReversedOrder()
469     {
470         List<String> filenames = Lists.newArrayList(
471                 "root/otherRoot/file1.txt",
472                 "root/otherRoot/file2.txt",
473                 "root/otherRoot/",
474                 "root/");
475 
476         int nestedRoots = ZipUtils.countNestingLevel(filenames);
477         assertEquals("The number of nested roots should be detected", 2, nestedRoots);
478     }
479 
480     @Test
481     public void countOneNestingLevelWithEmptyDirs()
482     {
483         List<String> filenames = Lists.newArrayList(
484                 "root/folder1/file1.txt",
485                 "root/folder1/file2.txt",
486                 "root/folder1/",
487                 "root/folder2/",
488                 "root/");
489 
490         int nestedRoots = ZipUtils.countNestingLevel(filenames);
491         assertEquals("The number of nested roots should be detected", 1, nestedRoots);
492     }
493 }