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.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;
  73     static boolean supportsLinks;
  74     static Path[] level1;
  75     static Path[] all;
  76     static Path[] all_folowLinks;
  77 
  78     @BeforeClass
  79     void setupTestFolder() throws IOException {
  80         testFolder = TestUtil.createTemporaryDirectory();
  81         supportsLinks = TestUtil.supportsLinks(testFolder);
  82         TreeSet<Path> set = new TreeSet<>();
  83 
  84         // Level 1
  85         Path empty = testFolder.resolve("empty");
  86         Path file = testFolder.resolve("file");
  87         Path dir = testFolder.resolve("dir");
  88         Path dir2 = testFolder.resolve("dir2");
  89         Files.createDirectory(empty);
  90         Files.createFile(file);
  91         Files.createDirectory(dir);
  92         Files.createDirectory(dir2);
  93         set.add(empty);
  94         set.add(file);
  95         set.add(dir);
  96         set.add(dir2);
  97         if (supportsLinks) {
  98             Path tmp = testFolder.resolve("linkDir");
  99             Files.createSymbolicLink(tmp, dir);
 100             set.add(tmp);
 101             tmp = testFolder.resolve("linkFile");
 102             Files.createSymbolicLink(tmp, file);
 103             set.add(tmp);
 104         }
 105         level1 = set.toArray(new Path[0]);
 106 
 107         // Level 2
 108         Path tmp = dir.resolve("d1");
 109         Files.createDirectory(tmp);
 110         set.add(tmp);
 111         tmp = dir.resolve("f1");
 112         Files.createFile(tmp);
 113         set.add(tmp);
 114         if (supportsLinks) {
 115             tmp = dir.resolve("lnDir2");
 116             Files.createSymbolicLink(tmp, dir2);
 117             set.add(tmp);
 118         }
 119         // walk include starting folder
 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) {
 208             fail("Unexpected IOException " + ex);
 209         }
 210     }
 211 
 212     public void testWalkFollowLinkLoop() {
 213         if (!supportsLinks) {
 214             return;
 215         }
 216 
 217         // Loops.
 218         try {
 219             Path dir = testFolder.resolve("dir");
 220             Path linkdir = testFolder.resolve("linkDir");
 221             Path d1 = dir.resolve("d1");
 222             Path cause = d1.resolve("lnSelf");
 223             Files.createSymbolicLink(cause, d1);
 224 
 225             // loop in descendant.
 226             validateFileSystemLoopException(dir, cause);
 227             // loop in self
 228             validateFileSystemLoopException(d1, cause);
 229             // start from other place via link
 230             validateFileSystemLoopException(linkdir,
 231                     linkdir.resolve(Paths.get("d1", "lnSelf")));
 232             Files.delete(cause);
 233 
 234             // loop to parent.
 235             cause = d1.resolve("lnParent");
 236             Files.createSymbolicLink(cause, dir);
 237 
 238             // loop should be detected at test/dir/d1/lnParent/d1
 239             validateFileSystemLoopException(d1, cause.resolve("d1"));
 240             // loop should be detected at link
 241             validateFileSystemLoopException(dir, cause);
 242             // loop should be detected at test/linkdir/d1/lnParent
 243             // which is test/dir we have visited via test/linkdir
 244             validateFileSystemLoopException(linkdir,
 245                     linkdir.resolve(Paths.get("d1", "lnParent")));
 246             Files.delete(cause);
 247 
 248             // cross loop
 249             Path dir2 = testFolder.resolve("dir2");
 250             cause = dir2.resolve("lnDir");
 251             Files.createSymbolicLink(cause, dir);
 252             validateFileSystemLoopException(dir,
 253                     dir.resolve(Paths.get("lnDir2", "lnDir")));
 254             validateFileSystemLoopException(dir2,
 255                     dir2.resolve(Paths.get("lnDir", "lnDir2")));
 256             validateFileSystemLoopException(linkdir,
 257                     linkdir.resolve(Paths.get("lnDir2", "lnDir")));
 258         } catch(IOException ioe) {
 259             fail("Unexpected IOException " + ioe);
 260         }
 261     }
 262 
 263     private static class PathBiPredicate implements BiPredicate<Path, BasicFileAttributes> {
 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 
 477     public void testSecurityException() throws IOException {
 478         Path empty = testFolder.resolve("empty");
 479         Path triggerFile = Files.createFile(empty.resolve("SecurityException"));
 480         Path sampleFile = Files.createDirectories(empty.resolve("sample"));
 481 
 482         Path dir2 = testFolder.resolve("dir2");
 483         Path triggerDir = Files.createDirectories(dir2.resolve("SecurityException"));
 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 }