1 /* 2 * Copyright (c) 2014, 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 /* 25 * @test 26 * @summary Basic test of jrt file system provider 27 * @run testng Basic 28 */ 29 30 import java.io.InputStream; 31 import java.io.DataInputStream; 32 import java.nio.file.DirectoryStream; 33 import java.nio.file.Files; 34 import java.nio.file.FileSystem; 35 import java.nio.file.FileSystems; 36 import java.nio.file.Path; 37 import java.nio.file.PathMatcher; 38 import java.nio.file.Paths; 39 import java.net.URI; 40 import java.util.Collections; 41 import java.util.Iterator; 42 import java.util.Map; 43 import java.util.NoSuchElementException; 44 import java.util.stream.Stream; 45 46 import org.testng.annotations.DataProvider; 47 import org.testng.annotations.Test; 48 49 import static org.testng.Assert.assertEquals; 50 import static org.testng.Assert.assertNotEquals; 51 import static org.testng.Assert.assertTrue; 52 import static org.testng.Assert.assertFalse; 53 54 /** 55 * Basic tests for jrt:/ file system provider. 56 */ 57 58 public class Basic { 59 60 // Checks that the given FileSystem is a jrt file system. 61 private void checkFileSystem(FileSystem fs) { 62 assertTrue(fs.provider().getScheme().equalsIgnoreCase("jrt")); 63 assertTrue(fs.isOpen()); 64 assertTrue(fs.isReadOnly()); 65 assertEquals(fs.getSeparator(), "/"); 66 67 // one root 68 Iterator<Path> roots = fs.getRootDirectories().iterator(); 69 assertTrue(roots.next().toString().equals("/")); 70 assertFalse(roots.hasNext()); 71 } 72 73 @Test 74 public void testGetFileSystem() { 75 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 76 checkFileSystem(fs); 77 78 // getFileSystem should return the same object each time 79 assertTrue(fs == FileSystems.getFileSystem(URI.create("jrt:/"))); 80 } 81 82 @Test(expectedExceptions = UnsupportedOperationException.class) 83 public void testCloseFileSystem() throws Exception { 84 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 85 fs.close(); // should throw UOE 86 } 87 88 @Test 89 public void testNewFileSystem() throws Exception { 90 FileSystem theFileSystem = FileSystems.getFileSystem(URI.create("jrt:/")); 91 Map<String, ?> env = Collections.emptyMap(); 92 try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), env)) { 93 checkFileSystem(fs); 94 assertTrue(fs != theFileSystem); 95 } 96 } 97 98 @DataProvider(name = "knownClassFiles") 99 private Object[][] knownClassFiles() { 100 return new Object[][] { 101 { "/java.base/java/lang/Object.class" }, 102 { "java.base/java/lang/Object.class" }, 103 }; 104 } 105 106 @Test(dataProvider = "knownClassFiles") 107 public void testKnownClassFiles(String path) throws Exception { 108 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 109 Path classFile = fs.getPath(path); 110 111 assertTrue(Files.isRegularFile(classFile)); 112 assertTrue(Files.size(classFile) > 0L); 113 114 // check magic number 115 try (InputStream in = Files.newInputStream(classFile)) { 116 int magic = new DataInputStream(in).readInt(); 117 assertEquals(magic, 0xCAFEBABE); 118 } 119 } 120 121 @DataProvider(name = "knownDirectories") 122 private Object[][] knownDirectories() { 123 return new Object[][] { 124 { "/" }, 125 { "." }, 126 { "./" }, 127 { "/." }, 128 { "/./" }, 129 { "/java.base/.." }, 130 { "/java.base/../" }, 131 { "/java.base/../." }, 132 { "/java.base" }, 133 { "/java.base/java/lang" }, 134 { "java.base/java/lang" }, 135 { "/java.base/java/lang/" }, 136 { "java.base/java/lang/" } 137 }; 138 } 139 140 @Test(dataProvider = "knownDirectories") 141 public void testKnownDirectories(String path) throws Exception { 142 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 143 Path dir = fs.getPath(path); 144 145 assertTrue(Files.isDirectory(dir)); 146 147 // directory should not be empty 148 try (Stream<Path> stream = Files.list(dir)) { 149 assertTrue(stream.count() > 0L); 150 } 151 try (Stream<Path> stream = Files.walk(dir)) { 152 assertTrue(stream.count() > 0L); 153 } 154 } 155 156 @DataProvider(name = "topLevelPkgDirs") 157 private Object[][] topLevelPkgDirs() { 158 return new Object[][] { 159 { "/java/lang" }, 160 { "java/lang" }, 161 { "/java/util" }, 162 { "java/util" }, 163 }; 164 } 165 166 @Test(dataProvider = "topLevelPkgDirs") 167 public void testNotExists(String path) throws Exception { 168 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 169 Path dir = fs.getPath(path); 170 171 // package directories should not be there at top level 172 assertTrue(Files.notExists(dir)); 173 } 174 175 /** 176 * Test the URI of every file in the jrt file system 177 */ 178 @Test 179 public void testToAndFromUri() throws Exception { 180 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 181 Path top = fs.getPath("/"); 182 try (Stream<Path> stream = Files.walk(top)) { 183 stream.forEach(path -> { 184 URI u = path.toUri(); 185 assertTrue(u.getScheme().equalsIgnoreCase("jrt")); 186 assertFalse(u.isOpaque()); 187 assertTrue(u.getAuthority() == null); 188 assertEquals(u.getPath(), path.toAbsolutePath().toString()); 189 Path p = Paths.get(u); 190 assertEquals(p, path); 191 }); 192 } 193 } 194 195 @Test 196 public void testDirectoryNames() throws Exception { 197 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 198 Path top = fs.getPath("/"); 199 // check that directory names do not have trailing '/' char 200 try (Stream<Path> stream = Files.walk(top)) { 201 stream.skip(1).filter(Files::isDirectory).forEach(path -> { 202 assertFalse(path.toString().endsWith("/")); 203 }); 204 } 205 } 206 207 @DataProvider(name = "pathPrefixs") 208 private Object[][] pathPrefixes() { 209 return new Object[][] { 210 { "/" }, 211 { "java.base/java/lang" }, 212 { "./java.base/java/lang" }, 213 { "/java.base/java/lang" }, 214 { "/./java.base/java/lang" }, 215 { "java.base/java/lang/" }, 216 { "./java.base/java/lang/" }, 217 { "/./java.base/java/lang/" }, 218 }; 219 } 220 221 @Test(dataProvider = "pathPrefixes") 222 public void testParentInDirList(String dir) throws Exception { 223 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 224 Path base = fs.getPath(dir); 225 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) { 226 for (Path entry: stream) { 227 assertTrue( entry.getParent().equals(base) ); 228 } 229 } 230 } 231 232 @DataProvider(name = "dirStreamStringFilterData") 233 private Object[][] dirStreamStringFilterData() { 234 return new Object[][] { 235 { "/java.base/java/lang", "/reflect" }, 236 { "/java.base/java/lang", "/Object.class" }, 237 { "/java.base/java/util", "/stream" }, 238 { "/java.base/java/util", "/List.class" }, 239 }; 240 } 241 242 @Test(dataProvider = "dirStreamStringFilterData") 243 public void testDirectoryStreamStringFilter(String dir, String filter) throws Exception { 244 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 245 Path base = fs.getPath(dir); 246 try (DirectoryStream<Path> stream = 247 Files.newDirectoryStream(base, p->!p.toString().endsWith(filter))) { 248 for (Path entry: stream) { 249 assertFalse(entry.toString().contains(filter), 250 "filtered path seen: " + filter); 251 } 252 } 253 254 // make sure without filter, we do see that matching entry! 255 boolean seen = false; 256 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) { 257 for (Path entry: stream) { 258 if (entry.toString().endsWith(filter)) { 259 seen = true; 260 break; 261 } 262 } 263 } 264 265 assertTrue(seen, "even without filter " + filter + " is missing"); 266 } 267 268 @DataProvider(name = "dirStreamFilterData") 269 private Object[][] dirStreamFilterData() { 270 return new Object[][] { 271 { 272 "/", 273 (DirectoryStream.Filter<Path>)(Files::isDirectory), 274 "isDirectory" 275 }, 276 { 277 "/java.base/java/lang", 278 (DirectoryStream.Filter<Path>)(Files::isRegularFile), 279 "isFile" 280 } 281 }; 282 } 283 284 @Test(dataProvider = "dirStreamFilterData") 285 private void testDirectoryStreamFilter(String dir, DirectoryStream.Filter filter, 286 String name) throws Exception { 287 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 288 Path base = fs.getPath(dir); 289 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base, filter)) { 290 for (Path entry: stream) { 291 assertTrue(filter.accept(entry), "filtered path seen: " + name); 292 } 293 } 294 295 // make sure without filter, we do see that matching entry! 296 boolean seen = false; 297 try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) { 298 for (Path entry: stream) { 299 if (filter.accept(entry)) { 300 seen = true; 301 break; 302 } 303 } 304 } 305 306 assertTrue(seen, "even without filter " + name + " is missing"); 307 } 308 309 @Test 310 private void testDirectoryStreamIterator() throws Exception { 311 // run the tests with null filter (no filter) 312 dirStreamIteratorTest(null); 313 // run the same tests with trivial "accept all" filter 314 dirStreamIteratorTest(p->true); 315 // two other non-trivial ones 316 dirStreamIteratorTest(Files::isDirectory); 317 dirStreamIteratorTest(Files::isRegularFile); 318 } 319 320 private void dirStreamIteratorTest(DirectoryStream.Filter<Path> filter) 321 throws Exception { 322 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 323 // This test assumes at least there are two elements in "java/lang" 324 // package with any filter passed. don't change to different path here! 325 Path dir = fs.getPath("/java.base/java/lang"); 326 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 327 Iterator<Path> itr = stream.iterator(); 328 itr.hasNext(); 329 Path path1 = itr.next(); 330 // missing second hasNext call 331 Path path2 = itr.next(); 332 assertNotEquals(path1, path2); 333 } 334 335 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 336 Iterator<Path> itr = stream.iterator(); 337 // no hasNext calls at all 338 Path path1 = itr.next(); 339 Path path2 = itr.next(); 340 assertNotEquals(path1, path2); 341 } 342 343 int numEntries = 0; 344 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 345 Iterator<Path> itr = stream.iterator(); 346 while (itr.hasNext()) { 347 numEntries++; 348 itr.next(); 349 } 350 351 // reached EOF, next call should result in exception 352 try { 353 itr.next(); 354 throw new AssertionError("should have thrown exception"); 355 } catch (NoSuchElementException nsee) { 356 System.out.println("got NoSuchElementException as expected"); 357 } 358 } 359 360 // redundant hasNext calls 361 try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) { 362 Iterator<Path> itr = stream.iterator(); 363 // any number of hasNext should definitely stay at first element 364 for (int i = 0; i < 2*numEntries; i++) { 365 itr.hasNext(); 366 } 367 368 for (int j = 0; j < numEntries; j++) { 369 itr.next(); 370 } 371 // exactly count number of entries! 372 assertFalse(itr.hasNext()); 373 } 374 } 375 376 @DataProvider(name = "hiddenPaths") 377 private Object[][] hiddenPaths() { 378 return new Object[][] { 379 { "/META-INF" }, 380 { "/META-INF/services" }, 381 { "/META-INF/services/java.nio.file.spi.FileSystemProvider" }, 382 { "/java.base/packages.offsets" }, 383 { "/java.instrument/packages.offsets" }, 384 { "/jdk.zipfs/packages.offsets" }, 385 { "/java/lang" }, 386 { "/java/util" }, 387 }; 388 } 389 390 @Test(dataProvider = "hiddenPaths") 391 public void testHiddenPathsNotExposed(String path) throws Exception { 392 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 393 assertTrue(Files.notExists(fs.getPath(path)), path + " should not exist"); 394 } 395 396 @DataProvider(name = "pathGlobPatterns") 397 private Object[][] pathGlobPatterns() { 398 return new Object[][] { 399 { "/*", "/java.base", true }, 400 { "/*", "/java.base/java", false }, 401 { "/j*", "/java.base", true }, 402 { "/J*", "/java.base", false }, 403 { "**.class", "/java.base/java/lang/Object.class", true }, 404 { "**.java", "/java.base/java/lang/Object.class", false }, 405 { "**java/*", "/java.base/java/lang", true }, 406 { "**java/lang/ref*", "/java.base/java/lang/reflect", true }, 407 { "**java/lang/ref*", "/java.base/java/lang/ref", true }, 408 { "**java/lang/ref?", "/java.base/java/lang/ref", false }, 409 { "**java/lang/{ref,refl*}", "/java.base/java/lang/ref", true }, 410 { "**java/lang/{ref,refl*}", "/java.base/java/lang/reflect", true }, 411 { "**java/[a-u]?*/*.class", "/java.base/java/util/Map.class", true }, 412 { "**java/util/[a-z]*.class", "/java.base/java/util/TreeMap.class", false }, 413 }; 414 } 415 416 @Test(dataProvider = "pathGlobPatterns") 417 public void testGlobPathMatcher(String pattern, String path, 418 boolean expectMatch) throws Exception { 419 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 420 PathMatcher pm = fs.getPathMatcher("glob:" + pattern); 421 Path p = fs.getPath(path); 422 assertTrue(Files.exists(p), path); 423 assertTrue(!(pm.matches(p) ^ expectMatch), 424 p + (expectMatch? " should match " : " should not match ") + 425 pattern); 426 } 427 428 @DataProvider(name = "pathRegexPatterns") 429 private Object[][] pathRegexPatterns() { 430 return new Object[][] { 431 { "/.*", "/java.base", true }, 432 { "/[^/]*", "/java.base/java", false }, 433 { "/j.*", "/java.base", true }, 434 { "/J.*", "/java.base", false }, 435 { ".*\\.class", "/java.base/java/lang/Object.class", true }, 436 { ".*\\.java", "/java.base/java/lang/Object.class", false }, 437 { ".*java/.*", "/java.base/java/lang", true }, 438 { ".*java/lang/ref.*", "/java.base/java/lang/reflect", true }, 439 { ".*java/lang/ref.*", "/java.base/java/lang/ref", true }, 440 { ".*/java/lang/ref.+", "/java.base/java/lang/ref", false }, 441 { ".*/java/lang/(ref|refl.*)", "/java.base/java/lang/ref", true }, 442 { ".*/java/lang/(ref|refl.*)", "/java.base/java/lang/reflect", true }, 443 { ".*/java/[a-u]?.*/.*\\.class", "/java.base/java/util/Map.class", true }, 444 { ".*/java/util/[a-z]*\\.class", "/java.base/java/util/TreeMap.class", false }, 445 }; 446 } 447 448 @Test(dataProvider = "pathRegexPatterns") 449 public void testRegexPathMatcher(String pattern, String path, 450 boolean expectMatch) throws Exception { 451 FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); 452 PathMatcher pm = fs.getPathMatcher("regex:" + pattern); 453 Path p = fs.getPath(path); 454 assertTrue(Files.exists(p), path); 455 assertTrue(!(pm.matches(p) ^ expectMatch), 456 p + (expectMatch? " should match " : " should not match ") + 457 pattern); 458 } 459 }