1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import org.testng.annotations.AfterClass; 25 import org.testng.annotations.BeforeClass; 26 import org.testng.annotations.DataProvider; 27 import org.testng.annotations.Test; 28 29 import java.io.IOException; 30 import java.nio.file.*; 31 import java.nio.file.spi.FileSystemProvider; 32 import java.util.Iterator; 33 import java.util.Map; 34 import java.util.NoSuchElementException; 35 import java.util.regex.PatternSyntaxException; 36 37 import static org.testng.Assert.*; 38 39 /** 40 * @test 41 * @summary ZIP File System tests that leverage DirectoryStream 42 * @modules jdk.zipfs 43 * @compile ZipFsDirectoryStreamTests.java 44 * @run testng ZipFsDirectoryStreamTests 45 * @run testng/othervm/java.security.policy=test.policy ZipFsDirectoryStreamTests 46 */ 47 public class ZipFsDirectoryStreamTests { 48 49 // Map to used for creating a ZIP archive 50 private static final Map<String, String> ZIPFS_MAP = Map.of("create", "true"); 51 52 // Map to used for extracting a ZIP archive 53 private static final Map<String, String> UNZIPFS_MAP = Map.of(); 54 55 // The ZIP file system provider 56 private static final FileSystemProvider ZIPFS_PROVIDER = getZipFSProvider(); 57 58 // Primary jar file used for testing 59 private static Path jarFile; 60 61 // Jar file used to validate the behavior of the navigation of an empty directory 62 private static Path emptyJarFile; 63 64 /** 65 * Create the JAR files used by the tests 66 */ 67 @BeforeClass 68 public void setUp() { 69 emptyJarFile = Paths.get("emptyDir.jar"); 70 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(emptyJarFile, ZIPFS_MAP);) { 71 72 jarFile = Utils.createJarFile("basic.jar", 73 "META-INF/services/java.nio.file.spi.FileSystemProvider"); 74 75 Files.createDirectory(zipfs.getPath("emptyDir")); 76 } catch (IOException e) { 77 e.printStackTrace(); 78 } 79 } 80 81 /** 82 * Remove JAR files used by test as part of clean-up 83 */ 84 @AfterClass 85 public void tearDown() { 86 try { 87 Files.deleteIfExists(jarFile); 88 Files.deleteIfExists(emptyJarFile); 89 } catch (Exception e) { 90 e.printStackTrace(); 91 } 92 93 } 94 95 /** 96 * Validate that you can specify a DirectoryStream.Filter using the ZIP File System and that the returned 97 * Iterator correctly indicates whether the filer has been matched 98 */ 99 @Test(dataProvider = "filterTestValues") 100 public void test0000(String glob, boolean expectedResult, String errMsg) { 101 102 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 103 DirectoryStream<Path> ds = Files.newDirectoryStream(zipfs.getPath("/"), 104 new DirectoryStream.Filter<Path>() { 105 private PathMatcher matcher = 106 zipfs.getPathMatcher("glob:"+ glob); 107 public boolean accept(Path file) { 108 return matcher.matches(file.getFileName()); 109 } 110 111 })) { 112 113 assertEquals(ds.iterator().hasNext(), expectedResult, errMsg); 114 115 } catch (Exception e) { 116 e.printStackTrace(); 117 } 118 } 119 120 /** 121 * Validate that you can specify a glob using the ZIP File System and that the returned 122 * Iterator correctly indicates whether the glob pattern has been matched 123 */ 124 @Test(dataProvider = "filterTestValues") 125 public void test0001(String glob, boolean expectedResult, String errMsg) { 126 127 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 128 DirectoryStream<Path> ds = 129 Files.newDirectoryStream(zipfs.getPath("/"), glob)) { 130 assertEquals(ds.iterator().hasNext(), expectedResult, errMsg); 131 132 } catch (Exception e) { 133 e.printStackTrace(); 134 } 135 } 136 137 /** 138 * Validate a PatternSyntaxException is thrown when specifying an invalid glob pattern 139 * with the ZIP File system 140 */ 141 @Test 142 public void test0002() { 143 144 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 145 ) { 146 assertThrows(PatternSyntaxException.class, () -> 147 Files.newDirectoryStream(zipfs.getPath("/"), "*[a-z")); 148 } catch (Exception e) { 149 e.printStackTrace(); 150 } 151 } 152 153 /** 154 * Validate that the correct type of paths are returned when creating a DirectoryStream 155 */ 156 @Test(dataProvider = "startPaths") 157 public void test0003(String startPath, String expectedPath) throws IOException { 158 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 159 DirectoryStream<Path> stream = Files.newDirectoryStream(zipfs.getPath(startPath))) { 160 161 for (Path entry : stream) { 162 assertTrue(entry.toString().equals(expectedPath), 163 String.format("Error: Expected path %s not found when starting at %s%n", 164 expectedPath, entry)); 165 } 166 } 167 } 168 169 /** 170 * Validate an NotDirectoryException is thrown when specifying a file for the starting path for 171 * creating a DirectoryStream with the ZIP File System 172 */ 173 @Test 174 public void test0004() { 175 176 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP)) { 177 assertThrows(NotDirectoryException.class, 178 () -> Files.newDirectoryStream( 179 zipfs.getPath("META-INF/services/java.nio.file.spi.FileSystemProvider"))); 180 181 } catch (Exception e) { 182 e.printStackTrace(); 183 } 184 } 185 186 /** 187 * Validate a IllegalStateException is thrown when accessing the Iterator more than once 188 * with the ZIP File System 189 */ 190 @Test 191 public void test0005() { 192 193 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 194 DirectoryStream<Path> ds = 195 Files.newDirectoryStream(zipfs.getPath("/"))) { 196 ds.iterator(); 197 assertThrows(IllegalStateException.class, () -> ds.iterator()); 198 199 } catch (Exception e) { 200 e.printStackTrace(); 201 } 202 } 203 204 /** 205 * Validate a IllegalStateException is thrown when accessing the Iterator after the DirectoryStream 206 * has been closed with the ZIP File System 207 */ 208 @Test 209 public void test0006() { 210 211 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 212 DirectoryStream<Path> ds = 213 Files.newDirectoryStream(zipfs.getPath("/"))) { 214 ds.close(); 215 assertThrows(IllegalStateException.class, () -> ds.iterator()); 216 217 // ZipDirectoryStream.iterator() throws ClosedDirectoryStream when obtaining an Iterator 218 // when the DirectoryStream is closed 219 assertThrows(ClosedDirectoryStreamException.class, () -> ds.iterator()); 220 221 } catch (Exception e) { 222 e.printStackTrace(); 223 } 224 } 225 226 /** 227 * Validate an UnsupportedOperationException is thrown when invoking an Iterator operation that is not 228 * supported with the ZIP File System 229 */ 230 @Test 231 public void test0007() { 232 233 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 234 DirectoryStream<Path> ds = 235 Files.newDirectoryStream(zipfs.getPath("/"))) { 236 Iterator<Path> i = ds.iterator(); 237 238 //System.out.println("Path: "+ i.next()); 239 assertThrows(UnsupportedOperationException.class, () -> i.remove()); 240 } catch (Exception e) { 241 e.printStackTrace(); 242 } 243 } 244 245 /** 246 * Validate an NoSuchElementException is thrown when invoking an Iterator.next() on a closed 247 * DirectoryStream with the ZIP File System 248 */ 249 @Test 250 public void test0008() { 251 252 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 253 DirectoryStream<Path> ds = 254 Files.newDirectoryStream(zipfs.getPath("/"))) { 255 Iterator<Path> i = ds.iterator(); 256 ds.close(); 257 assertThrows(NoSuchElementException.class, () -> i.next()); 258 } catch (Exception e) { 259 e.printStackTrace(); 260 } 261 } 262 263 /** 264 * Validate Iterator.hasNext() returns false when the directory is empty with the ZIP File System 265 */ 266 @Test 267 public void test0009() { 268 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(emptyJarFile, ZIPFS_MAP); 269 DirectoryStream<Path> ds = Files.newDirectoryStream(zipfs.getPath("emptyDir"))) { 270 assertFalse(ds.iterator().hasNext(), "Error: directory was not empty!"); 271 272 } catch(Exception e) { 273 e.printStackTrace(); 274 275 } 276 } 277 278 /** 279 * Validate Iterator.hasNext() returns false when the DirectoryStream is closed 280 * with the ZIP File System 281 */ 282 @Test 283 public void test0010() { 284 285 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 286 DirectoryStream<Path> ds = 287 Files.newDirectoryStream(zipfs.getPath("/"))) { 288 Iterator<Path> i = ds.iterator(); 289 ds.close(); 290 assertFalse(i.hasNext(), "Error: false should be returned as DirectoryStream is closed!"); 291 } catch (Exception e) { 292 e.printStackTrace(); 293 } 294 } 295 296 /** 297 * Validate that an IOException thrown by a filter is returned as the cause 298 * via a DirectoryIteratorException 299 */ 300 @Test 301 public void test0011() { 302 303 try (FileSystem zipfs = ZIPFS_PROVIDER.newFileSystem(Paths.get("basic.jar"), ZIPFS_MAP); 304 DirectoryStream<Path> ds = Files.newDirectoryStream(zipfs.getPath("/"), 305 new DirectoryStream.Filter<Path>() { 306 private PathMatcher matcher = 307 zipfs.getPathMatcher("glob:M*"); 308 public boolean accept(Path file) throws IOException { 309 throw new java.util.zip.ZipException(); 310 } 311 })) 312 { 313 314 for (Path entry: ds) { 315 throw new RuntimeException("Expected DirectoryIteratorException not thrown"); 316 } 317 } catch (DirectoryIteratorException x) { 318 IOException cause = x.getCause(); 319 if (!(cause instanceof java.util.zip.ZipException)) 320 throw new RuntimeException("Expected IOException not propagated"); 321 } catch (IOException e) { 322 e.printStackTrace(); 323 } 324 } 325 326 /** 327 * Glob values to use to validate filtering 328 */ 329 @DataProvider(name = "filterTestValues") 330 public static Object[][] filterValues() { 331 332 String expectedMsg = "Error: Matching entries were expected but not found!!!"; 333 String notExpectedMsg = "Error: No matching entries expected but were found!!!"; 334 return new Object[][]{ 335 336 {"M*", true, expectedMsg}, 337 {"I*", false, notExpectedMsg} 338 }; 339 } 340 341 /** 342 * Starting Path for the DirectoryStream and the expected path to be returned when traversing the stream 343 */ 344 @DataProvider(name = "startPaths") 345 public static Object[][] Name() { 346 return new Object[][]{ 347 348 {"META-INF", "META-INF/services"}, 349 {"/META-INF", "/META-INF/services"}, 350 {"./META-INF", "./META-INF/services"}, 351 {"", "META-INF"}, 352 {"/", "/META-INF"}, 353 {".", "./META-INF"}, 354 {"./", "./META-INF"} 355 }; 356 } 357 358 /** 359 * Returns the Zip FileSystem Provider 360 */ 361 private static FileSystemProvider getZipFSProvider() { 362 for (FileSystemProvider fsProvider : FileSystemProvider.installedProviders()) { 363 if ("jar".equals(fsProvider.getScheme())) { 364 return fsProvider; 365 } 366 } 367 return null; 368 } 369 370 }