1 /*
   2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 8006884
  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;
  74     static boolean supportsLinks;
  75     static Path[] level1;
  76     static Path[] all;
  77     static Path[] all_folowLinks;
  78 
  79     @BeforeClass
  80     void setupTestFolder() throws IOException {
  81         testFolder = TestUtil.createTemporaryDirectory();
  82         supportsLinks = TestUtil.supportsLinks(testFolder);
  83         TreeSet<Path> set = new TreeSet<>();
  84 
  85         // Level 1
  86         Path empty = testFolder.resolve("empty");
  87         Path file = testFolder.resolve("file");
  88         Path dir = testFolder.resolve("dir");
  89         Path dir2 = testFolder.resolve("dir2");
  90         Files.createDirectory(empty);
  91         Files.createFile(file);
  92         Files.createDirectory(dir);
  93         Files.createDirectory(dir2);
  94         set.add(empty);
  95         set.add(file);
  96         set.add(dir);
  97         set.add(dir2);
  98         if (supportsLinks) {
  99             Path tmp = testFolder.resolve("linkDir");
 100             Files.createSymbolicLink(tmp, dir);
 101             set.add(tmp);
 102             tmp = testFolder.resolve("linkFile");
 103             Files.createSymbolicLink(tmp, file);
 104             set.add(tmp);
 105         }
 106         level1 = set.toArray(new Path[0]);
 107 
 108         // Level 2
 109         Path tmp = dir.resolve("d1");
 110         Files.createDirectory(tmp);
 111         set.add(tmp);
 112         tmp = dir.resolve("f1");
 113         Files.createFile(tmp);
 114         set.add(tmp);
 115         if (supportsLinks) {
 116             tmp = dir.resolve("lnDir2");
 117             Files.createSymbolicLink(tmp, dir2);
 118             set.add(tmp);
 119         }
 120         // walk include starting folder
 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) {
 209             fail("Unexpected IOException " + ex);
 210         }
 211     }
 212 
 213     public void testWalkFollowLinkLoop() {
 214         if (!supportsLinks) {
 215             return;
 216         }
 217 
 218         // Loops.
 219         try {
 220             Path dir = testFolder.resolve("dir");
 221             Path linkdir = testFolder.resolve("linkDir");
 222             Path d1 = dir.resolve("d1");
 223             Path cause = d1.resolve("lnSelf");
 224             Files.createSymbolicLink(cause, d1);
 225 
 226             // loop in descendant.
 227             validateFileSystemLoopException(dir, cause);
 228             // loop in self
 229             validateFileSystemLoopException(d1, cause);
 230             // start from other place via link
 231             validateFileSystemLoopException(linkdir,
 232                     linkdir.resolve(Paths.get("d1", "lnSelf")));
 233             Files.delete(cause);
 234 
 235             // loop to parent.
 236             cause = d1.resolve("lnParent");
 237             Files.createSymbolicLink(cause, dir);
 238 
 239             // loop should be detected at test/dir/d1/lnParent/d1
 240             validateFileSystemLoopException(d1, cause.resolve("d1"));
 241             // loop should be detected at link
 242             validateFileSystemLoopException(dir, cause);
 243             // loop should be detected at test/linkdir/d1/lnParent
 244             // which is test/dir we have visited via test/linkdir
 245             validateFileSystemLoopException(linkdir,
 246                     linkdir.resolve(Paths.get("d1", "lnParent")));
 247             Files.delete(cause);
 248 
 249             // cross loop
 250             Path dir2 = testFolder.resolve("dir2");
 251             cause = dir2.resolve("lnDir");
 252             Files.createSymbolicLink(cause, dir);
 253             validateFileSystemLoopException(dir,
 254                     dir.resolve(Paths.get("lnDir2", "lnDir")));
 255             validateFileSystemLoopException(dir2,
 256                     dir2.resolve(Paths.get("lnDir", "lnDir2")));
 257             validateFileSystemLoopException(linkdir,
 258                     linkdir.resolve(Paths.get("lnDir2", "lnDir")));
 259         } catch(IOException ioe) {
 260             fail("Unexpected IOException " + ioe);
 261         }
 262     }
 263 
 264     private static class PathBiPredicate implements BiPredicate<Path, BasicFileAttributes> {
 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 
 478     public void testSecurityException() throws IOException {
 479         Path empty = testFolder.resolve("empty");
 480         Path triggerFile = Files.createFile(empty.resolve("SecurityException"));
 481         Path sampleFile = Files.createDirectories(empty.resolve("sample"));
 482 
 483         Path dir2 = testFolder.resolve("dir2");
 484         Path triggerDir = Files.createDirectories(dir2.resolve("SecurityException"));
 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 }