test/java/nio/file/Files/StreamTest.java

Print this page
rev 7633 : 8017513: Support for closeable streams
Reviewed-by:
Contributed-by: brian.goetz@oracle.com


  33 import java.io.UncheckedIOException;
  34 import java.nio.charset.Charset;
  35 import java.nio.charset.MalformedInputException;
  36 import java.nio.file.DirectoryIteratorException;
  37 import java.nio.file.DirectoryStream;
  38 import java.nio.file.FileSystemLoopException;
  39 import java.nio.file.FileVisitOption;
  40 import java.nio.file.Files;
  41 import java.nio.file.NoSuchFileException;
  42 import java.nio.file.Path;
  43 import java.nio.file.Paths;
  44 import java.nio.file.attribute.BasicFileAttributes;
  45 import java.util.Arrays;
  46 import java.util.Comparator;
  47 import java.util.Iterator;
  48 import java.util.List;
  49 import java.util.Objects;
  50 import java.util.Set;
  51 import java.util.TreeSet;
  52 import java.util.function.BiPredicate;
  53 import java.util.stream.CloseableStream;
  54 import java.util.stream.Collectors;
  55 import org.testng.annotations.AfterClass;
  56 import org.testng.annotations.BeforeClass;
  57 import org.testng.annotations.Test;
  58 import static org.testng.Assert.*;
  59 
  60 @Test(groups = "unit")
  61 public class StreamTest {
  62     /**
  63      * Default test folder
  64      * testFolder - empty
  65      *            - file
  66      *            - dir - d1
  67      *                  - f1
  68      *                  - lnDir2 (../dir2)
  69      *            - dir2
  70      *            - linkDir (./dir)
  71      *            - linkFile(./file)
  72      */
  73     static Path testFolder;


 121         set.add(testFolder);
 122         all = set.toArray(new Path[0]);
 123 
 124         // Follow links
 125         if (supportsLinks) {
 126             tmp = testFolder.resolve("linkDir");
 127             set.add(tmp.resolve("d1"));
 128             set.add(tmp.resolve("f1"));
 129             tmp = tmp.resolve("lnDir2");
 130             set.add(tmp);
 131         }
 132         all_folowLinks = set.toArray(new Path[0]);
 133     }
 134 
 135     @AfterClass
 136     void cleanupTestFolder() throws IOException {
 137         TestUtil.removeAll(testFolder);
 138     }
 139 
 140     public void testBasic() {
 141         try (CloseableStream<Path> s = Files.list(testFolder)) {
 142             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 143             assertEquals(actual, level1);
 144         } catch (IOException ioe) {
 145             fail("Unexpected IOException");
 146         }
 147 
 148         try (CloseableStream<Path> s = Files.list(testFolder.resolve("empty"))) {
 149             int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
 150             assertEquals(count, 0, "Expect empty stream.");
 151         } catch (IOException ioe) {
 152             fail("Unexpected IOException");
 153         }
 154     }
 155 
 156     public void testWalk() {
 157         try (CloseableStream<Path> s = Files.walk(testFolder)) {
 158             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 159             assertEquals(actual, all);
 160         } catch (IOException ioe) {
 161             fail("Unexpected IOException");
 162         }
 163     }
 164 
 165     public void testWalkOneLevel() {
 166         try (CloseableStream<Path> s = Files.walk(testFolder, 1)) {
 167             Object[] actual = s.filter(path -> ! path.equals(testFolder))
 168                                .sorted(Comparator.naturalOrder())
 169                                .toArray();
 170             assertEquals(actual, level1);
 171         } catch (IOException ioe) {
 172             fail("Unexpected IOException");
 173         }
 174     }
 175 
 176     public void testWalkFollowLink() {
 177         // If link is not supported, the directory structure won't have link.
 178         // We still want to test the behavior with FOLLOW_LINKS option.
 179         try (CloseableStream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
 180             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 181             assertEquals(actual, all_folowLinks);
 182         } catch (IOException ioe) {
 183             fail("Unexpected IOException");
 184         }
 185     }
 186 
 187     private void validateFileSystemLoopException(Path start, Path... causes) {
 188         try (CloseableStream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
 189             try {
 190                 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
 191                 fail("Should got FileSystemLoopException, but got " + count + "elements.");
 192             } catch (UncheckedIOException uioe) {
 193                 IOException ioe = uioe.getCause();
 194                 if (ioe instanceof FileSystemLoopException) {
 195                     FileSystemLoopException fsle = (FileSystemLoopException) ioe;
 196                     boolean match = false;
 197                     for (Path cause: causes) {
 198                         if (fsle.getFile().equals(cause.toString())) {
 199                             match = true;
 200                             break;
 201                         }
 202                     }
 203                     assertTrue(match);
 204                 } else {
 205                     fail("Unexpected UncheckedIOException cause " + ioe.toString());
 206                 }
 207             }
 208         } catch(IOException ex) {


 265         private final BiPredicate<Path, BasicFileAttributes> pred;
 266         private final Set<Path> visited = new TreeSet<Path>();
 267 
 268         PathBiPredicate(BiPredicate<Path, BasicFileAttributes> pred) {
 269             this.pred = Objects.requireNonNull(pred);
 270         }
 271 
 272         public boolean test(Path path, BasicFileAttributes attrs) {
 273             visited.add(path);
 274             return pred.test(path, attrs);
 275         }
 276 
 277         public Path[] visited() {
 278             return visited.toArray(new Path[0]);
 279         }
 280     }
 281 
 282     public void testFind() throws IOException {
 283         PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
 284 
 285         try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 286             Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
 287             assertEquals(pred.visited(), all);
 288             assertEquals(result.toArray(new Path[0]), pred.visited());
 289         }
 290 
 291         pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
 292         try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 293             s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
 294             assertEquals(pred.visited(), all);
 295         }
 296 
 297         pred = new PathBiPredicate((path, attrs) ->
 298             path.getFileName().toString().startsWith("e"));
 299         try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 300             s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
 301             assertEquals(pred.visited(), all);
 302         }
 303 
 304         pred = new PathBiPredicate((path, attrs) ->
 305             path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
 306         try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 307             s.forEach(path -> fail("Expect empty stream"));
 308             assertEquals(pred.visited(), all);
 309         }
 310     }
 311 
 312     // Test borrowed from BytesAndLines
 313     public void testLines() throws IOException {
 314         final Charset US_ASCII = Charset.forName("US-ASCII");
 315         Path tmpfile = Files.createTempFile("blah", "txt");
 316 
 317         try {
 318             // zero lines
 319             assertTrue(Files.size(tmpfile) == 0, "File should be empty");
 320             try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
 321                 assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
 322             }
 323 
 324             // one line
 325             byte[] hi = { (byte)'h', (byte)'i' };
 326             Files.write(tmpfile, hi);
 327             try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
 328                 List<String> lines = s.collect(Collectors.toList());
 329                 assertTrue(lines.size() == 1, "One line expected");
 330                 assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
 331             }
 332 
 333             // two lines using platform's line separator
 334             List<String> expected = Arrays.asList("hi", "there");
 335             Files.write(tmpfile, expected, US_ASCII);
 336             assertTrue(Files.size(tmpfile) > 0, "File is empty");
 337             try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
 338                 List<String> lines = s.collect(Collectors.toList());
 339                 assertTrue(lines.equals(expected), "Unexpected lines");
 340             }
 341 
 342             // MalformedInputException
 343             byte[] bad = { (byte)0xff, (byte)0xff };
 344             Files.write(tmpfile, bad);
 345             try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
 346                 try {
 347                     List<String> lines = s.collect(Collectors.toList());
 348                     throw new RuntimeException("UncheckedIOException expected");
 349                 } catch (UncheckedIOException ex) {
 350                     assertTrue(ex.getCause() instanceof MalformedInputException,
 351                                "MalformedInputException expected");
 352                 }
 353             }
 354 
 355             // NullPointerException
 356             try {
 357                 Files.lines(null, US_ASCII);
 358                 throw new RuntimeException("NullPointerException expected");
 359             } catch (NullPointerException ignore) { }
 360             try {
 361                 Files.lines(tmpfile, null);
 362                 throw new RuntimeException("NullPointerException expected");
 363             } catch (NullPointerException ignore) { }
 364 
 365         } finally {
 366             Files.delete(tmpfile);
 367         }
 368     }
 369 
 370     public void testDirectoryIteratorException() throws IOException {
 371         Path dir = testFolder.resolve("dir2");
 372         Path trigger = dir.resolve("DirectoryIteratorException");
 373         Files.createFile(trigger);
 374         FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
 375         FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);
 376 
 377         try {
 378             fsp.setFaultyMode(false);
 379             Path fakeRoot = fs.getRoot();
 380             try {
 381                 try (CloseableStream<Path> s = Files.list(fakeRoot)) {
 382                     s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
 383                 }
 384             } catch (UncheckedIOException uioe) {
 385                 fail("Unexpected exception.");
 386             }
 387 
 388             fsp.setFaultyMode(true);
 389             try {
 390                 try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {
 391                     Iterator<Path> itor = ds.iterator();
 392                     while (itor.hasNext()) {
 393                         itor.next();
 394                     }
 395                 }
 396                 fail("Shoule throw DirectoryIteratorException");
 397             } catch (DirectoryIteratorException die) {
 398             }
 399 
 400             try {
 401                 try (CloseableStream<Path> s = Files.list(fakeRoot)) {
 402                     s.forEach(path -> fail("should not get here"));
 403                 }
 404             } catch (UncheckedIOException uioe) {
 405                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
 406             } catch (DirectoryIteratorException die) {
 407                 fail("Should have been converted into UncheckedIOException.");
 408             }
 409         } finally {
 410             // Cleanup
 411             if (fs != null) {
 412                 fs.close();
 413             }
 414             Files.delete(trigger);
 415         }
 416     }
 417 
 418     public void testUncheckedIOException() throws IOException {
 419         Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));
 420         Files.createFile(triggerFile);
 421         Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));
 422         Files.createDirectories(triggerDir);
 423         Files.createFile(triggerDir.resolve("file"));
 424         FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
 425         FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
 426 
 427         try {
 428             fsp.setFaultyMode(false);
 429             Path fakeRoot = fs.getRoot();
 430             try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
 431                 // only one file
 432                 s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
 433             }
 434 
 435             try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
 436                 String[] result = s.map(path -> path.getFileName().toString())
 437                                    .toArray(String[]::new);
 438                 // ordered as depth-first
 439                 assertEquals(result, new String[] { "empty", "IOException", "file"});
 440             }
 441 
 442             fsp.setFaultyMode(true);
 443             try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
 444                 s.forEach(path -> fail("should have caused exception"));
 445             } catch (UncheckedIOException uioe) {
 446                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
 447             }
 448 
 449             try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
 450                 String[] result = s.map(path -> path.getFileName().toString())
 451                                    .toArray(String[]::new);
 452                 fail("should not reach here due to IOException");
 453             } catch (UncheckedIOException uioe) {
 454                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
 455             }
 456 
 457             try (CloseableStream<Path> s = Files.walk(
 458                 fakeRoot.resolve("empty").resolve("IOException")))
 459             {
 460                 String[] result = s.map(path -> path.getFileName().toString())
 461                                    .toArray(String[]::new);
 462                 fail("should not reach here due to IOException");
 463             } catch (IOException ioe) {
 464                 assertTrue(ioe instanceof FaultyFileSystem.FaultyException);
 465             } catch (UncheckedIOException ex) {
 466                 fail("Top level should be repored as is");
 467             }
 468          } finally {
 469             // Cleanup
 470             if (fs != null) {
 471                 fs.close();
 472             }
 473             Files.delete(triggerFile);
 474             TestUtil.removeAll(triggerDir);
 475         }
 476     }
 477 


 485         Files.createFile(triggerDir.resolve("fileInSE"));
 486         Path sample = Files.createFile(dir2.resolve("file"));
 487 
 488         Path triggerLink = null;
 489         Path linkTriggerDir = null;
 490         Path linkTriggerFile = null;
 491         if (supportsLinks) {
 492             Path dir = testFolder.resolve("dir");
 493             triggerLink = Files.createSymbolicLink(dir.resolve("SecurityException"), empty);
 494             linkTriggerDir = Files.createSymbolicLink(dir.resolve("lnDirSE"), triggerDir);
 495             linkTriggerFile = Files.createSymbolicLink(dir.resolve("lnFileSE"), triggerFile);
 496         }
 497 
 498         FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
 499         FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
 500 
 501         try {
 502             fsp.setFaultyMode(false);
 503             Path fakeRoot = fs.getRoot();
 504             // validate setting
 505             try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
 506                 String[] result = s.map(path -> path.getFileName().toString())
 507                                    .toArray(String[]::new);
 508                 assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
 509             }
 510 
 511             try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
 512                 String[] result = s.map(path -> path.getFileName().toString())
 513                                    .toArray(String[]::new);
 514                 assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
 515             }
 516 
 517             if (supportsLinks) {
 518                 try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
 519                     String[] result = s.map(path -> path.getFileName().toString())
 520                                        .toArray(String[]::new);
 521                     assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
 522                 }
 523             }
 524 
 525             // execute test
 526             fsp.setFaultyMode(true);
 527             // ignore file cause SecurityException
 528             try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
 529                 String[] result = s.map(path -> path.getFileName().toString())
 530                                    .toArray(String[]::new);
 531                 assertEqualsNoOrder(result, new String[] { "empty", "sample" });
 532             }
 533             // skip folder cause SecurityException
 534             try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
 535                 String[] result = s.map(path -> path.getFileName().toString())
 536                                    .toArray(String[]::new);
 537                 assertEqualsNoOrder(result, new String[] { "dir2", "file" });
 538             }
 539 
 540             if (supportsLinks) {
 541                 // not following links
 542                 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
 543                     String[] result = s.map(path -> path.getFileName().toString())
 544                                        .toArray(String[]::new);
 545                     assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
 546                 }
 547 
 548                 // following links
 549                 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
 550                     String[] result = s.map(path -> path.getFileName().toString())
 551                                        .toArray(String[]::new);
 552                     // ?? Should fileInSE show up?
 553                     // With FaultyFS, it does as no exception thrown for link to "SecurityException" with read on "lnXxxSE"
 554                     assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "file", "lnDirSE", "lnFileSE", "fileInSE" });
 555                 }
 556             }
 557 
 558             // list instead of walk
 559             try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
 560                 String[] result = s.map(path -> path.getFileName().toString())
 561                                    .toArray(String[]::new);
 562                 assertEqualsNoOrder(result, new String[] { "sample" });
 563             }
 564             try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
 565                 String[] result = s.map(path -> path.getFileName().toString())
 566                                    .toArray(String[]::new);
 567                 assertEqualsNoOrder(result, new String[] { "file" });
 568             }
 569 
 570             // root cause SecurityException should be reported
 571             try (CloseableStream<Path> s = Files.walk(
 572                 fakeRoot.resolve("dir2").resolve("SecurityException")))
 573             {
 574                 String[] result = s.map(path -> path.getFileName().toString())
 575                                    .toArray(String[]::new);
 576                 fail("should not reach here due to SecurityException");
 577             } catch (SecurityException se) {
 578                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 579             }
 580 
 581             // Walk a file cause SecurityException, we should get SE
 582             try (CloseableStream<Path> s = Files.walk(
 583                 fakeRoot.resolve("dir").resolve("SecurityException")))
 584             {
 585                 String[] result = s.map(path -> path.getFileName().toString())
 586                                    .toArray(String[]::new);
 587                 fail("should not reach here due to SecurityException");
 588             } catch (SecurityException se) {
 589                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 590             }
 591 
 592             // List a file cause SecurityException, we should get SE as cannot read attribute
 593             try (CloseableStream<Path> s = Files.list(
 594                 fakeRoot.resolve("dir2").resolve("SecurityException")))
 595             {
 596                 String[] result = s.map(path -> path.getFileName().toString())
 597                                    .toArray(String[]::new);
 598                 fail("should not reach here due to SecurityException");
 599             } catch (SecurityException se) {
 600                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 601             }
 602 
 603             try (CloseableStream<Path> s = Files.list(
 604                 fakeRoot.resolve("dir").resolve("SecurityException")))
 605             {
 606                 String[] result = s.map(path -> path.getFileName().toString())
 607                                    .toArray(String[]::new);
 608                 fail("should not reach here due to SecurityException");
 609             } catch (SecurityException se) {
 610                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 611             }
 612          } finally {
 613             // Cleanup
 614             if (fs != null) {
 615                 fs.close();
 616             }
 617             if (supportsLinks) {
 618                 Files.delete(triggerLink);
 619                 Files.delete(linkTriggerDir);
 620                 Files.delete(linkTriggerFile);
 621             }
 622             Files.delete(triggerFile);
 623             Files.delete(sampleFile);
 624             Files.delete(sample);
 625             TestUtil.removeAll(triggerDir);
 626         }
 627     }
 628 
 629     public void testConstructException() {
 630         try (CloseableStream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
 631             s.forEach(l -> fail("File is not even exist!"));
 632         } catch (IOException ioe) {
 633             assertTrue(ioe instanceof NoSuchFileException);
 634         }
 635     }
 636 
 637     public void testClosedStream() throws IOException {
 638         try (CloseableStream<Path> s = Files.list(testFolder)) {
 639             s.close();
 640             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 641             assertTrue(actual.length <= level1.length);


 642         }
 643 
 644         try (CloseableStream<Path> s = Files.walk(testFolder)) {
 645             s.close();
 646             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 647             fail("Operate on closed stream should throw IllegalStateException");
 648         } catch (IllegalStateException ex) {
 649             // expected
 650         }
 651 
 652         try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
 653                     (p, attr) -> true)) {
 654             s.close();
 655             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 656             fail("Operate on closed stream should throw IllegalStateException");
 657         } catch (IllegalStateException ex) {
 658             // expected
 659         }
 660     }
 661 }


  33 import java.io.UncheckedIOException;
  34 import java.nio.charset.Charset;
  35 import java.nio.charset.MalformedInputException;
  36 import java.nio.file.DirectoryIteratorException;
  37 import java.nio.file.DirectoryStream;
  38 import java.nio.file.FileSystemLoopException;
  39 import java.nio.file.FileVisitOption;
  40 import java.nio.file.Files;
  41 import java.nio.file.NoSuchFileException;
  42 import java.nio.file.Path;
  43 import java.nio.file.Paths;
  44 import java.nio.file.attribute.BasicFileAttributes;
  45 import java.util.Arrays;
  46 import java.util.Comparator;
  47 import java.util.Iterator;
  48 import java.util.List;
  49 import java.util.Objects;
  50 import java.util.Set;
  51 import java.util.TreeSet;
  52 import java.util.function.BiPredicate;
  53 import java.util.stream.Stream;
  54 import java.util.stream.Collectors;
  55 import org.testng.annotations.AfterClass;
  56 import org.testng.annotations.BeforeClass;
  57 import org.testng.annotations.Test;
  58 import static org.testng.Assert.*;
  59 
  60 @Test(groups = "unit")
  61 public class StreamTest {
  62     /**
  63      * Default test folder
  64      * testFolder - empty
  65      *            - file
  66      *            - dir - d1
  67      *                  - f1
  68      *                  - lnDir2 (../dir2)
  69      *            - dir2
  70      *            - linkDir (./dir)
  71      *            - linkFile(./file)
  72      */
  73     static Path testFolder;


 121         set.add(testFolder);
 122         all = set.toArray(new Path[0]);
 123 
 124         // Follow links
 125         if (supportsLinks) {
 126             tmp = testFolder.resolve("linkDir");
 127             set.add(tmp.resolve("d1"));
 128             set.add(tmp.resolve("f1"));
 129             tmp = tmp.resolve("lnDir2");
 130             set.add(tmp);
 131         }
 132         all_folowLinks = set.toArray(new Path[0]);
 133     }
 134 
 135     @AfterClass
 136     void cleanupTestFolder() throws IOException {
 137         TestUtil.removeAll(testFolder);
 138     }
 139 
 140     public void testBasic() {
 141         try (Stream<Path> s = Files.list(testFolder)) {
 142             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 143             assertEquals(actual, level1);
 144         } catch (IOException ioe) {
 145             fail("Unexpected IOException");
 146         }
 147 
 148         try (Stream<Path> s = Files.list(testFolder.resolve("empty"))) {
 149             int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
 150             assertEquals(count, 0, "Expect empty stream.");
 151         } catch (IOException ioe) {
 152             fail("Unexpected IOException");
 153         }
 154     }
 155 
 156     public void testWalk() {
 157         try (Stream<Path> s = Files.walk(testFolder)) {
 158             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 159             assertEquals(actual, all);
 160         } catch (IOException ioe) {
 161             fail("Unexpected IOException");
 162         }
 163     }
 164 
 165     public void testWalkOneLevel() {
 166         try (Stream<Path> s = Files.walk(testFolder, 1)) {
 167             Object[] actual = s.filter(path -> ! path.equals(testFolder))
 168                                .sorted(Comparator.naturalOrder())
 169                                .toArray();
 170             assertEquals(actual, level1);
 171         } catch (IOException ioe) {
 172             fail("Unexpected IOException");
 173         }
 174     }
 175 
 176     public void testWalkFollowLink() {
 177         // If link is not supported, the directory structure won't have link.
 178         // We still want to test the behavior with FOLLOW_LINKS option.
 179         try (Stream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
 180             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 181             assertEquals(actual, all_folowLinks);
 182         } catch (IOException ioe) {
 183             fail("Unexpected IOException");
 184         }
 185     }
 186 
 187     private void validateFileSystemLoopException(Path start, Path... causes) {
 188         try (Stream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
 189             try {
 190                 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
 191                 fail("Should got FileSystemLoopException, but got " + count + "elements.");
 192             } catch (UncheckedIOException uioe) {
 193                 IOException ioe = uioe.getCause();
 194                 if (ioe instanceof FileSystemLoopException) {
 195                     FileSystemLoopException fsle = (FileSystemLoopException) ioe;
 196                     boolean match = false;
 197                     for (Path cause: causes) {
 198                         if (fsle.getFile().equals(cause.toString())) {
 199                             match = true;
 200                             break;
 201                         }
 202                     }
 203                     assertTrue(match);
 204                 } else {
 205                     fail("Unexpected UncheckedIOException cause " + ioe.toString());
 206                 }
 207             }
 208         } catch(IOException ex) {


 265         private final BiPredicate<Path, BasicFileAttributes> pred;
 266         private final Set<Path> visited = new TreeSet<Path>();
 267 
 268         PathBiPredicate(BiPredicate<Path, BasicFileAttributes> pred) {
 269             this.pred = Objects.requireNonNull(pred);
 270         }
 271 
 272         public boolean test(Path path, BasicFileAttributes attrs) {
 273             visited.add(path);
 274             return pred.test(path, attrs);
 275         }
 276 
 277         public Path[] visited() {
 278             return visited.toArray(new Path[0]);
 279         }
 280     }
 281 
 282     public void testFind() throws IOException {
 283         PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
 284 
 285         try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 286             Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
 287             assertEquals(pred.visited(), all);
 288             assertEquals(result.toArray(new Path[0]), pred.visited());
 289         }
 290 
 291         pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
 292         try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 293             s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
 294             assertEquals(pred.visited(), all);
 295         }
 296 
 297         pred = new PathBiPredicate((path, attrs) ->
 298             path.getFileName().toString().startsWith("e"));
 299         try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 300             s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
 301             assertEquals(pred.visited(), all);
 302         }
 303 
 304         pred = new PathBiPredicate((path, attrs) ->
 305             path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
 306         try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
 307             s.forEach(path -> fail("Expect empty stream"));
 308             assertEquals(pred.visited(), all);
 309         }
 310     }
 311 
 312     // Test borrowed from BytesAndLines
 313     public void testLines() throws IOException {
 314         final Charset US_ASCII = Charset.forName("US-ASCII");
 315         Path tmpfile = Files.createTempFile("blah", "txt");
 316 
 317         try {
 318             // zero lines
 319             assertTrue(Files.size(tmpfile) == 0, "File should be empty");
 320             try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
 321                 assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
 322             }
 323 
 324             // one line
 325             byte[] hi = { (byte)'h', (byte)'i' };
 326             Files.write(tmpfile, hi);
 327             try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
 328                 List<String> lines = s.collect(Collectors.toList());
 329                 assertTrue(lines.size() == 1, "One line expected");
 330                 assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
 331             }
 332 
 333             // two lines using platform's line separator
 334             List<String> expected = Arrays.asList("hi", "there");
 335             Files.write(tmpfile, expected, US_ASCII);
 336             assertTrue(Files.size(tmpfile) > 0, "File is empty");
 337             try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
 338                 List<String> lines = s.collect(Collectors.toList());
 339                 assertTrue(lines.equals(expected), "Unexpected lines");
 340             }
 341 
 342             // MalformedInputException
 343             byte[] bad = { (byte)0xff, (byte)0xff };
 344             Files.write(tmpfile, bad);
 345             try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
 346                 try {
 347                     List<String> lines = s.collect(Collectors.toList());
 348                     throw new RuntimeException("UncheckedIOException expected");
 349                 } catch (UncheckedIOException ex) {
 350                     assertTrue(ex.getCause() instanceof MalformedInputException,
 351                                "MalformedInputException expected");
 352                 }
 353             }
 354 
 355             // NullPointerException
 356             try {
 357                 Files.lines(null, US_ASCII);
 358                 throw new RuntimeException("NullPointerException expected");
 359             } catch (NullPointerException ignore) { }
 360             try {
 361                 Files.lines(tmpfile, null);
 362                 throw new RuntimeException("NullPointerException expected");
 363             } catch (NullPointerException ignore) { }
 364 
 365         } finally {
 366             Files.delete(tmpfile);
 367         }
 368     }
 369 
 370     public void testDirectoryIteratorException() throws IOException {
 371         Path dir = testFolder.resolve("dir2");
 372         Path trigger = dir.resolve("DirectoryIteratorException");
 373         Files.createFile(trigger);
 374         FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
 375         FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);
 376 
 377         try {
 378             fsp.setFaultyMode(false);
 379             Path fakeRoot = fs.getRoot();
 380             try {
 381                 try (Stream<Path> s = Files.list(fakeRoot)) {
 382                     s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
 383                 }
 384             } catch (UncheckedIOException uioe) {
 385                 fail("Unexpected exception.");
 386             }
 387 
 388             fsp.setFaultyMode(true);
 389             try {
 390                 try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {
 391                     Iterator<Path> itor = ds.iterator();
 392                     while (itor.hasNext()) {
 393                         itor.next();
 394                     }
 395                 }
 396                 fail("Shoule throw DirectoryIteratorException");
 397             } catch (DirectoryIteratorException die) {
 398             }
 399 
 400             try {
 401                 try (Stream<Path> s = Files.list(fakeRoot)) {
 402                     s.forEach(path -> fail("should not get here"));
 403                 }
 404             } catch (UncheckedIOException uioe) {
 405                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
 406             } catch (DirectoryIteratorException die) {
 407                 fail("Should have been converted into UncheckedIOException.");
 408             }
 409         } finally {
 410             // Cleanup
 411             if (fs != null) {
 412                 fs.close();
 413             }
 414             Files.delete(trigger);
 415         }
 416     }
 417 
 418     public void testUncheckedIOException() throws IOException {
 419         Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));
 420         Files.createFile(triggerFile);
 421         Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));
 422         Files.createDirectories(triggerDir);
 423         Files.createFile(triggerDir.resolve("file"));
 424         FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
 425         FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
 426 
 427         try {
 428             fsp.setFaultyMode(false);
 429             Path fakeRoot = fs.getRoot();
 430             try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
 431                 // only one file
 432                 s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
 433             }
 434 
 435             try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
 436                 String[] result = s.map(path -> path.getFileName().toString())
 437                                    .toArray(String[]::new);
 438                 // ordered as depth-first
 439                 assertEquals(result, new String[] { "empty", "IOException", "file"});
 440             }
 441 
 442             fsp.setFaultyMode(true);
 443             try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
 444                 s.forEach(path -> fail("should have caused exception"));
 445             } catch (UncheckedIOException uioe) {
 446                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
 447             }
 448 
 449             try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
 450                 String[] result = s.map(path -> path.getFileName().toString())
 451                                    .toArray(String[]::new);
 452                 fail("should not reach here due to IOException");
 453             } catch (UncheckedIOException uioe) {
 454                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
 455             }
 456 
 457             try (Stream<Path> s = Files.walk(
 458                 fakeRoot.resolve("empty").resolve("IOException")))
 459             {
 460                 String[] result = s.map(path -> path.getFileName().toString())
 461                                    .toArray(String[]::new);
 462                 fail("should not reach here due to IOException");
 463             } catch (IOException ioe) {
 464                 assertTrue(ioe instanceof FaultyFileSystem.FaultyException);
 465             } catch (UncheckedIOException ex) {
 466                 fail("Top level should be repored as is");
 467             }
 468          } finally {
 469             // Cleanup
 470             if (fs != null) {
 471                 fs.close();
 472             }
 473             Files.delete(triggerFile);
 474             TestUtil.removeAll(triggerDir);
 475         }
 476     }
 477 


 485         Files.createFile(triggerDir.resolve("fileInSE"));
 486         Path sample = Files.createFile(dir2.resolve("file"));
 487 
 488         Path triggerLink = null;
 489         Path linkTriggerDir = null;
 490         Path linkTriggerFile = null;
 491         if (supportsLinks) {
 492             Path dir = testFolder.resolve("dir");
 493             triggerLink = Files.createSymbolicLink(dir.resolve("SecurityException"), empty);
 494             linkTriggerDir = Files.createSymbolicLink(dir.resolve("lnDirSE"), triggerDir);
 495             linkTriggerFile = Files.createSymbolicLink(dir.resolve("lnFileSE"), triggerFile);
 496         }
 497 
 498         FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
 499         FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
 500 
 501         try {
 502             fsp.setFaultyMode(false);
 503             Path fakeRoot = fs.getRoot();
 504             // validate setting
 505             try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
 506                 String[] result = s.map(path -> path.getFileName().toString())
 507                                    .toArray(String[]::new);
 508                 assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
 509             }
 510 
 511             try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
 512                 String[] result = s.map(path -> path.getFileName().toString())
 513                                    .toArray(String[]::new);
 514                 assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
 515             }
 516 
 517             if (supportsLinks) {
 518                 try (Stream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
 519                     String[] result = s.map(path -> path.getFileName().toString())
 520                                        .toArray(String[]::new);
 521                     assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
 522                 }
 523             }
 524 
 525             // execute test
 526             fsp.setFaultyMode(true);
 527             // ignore file cause SecurityException
 528             try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
 529                 String[] result = s.map(path -> path.getFileName().toString())
 530                                    .toArray(String[]::new);
 531                 assertEqualsNoOrder(result, new String[] { "empty", "sample" });
 532             }
 533             // skip folder cause SecurityException
 534             try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
 535                 String[] result = s.map(path -> path.getFileName().toString())
 536                                    .toArray(String[]::new);
 537                 assertEqualsNoOrder(result, new String[] { "dir2", "file" });
 538             }
 539 
 540             if (supportsLinks) {
 541                 // not following links
 542                 try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
 543                     String[] result = s.map(path -> path.getFileName().toString())
 544                                        .toArray(String[]::new);
 545                     assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
 546                 }
 547 
 548                 // following links
 549                 try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
 550                     String[] result = s.map(path -> path.getFileName().toString())
 551                                        .toArray(String[]::new);
 552                     // ?? Should fileInSE show up?
 553                     // With FaultyFS, it does as no exception thrown for link to "SecurityException" with read on "lnXxxSE"
 554                     assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "file", "lnDirSE", "lnFileSE", "fileInSE" });
 555                 }
 556             }
 557 
 558             // list instead of walk
 559             try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
 560                 String[] result = s.map(path -> path.getFileName().toString())
 561                                    .toArray(String[]::new);
 562                 assertEqualsNoOrder(result, new String[] { "sample" });
 563             }
 564             try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
 565                 String[] result = s.map(path -> path.getFileName().toString())
 566                                    .toArray(String[]::new);
 567                 assertEqualsNoOrder(result, new String[] { "file" });
 568             }
 569 
 570             // root cause SecurityException should be reported
 571             try (Stream<Path> s = Files.walk(
 572                 fakeRoot.resolve("dir2").resolve("SecurityException")))
 573             {
 574                 String[] result = s.map(path -> path.getFileName().toString())
 575                                    .toArray(String[]::new);
 576                 fail("should not reach here due to SecurityException");
 577             } catch (SecurityException se) {
 578                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 579             }
 580 
 581             // Walk a file cause SecurityException, we should get SE
 582             try (Stream<Path> s = Files.walk(
 583                 fakeRoot.resolve("dir").resolve("SecurityException")))
 584             {
 585                 String[] result = s.map(path -> path.getFileName().toString())
 586                                    .toArray(String[]::new);
 587                 fail("should not reach here due to SecurityException");
 588             } catch (SecurityException se) {
 589                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 590             }
 591 
 592             // List a file cause SecurityException, we should get SE as cannot read attribute
 593             try (Stream<Path> s = Files.list(
 594                 fakeRoot.resolve("dir2").resolve("SecurityException")))
 595             {
 596                 String[] result = s.map(path -> path.getFileName().toString())
 597                                    .toArray(String[]::new);
 598                 fail("should not reach here due to SecurityException");
 599             } catch (SecurityException se) {
 600                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 601             }
 602 
 603             try (Stream<Path> s = Files.list(
 604                 fakeRoot.resolve("dir").resolve("SecurityException")))
 605             {
 606                 String[] result = s.map(path -> path.getFileName().toString())
 607                                    .toArray(String[]::new);
 608                 fail("should not reach here due to SecurityException");
 609             } catch (SecurityException se) {
 610                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
 611             }
 612          } finally {
 613             // Cleanup
 614             if (fs != null) {
 615                 fs.close();
 616             }
 617             if (supportsLinks) {
 618                 Files.delete(triggerLink);
 619                 Files.delete(linkTriggerDir);
 620                 Files.delete(linkTriggerFile);
 621             }
 622             Files.delete(triggerFile);
 623             Files.delete(sampleFile);
 624             Files.delete(sample);
 625             TestUtil.removeAll(triggerDir);
 626         }
 627     }
 628 
 629     public void testConstructException() {
 630         try (Stream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
 631             s.forEach(l -> fail("File is not even exist!"));
 632         } catch (IOException ioe) {
 633             assertTrue(ioe instanceof NoSuchFileException);
 634         }
 635     }
 636 
 637     public void testClosedStream() throws IOException {
 638         try (Stream<Path> s = Files.list(testFolder)) {
 639             s.close();
 640             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 641             fail("Operate on closed stream should throw IllegalStateException");
 642         } catch (IllegalStateException ex) {
 643             // expected
 644         }
 645 
 646         try (Stream<Path> s = Files.walk(testFolder)) {
 647             s.close();
 648             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 649             fail("Operate on closed stream should throw IllegalStateException");
 650         } catch (IllegalStateException ex) {
 651             // expected
 652         }
 653 
 654         try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
 655                     (p, attr) -> true)) {
 656             s.close();
 657             Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
 658             fail("Operate on closed stream should throw IllegalStateException");
 659         } catch (IllegalStateException ex) {
 660             // expected
 661         }
 662     }
 663 }