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.IOException;
  32 import java.io.DataInputStream;
  33 import java.nio.file.DirectoryStream;
  34 import java.nio.file.InvalidPathException;
  35 import java.nio.file.Files;
  36 import java.nio.file.FileSystem;
  37 import java.nio.file.FileSystems;
  38 import java.nio.file.Path;
  39 import java.nio.file.PathMatcher;
  40 import java.nio.file.Paths;
  41 import java.net.URI;
  42 import java.util.Collections;
  43 import java.util.Iterator;
  44 import java.util.Map;
  45 import java.util.NoSuchElementException;
  46 import java.util.stream.Stream;
  47 
  48 import org.testng.annotations.DataProvider;
  49 import org.testng.annotations.Test;
  50 
  51 import static org.testng.Assert.assertEquals;
  52 import static org.testng.Assert.assertNotEquals;
  53 import static org.testng.Assert.assertTrue;
  54 import static org.testng.Assert.assertFalse;
  55 
  56 /**
  57  * Basic tests for jrt:/ file system provider.
  58  */
  59 
  60 public class Basic {
  61 
  62     // Checks that the given FileSystem is a jrt file system.
  63     private void checkFileSystem(FileSystem fs) {
  64         assertTrue(fs.provider().getScheme().equalsIgnoreCase("jrt"));
  65         assertTrue(fs.isOpen());
  66         assertTrue(fs.isReadOnly());
  67         assertEquals(fs.getSeparator(), "/");
  68 
  69         // one root
  70         Iterator<Path> roots = fs.getRootDirectories().iterator();
  71         assertTrue(roots.next().toString().equals("/"));
  72         assertFalse(roots.hasNext());
  73     }
  74 
  75     @Test
  76     public void testGetFileSystem() {
  77         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
  78         checkFileSystem(fs);
  79 
  80         // getFileSystem should return the same object each time
  81         assertTrue(fs == FileSystems.getFileSystem(URI.create("jrt:/")));
  82     }
  83 
  84     @Test(expectedExceptions = UnsupportedOperationException.class)
  85     public void testCloseFileSystem() throws Exception {
  86         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
  87         fs.close(); // should throw UOE
  88     }
  89 
  90     @Test
  91     public void testNewFileSystem() throws Exception {
  92         FileSystem theFileSystem = FileSystems.getFileSystem(URI.create("jrt:/"));
  93         Map<String, ?> env = Collections.emptyMap();
  94         try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), env)) {
  95             checkFileSystem(fs);
  96             assertTrue(fs != theFileSystem);
  97         }
  98     }
  99 
 100     @DataProvider(name = "knownClassFiles")
 101     private Object[][] knownClassFiles() {
 102         return new Object[][] {
 103             { "/modules/java.base/java/lang/Object.class" },
 104             { "modules/java.base/java/lang/Object.class" },
 105         };
 106     }
 107 
 108     @Test(dataProvider = "knownClassFiles")
 109     public void testKnownClassFiles(String path) throws Exception {
 110         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 111         Path classFile = fs.getPath(path);
 112 
 113         assertTrue(Files.isRegularFile(classFile));
 114         assertTrue(Files.size(classFile) > 0L);
 115 
 116         // check magic number
 117         try (InputStream in = Files.newInputStream(classFile)) {
 118             int magic = new DataInputStream(in).readInt();
 119             assertEquals(magic, 0xCAFEBABE);
 120         }
 121     }
 122 
 123     @DataProvider(name = "knownDirectories")
 124     private Object[][] knownDirectories() {
 125         return new Object[][] {
 126             { "/"                     },
 127             { "."                     },
 128             { "./"                    },
 129             { "/."                    },
 130             { "/./"                   },
 131             { "/modules/java.base/.."         },
 132             { "/modules/java.base/../"        },
 133             { "/modules/java.base/../."       },
 134             { "/modules/java.base"            },
 135             { "/modules/java.base/java/lang"  },
 136             { "modules/java.base/java/lang"   },
 137             { "/modules/java.base/java/lang/" },
 138             { "modules/java.base/java/lang/"  }
 139         };
 140     }
 141 
 142     @Test(dataProvider = "knownDirectories")
 143     public void testKnownDirectories(String path) throws Exception {
 144         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 145         Path dir = fs.getPath(path);
 146 
 147         assertTrue(Files.isDirectory(dir));
 148 
 149         // directory should not be empty
 150         try (Stream<Path> stream = Files.list(dir)) {
 151             assertTrue(stream.count() > 0L);
 152         }
 153         try (Stream<Path> stream = Files.walk(dir)) {
 154             assertTrue(stream.count() > 0L);
 155         }
 156     }
 157 
 158     @DataProvider(name = "topLevelPkgDirs")
 159     private Object[][] topLevelPkgDirs() {
 160         return new Object[][] {
 161             { "/java/lang" },
 162             { "java/lang"  },
 163             { "/java/util" },
 164             { "java/util"  },
 165         };
 166     }
 167 
 168     @Test(dataProvider = "topLevelPkgDirs")
 169     public void testNotExists(String path) throws Exception {
 170         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 171         Path dir = fs.getPath(path);
 172 
 173         // package directories should not be there at top level
 174         assertTrue(Files.notExists(dir));
 175     }
 176 
 177     /**
 178      * Test the URI of every file in the jrt file system
 179      */
 180     @Test
 181     public void testToAndFromUri() throws Exception {
 182         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 183         Path top = fs.getPath("/");
 184         try (Stream<Path> stream = Files.walk(top)) {
 185             stream.forEach(path -> {
 186                 URI u = path.toUri();
 187                 assertTrue(u.getScheme().equalsIgnoreCase("jrt"));
 188                 assertFalse(u.isOpaque());
 189                 assertTrue(u.getAuthority() == null);
 190                 assertEquals(u.getPath(), path.toAbsolutePath().toString());
 191                 Path p = Paths.get(u);
 192                 assertEquals(p, path);
 193             });
 194         }
 195     }
 196 
 197     @Test
 198     public void testDirectoryNames() throws Exception {
 199         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 200         Path top = fs.getPath("/");
 201         // check that directory names do not have trailing '/' char
 202         try (Stream<Path> stream = Files.walk(top)) {
 203             stream.skip(1).filter(Files::isDirectory).forEach(path -> {
 204                 assertFalse(path.toString().endsWith("/"));
 205             });
 206         }
 207     }
 208 
 209     @DataProvider(name = "pathPrefixs")
 210     private Object[][] pathPrefixes() {
 211         return new Object[][] {
 212             { "/"                       },
 213             { "modules/java.base/java/lang"     },
 214             { "./modules/java.base/java/lang"   },
 215             { "/modules/java.base/java/lang"    },
 216             { "/./modules/java.base/java/lang"  },
 217             { "modules/java.base/java/lang/"    },
 218             { "./modules/java.base/java/lang/"  },
 219             { "/./modules/java.base/java/lang/" },
 220         };
 221     }
 222 
 223     // @Test(dataProvider = "pathPrefixes")
 224     public void testParentInDirList(String dir) throws Exception {
 225         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 226         Path base = fs.getPath(dir);
 227         try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) {
 228             for (Path entry: stream) {
 229                 assertTrue( entry.getParent().equals(base),
 230                     base.toString() + "-> " + entry.toString() );
 231             }
 232         }
 233     }
 234 
 235     @DataProvider(name = "dirStreamStringFilterData")
 236     private Object[][] dirStreamStringFilterData() {
 237         return new Object[][] {
 238             { "/modules/java.base/java/lang", "/reflect"      },
 239             { "/modules/java.base/java/lang", "/Object.class" },
 240             { "/modules/java.base/java/util", "/stream"       },
 241             { "/modules/java.base/java/util", "/List.class"   },
 242         };
 243     }
 244 
 245     @Test(dataProvider = "dirStreamStringFilterData")
 246     public void testDirectoryStreamStringFilter(String dir, String filter) throws Exception {
 247         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 248         Path base = fs.getPath(dir);
 249         try (DirectoryStream<Path> stream =
 250                 Files.newDirectoryStream(base, p->!p.toString().endsWith(filter))) {
 251             for (Path entry: stream) {
 252                 assertFalse(entry.toString().contains(filter),
 253                     "filtered path seen: " + filter);
 254             }
 255         }
 256 
 257         // make sure without filter, we do see that matching entry!
 258         boolean seen = false;
 259         try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) {
 260             for (Path entry: stream) {
 261                 if (entry.toString().endsWith(filter)) {
 262                     seen = true;
 263                     break;
 264                 }
 265             }
 266         }
 267 
 268         assertTrue(seen, "even without filter " + filter + " is missing");
 269     }
 270 
 271     @DataProvider(name = "dirStreamFilterData")
 272     private Object[][] dirStreamFilterData() {
 273         return new Object[][] {
 274             {
 275               "/",
 276               (DirectoryStream.Filter<Path>)(Files::isDirectory),
 277               "isDirectory"
 278             },
 279             {
 280               "/modules/java.base/java/lang",
 281               (DirectoryStream.Filter<Path>)(Files::isRegularFile),
 282               "isFile"
 283             }
 284         };
 285     }
 286 
 287     @Test(dataProvider = "dirStreamFilterData")
 288     private void testDirectoryStreamFilter(String dir, DirectoryStream.Filter filter,
 289             String name) throws Exception {
 290         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 291         Path base = fs.getPath(dir);
 292         try (DirectoryStream<Path> stream = Files.newDirectoryStream(base, filter)) {
 293             for (Path entry: stream) {
 294                 assertTrue(filter.accept(entry), "filtered path seen: " + name);
 295             }
 296         }
 297 
 298         // make sure without filter, we do see that matching entry!
 299         boolean seen = false;
 300         try (DirectoryStream<Path> stream = Files.newDirectoryStream(base)) {
 301             for (Path entry: stream) {
 302                 if (filter.accept(entry)) {
 303                     seen = true;
 304                     break;
 305                 }
 306             }
 307         }
 308 
 309         assertTrue(seen, "even without filter " + name + " is missing");
 310     }
 311 
 312     @Test
 313     private void testDirectoryStreamIterator() throws Exception {
 314         // run the tests with null filter (no filter)
 315         dirStreamIteratorTest(null);
 316         // run the same tests with trivial "accept all" filter
 317         dirStreamIteratorTest(p->true);
 318         // two other non-trivial ones
 319         dirStreamIteratorTest(Files::isDirectory);
 320         dirStreamIteratorTest(Files::isRegularFile);
 321     }
 322 
 323     private void dirStreamIteratorTest(DirectoryStream.Filter<Path> filter)
 324             throws Exception {
 325         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 326         // This test assumes at least there are two elements in "java/lang"
 327         // package with any filter passed. don't change to different path here!
 328         Path dir = fs.getPath("/modules/java.base/java/lang");
 329         try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
 330             Iterator<Path> itr = stream.iterator();
 331             itr.hasNext();
 332             Path path1 = itr.next();
 333             // missing second hasNext call
 334             Path path2 = itr.next();
 335             assertNotEquals(path1, path2);
 336         }
 337 
 338         try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
 339             Iterator<Path> itr = stream.iterator();
 340             // no hasNext calls at all
 341             Path path1 = itr.next();
 342             Path path2 = itr.next();
 343             assertNotEquals(path1, path2);
 344         }
 345 
 346         int numEntries = 0;
 347         try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
 348             Iterator<Path> itr = stream.iterator();
 349             while (itr.hasNext()) {
 350                 numEntries++;
 351                 itr.next();
 352             }
 353 
 354             // reached EOF, next call should result in exception
 355             try {
 356                 itr.next();
 357                 throw new AssertionError("should have thrown exception");
 358             } catch (NoSuchElementException nsee) {
 359                 System.out.println("got NoSuchElementException as expected");
 360             }
 361         }
 362 
 363         // redundant hasNext calls
 364         try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, filter)) {
 365             Iterator<Path> itr = stream.iterator();
 366             // any number of hasNext should definitely stay at first element
 367             for (int i = 0; i < 2*numEntries; i++) {
 368                 itr.hasNext();
 369             }
 370 
 371             for (int j = 0; j < numEntries; j++) {
 372                 itr.next();
 373             }
 374             // exactly count number of entries!
 375             assertFalse(itr.hasNext());
 376         }
 377     }
 378 
 379     @DataProvider(name = "hiddenPaths")
 380     private Object[][] hiddenPaths() {
 381         return new Object[][] {
 382             { "/META-INF" },
 383             { "/META-INF/services" },
 384             { "/META-INF/services/java.nio.file.spi.FileSystemProvider" },
 385             { "/modules/java.base/packages.offsets" },
 386             { "/modules/java.instrument/packages.offsets" },
 387             { "/modules/jdk.zipfs/packages.offsets" },
 388             { "/modules/java.base/_the.java.base.vardeps" },
 389             { "/modules/java.base/_the.java.base_batch" },
 390             { "/java/lang" },
 391             { "/java/util" },
 392         };
 393     }
 394 
 395     @Test(dataProvider = "hiddenPaths")
 396     public void testHiddenPathsNotExposed(String path) throws Exception {
 397         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 398         assertTrue(Files.notExists(fs.getPath(path)), path + " should not exist");
 399     }
 400 
 401     @DataProvider(name = "pathGlobPatterns")
 402     private Object[][] pathGlobPatterns() {
 403         return new Object[][] {
 404             { "/modules/*", "/modules/java.base", true },
 405             { "/modules/*", "/modules/java.base/java", false },
 406             { "/modules/j*", "/modules/java.base", true },
 407             { "/modules/J*", "/modules/java.base", false },
 408             { "**.class", "/modules/java.base/java/lang/Object.class", true },
 409             { "**.java", "/modules/java.base/java/lang/Object.class", false },
 410             { "**java/*", "/modules/java.base/java/lang", true },
 411             { "**java/lang/ref*", "/modules/java.base/java/lang/reflect", true },
 412             { "**java/lang/ref*", "/modules/java.base/java/lang/ref", true },
 413             { "**java/lang/ref?", "/modules/java.base/java/lang/ref", false },
 414             { "**java/lang/{ref,refl*}", "/modules/java.base/java/lang/ref", true },
 415             { "**java/lang/{ref,refl*}", "/modules/java.base/java/lang/reflect", true },
 416             { "**java/[a-u]?*/*.class", "/modules/java.base/java/util/Map.class", true },
 417             { "**java/util/[a-z]*.class", "/modules/java.base/java/util/TreeMap.class", false },
 418         };
 419     }
 420 
 421     @Test(dataProvider = "pathGlobPatterns")
 422     public void testGlobPathMatcher(String pattern, String path,
 423             boolean expectMatch) throws Exception {
 424         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 425         PathMatcher pm = fs.getPathMatcher("glob:" + pattern);
 426         Path p = fs.getPath(path);
 427         assertTrue(Files.exists(p), path);
 428         assertTrue(!(pm.matches(p) ^ expectMatch),
 429             p + (expectMatch? " should match " : " should not match ") +
 430             pattern);
 431     }
 432 
 433     @DataProvider(name = "pathRegexPatterns")
 434     private Object[][] pathRegexPatterns() {
 435         return new Object[][] {
 436             { "/modules/.*", "/modules/java.base", true },
 437             { "/modules/[^/]*", "/modules/java.base/java", false },
 438             { "/modules/j.*", "/modules/java.base", true },
 439             { "/modules/J.*", "/modules/java.base", false },
 440             { ".*\\.class", "/modules/java.base/java/lang/Object.class", true },
 441             { ".*\\.java", "/modules/java.base/java/lang/Object.class", false },
 442             { ".*java/.*", "/modules/java.base/java/lang", true },
 443             { ".*java/lang/ref.*", "/modules/java.base/java/lang/reflect", true },
 444             { ".*java/lang/ref.*", "/modules/java.base/java/lang/ref", true },
 445             { ".*/java/lang/ref.+", "/modules/java.base/java/lang/ref", false },
 446             { ".*/java/lang/(ref|refl.*)", "/modules/java.base/java/lang/ref", true },
 447             { ".*/java/lang/(ref|refl.*)", "/modules/java.base/java/lang/reflect", true },
 448             { ".*/java/[a-u]?.*/.*\\.class", "/modules/java.base/java/util/Map.class", true },
 449             { ".*/java/util/[a-z]*\\.class", "/modules/java.base/java/util/TreeMap.class", false },
 450         };
 451     }
 452 
 453     @Test(dataProvider = "pathRegexPatterns")
 454     public void testRegexPathMatcher(String pattern, String path,
 455             boolean expectMatch) throws Exception {
 456         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 457         PathMatcher pm = fs.getPathMatcher("regex:" + pattern);
 458         Path p = fs.getPath(path);
 459         assertTrue(Files.exists(p), path);
 460         assertTrue(!(pm.matches(p) ^ expectMatch),
 461             p + (expectMatch? " should match " : " should not match ") +
 462             pattern);
 463     }
 464 
 465     @Test
 466     public void testPackagesAndModules() throws Exception {
 467         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 468         assertTrue(Files.isDirectory(fs.getPath("/packages")));
 469         assertTrue(Files.isDirectory(fs.getPath("/modules")));
 470     }
 471 
 472     @DataProvider(name = "packagesSubDirs")
 473     private Object[][] packagesSubDirs() {
 474         return new Object[][] {
 475             { "java.lang" },
 476             { "java.util" },
 477             { "java.nio"  },
 478             { "jdk.nashorn.api.scripting" }
 479         };
 480     }
 481 
 482     @Test(dataProvider = "packagesSubDirs")
 483     public void testPackagesSubDirs(String pkg) throws Exception {
 484         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 485         assertTrue(Files.isDirectory(fs.getPath("/packages/" + pkg)),
 486             pkg + " missing");
 487     }
 488 
 489     @DataProvider(name = "packagesLinks")
 490     private Object[][] packagesLinks() {
 491         return new Object[][] {
 492             { "/packages/java.lang/java.base" },
 493             { "/packages/java.lang/java.instrument" },
 494             { "/packages/java/java.base" },
 495             { "/packages/java/java.instrument" },
 496             { "/packages/java/java.rmi"  },
 497             { "/packages/java/java.sql"  },
 498             { "/packages/javax/java.base"  },
 499             { "/packages/javax/java.sql"  },
 500             { "/packages/javax/java.xml"  },
 501             { "/packages/javax/java.management"  },
 502             { "/packages/java.util/java.base" },
 503             { "/packages/jdk.nashorn.api.scripting/jdk.scripting.nashorn" },
 504         };
 505     }
 506 
 507     @Test(dataProvider = "packagesLinks")
 508     public void testPackagesLinks(String link) throws Exception {
 509         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 510         Path path = fs.getPath(link);
 511         assertTrue(Files.exists(path), link + " missing");
 512         assertTrue(Files.isSymbolicLink(path), path + " is not a link");
 513         path = Files.readSymbolicLink(path);
 514         assertEquals(path.toString(), "/modules" + link.substring(link.lastIndexOf("/")));
 515     }
 516 
 517     @DataProvider(name = "modulesSubDirs")
 518     private Object[][] modulesSubDirs() {
 519         return new Object[][] {
 520             { "java.base" },
 521             { "java.sql" },
 522             { "jdk.scripting.nashorn" },
 523         };
 524     }
 525 
 526     @Test(dataProvider = "modulesSubDirs")
 527     public void testModulesSubDirs(String module) throws Exception {
 528         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 529         Path path = fs.getPath("/modules/" + module);
 530         assertTrue(Files.isDirectory(path), module + " missing");
 531         assertTrue(!Files.isSymbolicLink(path), path + " is a link");
 532     }
 533 
 534     @DataProvider(name="linkChases")
 535     private Object[][] linkChases() {
 536         return new Object[][] {
 537             { "/modules/java.base/java/lang" },
 538             { "/modules/java.base/java/util/Vector.class" },
 539             { "/modules/jdk.scripting.nashorn/jdk/nashorn" },
 540             { "/packages/java.lang/java.base/java/lang" },
 541             { "/packages/java.util/java.base/java/util/Vector.class" },
 542         };
 543     }
 544 
 545     @Test(dataProvider = "linkChases")
 546     public void testLinkChases(String link) throws Exception {
 547         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 548         Path path = fs.getPath(link);
 549         assertTrue(Files.exists(path), link);
 550     }
 551 
 552     @Test
 553     public void testSymlinkDirList() throws Exception {
 554         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 555         Path path = fs.getPath("/packages/java.lang/java.base");
 556         assertTrue(Files.isSymbolicLink(path));
 557         assertTrue(Files.isDirectory(path));
 558 
 559         boolean javaSeen = false, javaxSeen = false;
 560         try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
 561             for (Path p : stream) {
 562                 String str = p.toString();
 563                 if (str.endsWith("/java")) {
 564                     javaSeen = true;
 565                 } else if (str.endsWith("javax")) {
 566                     javaxSeen = true;
 567                 }
 568             }
 569         }
 570         assertTrue(javaSeen);
 571         assertTrue(javaxSeen);
 572     }
 573 
 574     @Test
 575     public void invalidPathTest() {
 576         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 577         InvalidPathException ipe = null;
 578         try {
 579             boolean res = Files.exists(fs.getPath("/packages/\ud834\udd7b"));
 580             assertFalse(res);
 581             return;
 582         } catch (InvalidPathException e) {
 583             ipe = e;
 584         }
 585         assertTrue(ipe != null);
 586     }
 587 
 588     @DataProvider(name="packagesLinkedDirs")
 589     private Object[][] packagesLinkedDirs() {
 590         return new Object[][] {
 591             { "/packages/java.lang/java.base/java/lang/ref"             },
 592             { "/./packages/java.lang/java.base/java/lang/ref"           },
 593             { "packages/java.lang/java.base/java/lang/ref"              },
 594             { "/packages/../packages/java.lang/java.base/java/lang/ref" },
 595             { "/packages/java.lang/java.base/java/util/zip"             },
 596             { "/./packages/java.lang/java.base/java/util/zip"           },
 597             { "packages/java.lang/java.base/java/util/zip"              },
 598             { "/packages/../packages/java.lang/java.base/java/util/zip" },
 599             { "/packages/com.oracle/java.xml.ws/com"                    },
 600             { "/./packages/com.oracle/java.xml.ws/com"                  },
 601             { "packages/com.oracle/java.xml.ws/com"                     },
 602             { "/packages/../packages/com.oracle/java.xml.ws/com"        }
 603         };
 604     }
 605 
 606     // @bug 8141521: jrt file system's DirectoryStream reports child paths
 607     // with wrong paths for directories under /packages
 608     @Test(dataProvider = "packagesLinkedDirs")
 609     public void dirStreamPackagesDirTest(String dirName) throws IOException {
 610         FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
 611         Path path = fs.getPath(dirName);
 612 
 613         int childCount = 0, dirPrefixOkayCount = 0;
 614         try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(path)) {
 615             for (Path child : dirStream) {
 616                 childCount++;
 617                 if (child.toString().startsWith(dirName)) {
 618                     dirPrefixOkayCount++;
 619                 }
 620             }
 621         }
 622 
 623         assertTrue(childCount != 0);
 624         assertEquals(dirPrefixOkayCount, childCount);
 625     }
 626 }