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

Print this page
rev 7962 : 8017513: Support for closeable streams
8022237: j.u.s.BaseStream.onClose() has an issue in implementation or requires spec clarification
8022572: Same exception instances thrown from j.u.stream.Stream.onClose() handlers are not listed as suppressed
Summary: BaseStream implements AutoCloseable; Remove CloseableStream and DelegatingStream
Reviewed-by:
Contributed-by: brian.goetz@oracle.com


  26  * @summary Unit test for java.nio.file.Files
  27  * @library ..
  28  * @build PassThroughFileSystem FaultyFileSystem
  29  * @run testng StreamTest
  30  */
  31 
  32 import java.io.IOException;
  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 }


  26  * @summary Unit test for java.nio.file.Files
  27  * @library ..
  28  * @build PassThroughFileSystem FaultyFileSystem
  29  * @run testng StreamTest
  30  */
  31 
  32 import java.io.IOException;
  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.Iterator;
  47 import java.util.List;
  48 import java.util.Objects;
  49 import java.util.Set;
  50 import java.util.TreeSet;
  51 import java.util.function.BiPredicate;
  52 import java.util.stream.Stream;
  53 import java.util.stream.Collectors;
  54 import org.testng.annotations.AfterClass;
  55 import org.testng.annotations.BeforeClass;
  56 import org.testng.annotations.Test;
  57 import static org.testng.Assert.*;
  58 
  59 @Test(groups = "unit")
  60 public class StreamTest {
  61     /**
  62      * Default test folder
  63      * testFolder - empty
  64      *            - file
  65      *            - dir - d1
  66      *                  - f1
  67      *                  - lnDir2 (../dir2)
  68      *            - dir2
  69      *            - linkDir (./dir)
  70      *            - linkFile(./file)
  71      */
  72     static Path testFolder;


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


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


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