StreamTest.java revision 8374:9632de07d963
10Sduke/*
211884Sykantser * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
30Sduke * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
40Sduke *
50Sduke * This code is free software; you can redistribute it and/or modify it
60Sduke * under the terms of the GNU General Public License version 2 only, as
70Sduke * published by the Free Software Foundation.
80Sduke *
90Sduke * This code is distributed in the hope that it will be useful, but WITHOUT
100Sduke * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
110Sduke * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
120Sduke * version 2 for more details (a copy is included in the LICENSE file that
130Sduke * accompanied this code).
140Sduke *
150Sduke * You should have received a copy of the GNU General Public License version
160Sduke * 2 along with this work; if not, write to the Free Software Foundation,
170Sduke * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
180Sduke *
192362Sohair * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202362Sohair * or visit www.oracle.com if you need additional information or have any
212362Sohair * questions.
220Sduke */
230Sduke
240Sduke/* @test
250Sduke * @bug 8006884 8019526
260Sduke * @build PassThroughFileSystem FaultyFileSystem
270Sduke * @run testng StreamTest
280Sduke * @summary Unit test for java.nio.file.Files methods that return a Stream
290Sduke */
3016603Sdfuchs
310Sdukeimport java.io.IOException;
320Sdukeimport java.io.UncheckedIOException;
330Sdukeimport java.nio.charset.Charset;
340Sdukeimport java.nio.charset.MalformedInputException;
350Sdukeimport java.nio.file.DirectoryIteratorException;
360Sdukeimport java.nio.file.DirectoryStream;
370Sdukeimport java.nio.file.FileSystemLoopException;
380Sdukeimport java.nio.file.FileVisitOption;
390Sdukeimport java.nio.file.Files;
400Sdukeimport java.nio.file.NoSuchFileException;
410Sdukeimport java.nio.file.Path;
420Sdukeimport java.nio.file.Paths;
430Sdukeimport java.nio.file.attribute.BasicFileAttributes;
440Sdukeimport java.util.Arrays;
450Sdukeimport java.util.Collections;
460Sdukeimport java.util.Iterator;
470Sdukeimport java.util.List;
480Sdukeimport java.util.Objects;
490Sdukeimport java.util.Set;
500Sdukeimport java.util.TreeSet;
510Sdukeimport java.util.concurrent.Callable;
520Sdukeimport java.util.function.BiPredicate;
530Sdukeimport java.util.stream.Stream;
540Sdukeimport java.util.stream.Collectors;
550Sdukeimport org.testng.annotations.AfterClass;
560Sdukeimport org.testng.annotations.BeforeClass;
570Sdukeimport org.testng.annotations.Test;
580Sdukeimport static org.testng.Assert.*;
590Sduke
600Sduke@Test(groups = "unit")
610Sdukepublic class StreamTest {
620Sduke    /**
630Sduke     * Default test folder
640Sduke     * testFolder - empty
650Sduke     *            - file
660Sduke     *            - dir - d1
670Sduke     *                  - f1
680Sduke     *                  - lnDir2 (../dir2)
690Sduke     *            - dir2
700Sduke     *            - linkDir (./dir)
710Sduke     *            - linkFile(./file)
720Sduke     */
730Sduke    static Path testFolder;
740Sduke    static boolean supportsLinks;
750Sduke    static Path[] level1;
760Sduke    static Path[] all;
770Sduke    static Path[] all_folowLinks;
780Sduke
790Sduke    @BeforeClass
800Sduke    void setupTestFolder() throws IOException {
810Sduke        testFolder = TestUtil.createTemporaryDirectory();
820Sduke        supportsLinks = TestUtil.supportsLinks(testFolder);
830Sduke        TreeSet<Path> set = new TreeSet<>();
840Sduke
850Sduke        // Level 1
860Sduke        Path empty = testFolder.resolve("empty");
870Sduke        Path file = testFolder.resolve("file");
880Sduke        Path dir = testFolder.resolve("dir");
890Sduke        Path dir2 = testFolder.resolve("dir2");
900Sduke        Files.createDirectory(empty);
910Sduke        Files.createFile(file);
920Sduke        Files.createDirectory(dir);
930Sduke        Files.createDirectory(dir2);
940Sduke        set.add(empty);
950Sduke        set.add(file);
960Sduke        set.add(dir);
970Sduke        set.add(dir2);
980Sduke        if (supportsLinks) {
990Sduke            Path tmp = testFolder.resolve("linkDir");
1000Sduke            Files.createSymbolicLink(tmp, dir);
1010Sduke            set.add(tmp);
1020Sduke            tmp = testFolder.resolve("linkFile");
1030Sduke            Files.createSymbolicLink(tmp, file);
1040Sduke            set.add(tmp);
1050Sduke        }
1060Sduke        level1 = set.toArray(new Path[0]);
1070Sduke
1080Sduke        // Level 2
1090Sduke        Path tmp = dir.resolve("d1");
1100Sduke        Files.createDirectory(tmp);
1110Sduke        set.add(tmp);
1120Sduke        tmp = dir.resolve("f1");
1130Sduke        Files.createFile(tmp);
1140Sduke        set.add(tmp);
1150Sduke        if (supportsLinks) {
1160Sduke            tmp = dir.resolve("lnDir2");
1170Sduke            Files.createSymbolicLink(tmp, dir2);
1180Sduke            set.add(tmp);
1190Sduke        }
1200Sduke        // walk include starting folder
1210Sduke        set.add(testFolder);
1220Sduke        all = set.toArray(new Path[0]);
1230Sduke
1240Sduke        // Follow links
1250Sduke        if (supportsLinks) {
1260Sduke            tmp = testFolder.resolve("linkDir");
1270Sduke            set.add(tmp.resolve("d1"));
1280Sduke            set.add(tmp.resolve("f1"));
1290Sduke            tmp = tmp.resolve("lnDir2");
1300Sduke            set.add(tmp);
1310Sduke        }
1320Sduke        all_folowLinks = set.toArray(new Path[0]);
1330Sduke    }
1340Sduke
1350Sduke    @AfterClass
1360Sduke    void cleanupTestFolder() throws IOException {
1370Sduke        TestUtil.removeAll(testFolder);
1380Sduke    }
1390Sduke
1400Sduke    public void testBasic() {
1410Sduke        try (Stream<Path> s = Files.list(testFolder)) {
1420Sduke            Object[] actual = s.sorted().toArray();
1430Sduke            assertEquals(actual, level1);
1440Sduke        } catch (IOException ioe) {
1450Sduke            fail("Unexpected IOException");
1460Sduke        }
1470Sduke
1480Sduke        try (Stream<Path> s = Files.list(testFolder.resolve("empty"))) {
1490Sduke            int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
1500Sduke            assertEquals(count, 0, "Expect empty stream.");
1510Sduke        } catch (IOException ioe) {
1520Sduke            fail("Unexpected IOException");
1530Sduke        }
1540Sduke    }
1550Sduke
1560Sduke    public void testWalk() {
1570Sduke        try (Stream<Path> s = Files.walk(testFolder)) {
1580Sduke            Object[] actual = s.sorted().toArray();
1590Sduke            assertEquals(actual, all);
1600Sduke        } catch (IOException ioe) {
161            fail("Unexpected IOException");
162        }
163    }
164
165    public void testWalkOneLevel() {
166        try (Stream<Path> s = Files.walk(testFolder, 1)) {
167            Object[] actual = s.filter(path -> ! path.equals(testFolder))
168                               .sorted()
169                               .toArray();
170            assertEquals(actual, level1);
171        } catch (IOException ioe) {
172            fail("Unexpected IOException");
173        }
174    }
175
176    public void testWalkFollowLink() {
177        // If link is not supported, the directory structure won't have link.
178        // We still want to test the behavior with FOLLOW_LINKS option.
179        try (Stream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
180            Object[] actual = s.sorted().toArray();
181            assertEquals(actual, all_folowLinks);
182        } catch (IOException ioe) {
183            fail("Unexpected IOException");
184        }
185    }
186
187    private void validateFileSystemLoopException(Path start, Path... causes) {
188        try (Stream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
189            try {
190                int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
191                fail("Should got FileSystemLoopException, but got " + count + "elements.");
192            } catch (UncheckedIOException uioe) {
193                IOException ioe = uioe.getCause();
194                if (ioe instanceof FileSystemLoopException) {
195                    FileSystemLoopException fsle = (FileSystemLoopException) ioe;
196                    boolean match = false;
197                    for (Path cause: causes) {
198                        if (fsle.getFile().equals(cause.toString())) {
199                            match = true;
200                            break;
201                        }
202                    }
203                    assertTrue(match);
204                } else {
205                    fail("Unexpected UncheckedIOException cause " + ioe.toString());
206                }
207            }
208        } catch(IOException ex) {
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 (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
286            Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
287            assertEquals(pred.visited(), all);
288            assertEquals(result.toArray(new Path[0]), pred.visited());
289        }
290
291        pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
292        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
293            s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
294            assertEquals(pred.visited(), all);
295        }
296
297        pred = new PathBiPredicate((path, attrs) ->
298            path.getFileName().toString().startsWith("e"));
299        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
300            s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
301            assertEquals(pred.visited(), all);
302        }
303
304        pred = new PathBiPredicate((path, attrs) ->
305            path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
306        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
307            s.forEach(path -> fail("Expect empty stream"));
308            assertEquals(pred.visited(), all);
309        }
310    }
311
312    // Test borrowed from BytesAndLines
313    public void testLines() throws IOException {
314        final Charset US_ASCII = Charset.forName("US-ASCII");
315        Path tmpfile = Files.createTempFile("blah", "txt");
316
317        try {
318            // zero lines
319            assertTrue(Files.size(tmpfile) == 0, "File should be empty");
320            try (Stream<String> s = Files.lines(tmpfile)) {
321                checkLines(s, Collections.emptyList());
322            }
323            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
324                checkLines(s, Collections.emptyList());
325            }
326
327            // one line
328            List<String> oneLine = Arrays.asList("hi");
329            Files.write(tmpfile, oneLine, US_ASCII);
330            try (Stream<String> s = Files.lines(tmpfile)) {
331                checkLines(s, oneLine);
332            }
333            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
334                checkLines(s, oneLine);
335            }
336
337            // two lines using platform's line separator
338            List<String> twoLines = Arrays.asList("hi", "there");
339            Files.write(tmpfile, twoLines, US_ASCII);
340            try (Stream<String> s = Files.lines(tmpfile)) {
341                checkLines(s, twoLines);
342            }
343            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
344                checkLines(s, twoLines);
345            }
346
347            // MalformedInputException
348            byte[] bad = { (byte)0xff, (byte)0xff };
349            Files.write(tmpfile, bad);
350            try (Stream<String> s = Files.lines(tmpfile)) {
351                checkMalformedInputException(s);
352            }
353            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
354                checkMalformedInputException(s);
355            }
356
357            // NullPointerException
358            checkNullPointerException(() -> Files.lines(null));
359            checkNullPointerException(() -> Files.lines(null, US_ASCII));
360            checkNullPointerException(() -> Files.lines(tmpfile, null));
361
362        } finally {
363            Files.delete(tmpfile);
364        }
365    }
366
367    private void checkLines(Stream<String> s, List<String> expected) {
368        List<String> lines = s.collect(Collectors.toList());
369        assertTrue(lines.size() == expected.size(), "Unexpected number of lines");
370        assertTrue(lines.equals(expected), "Unexpected content");
371    }
372
373    private void checkMalformedInputException(Stream<String> s) {
374        try {
375            List<String> lines = s.collect(Collectors.toList());
376            fail("UncheckedIOException expected");
377        } catch (UncheckedIOException ex) {
378            IOException cause = ex.getCause();
379            assertTrue(cause instanceof MalformedInputException,
380                "MalformedInputException expected");
381        }
382    }
383
384    private void checkNullPointerException(Callable<?> c) {
385        try {
386            c.call();
387            fail("NullPointerException expected");
388        } catch (NullPointerException ignore) {
389        } catch (Exception e) {
390            fail(e + " not expected");
391        }
392    }
393
394    public void testDirectoryIteratorException() throws IOException {
395        Path dir = testFolder.resolve("dir2");
396        Path trigger = dir.resolve("DirectoryIteratorException");
397        Files.createFile(trigger);
398        FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
399        FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);
400
401        try {
402            fsp.setFaultyMode(false);
403            Path fakeRoot = fs.getRoot();
404            try {
405                try (Stream<Path> s = Files.list(fakeRoot)) {
406                    s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
407                }
408            } catch (UncheckedIOException uioe) {
409                fail("Unexpected exception.");
410            }
411
412            fsp.setFaultyMode(true);
413            try {
414                try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {
415                    Iterator<Path> itor = ds.iterator();
416                    while (itor.hasNext()) {
417                        itor.next();
418                    }
419                }
420                fail("Shoule throw DirectoryIteratorException");
421            } catch (DirectoryIteratorException die) {
422            }
423
424            try {
425                try (Stream<Path> s = Files.list(fakeRoot)) {
426                    s.forEach(path -> fail("should not get here"));
427                }
428            } catch (UncheckedIOException uioe) {
429                assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
430            } catch (DirectoryIteratorException die) {
431                fail("Should have been converted into UncheckedIOException.");
432            }
433        } finally {
434            // Cleanup
435            if (fs != null) {
436                fs.close();
437            }
438            Files.delete(trigger);
439        }
440    }
441
442    public void testUncheckedIOException() throws IOException {
443        Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));
444        Files.createFile(triggerFile);
445        Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));
446        Files.createDirectories(triggerDir);
447        Files.createFile(triggerDir.resolve("file"));
448        FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
449        FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
450
451        try {
452            fsp.setFaultyMode(false);
453            Path fakeRoot = fs.getRoot();
454            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
455                // only one file
456                s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
457            }
458
459            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
460                String[] result = s.map(path -> path.getFileName().toString())
461                                   .toArray(String[]::new);
462                // ordered as depth-first
463                assertEquals(result, new String[] { "empty", "IOException", "file"});
464            }
465
466            fsp.setFaultyMode(true);
467            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
468                s.forEach(path -> fail("should have caused exception"));
469            } catch (UncheckedIOException uioe) {
470                assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
471            }
472
473            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
474                String[] result = s.map(path -> path.getFileName().toString())
475                                   .toArray(String[]::new);
476                fail("should not reach here due to IOException");
477            } catch (UncheckedIOException uioe) {
478                assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
479            }
480
481            try (Stream<Path> s = Files.walk(
482                fakeRoot.resolve("empty").resolve("IOException")))
483            {
484                String[] result = s.map(path -> path.getFileName().toString())
485                                   .toArray(String[]::new);
486                fail("should not reach here due to IOException");
487            } catch (IOException ioe) {
488                assertTrue(ioe instanceof FaultyFileSystem.FaultyException);
489            } catch (UncheckedIOException ex) {
490                fail("Top level should be repored as is");
491            }
492         } finally {
493            // Cleanup
494            if (fs != null) {
495                fs.close();
496            }
497            Files.delete(triggerFile);
498            TestUtil.removeAll(triggerDir);
499        }
500    }
501
502    public void testSecurityException() throws IOException {
503        Path empty = testFolder.resolve("empty");
504        Path triggerFile = Files.createFile(empty.resolve("SecurityException"));
505        Path sampleFile = Files.createDirectories(empty.resolve("sample"));
506
507        Path dir2 = testFolder.resolve("dir2");
508        Path triggerDir = Files.createDirectories(dir2.resolve("SecurityException"));
509        Files.createFile(triggerDir.resolve("fileInSE"));
510        Path sample = Files.createFile(dir2.resolve("file"));
511
512        Path triggerLink = null;
513        Path linkTriggerDir = null;
514        Path linkTriggerFile = null;
515        if (supportsLinks) {
516            Path dir = testFolder.resolve("dir");
517            triggerLink = Files.createSymbolicLink(dir.resolve("SecurityException"), empty);
518            linkTriggerDir = Files.createSymbolicLink(dir.resolve("lnDirSE"), triggerDir);
519            linkTriggerFile = Files.createSymbolicLink(dir.resolve("lnFileSE"), triggerFile);
520        }
521
522        FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
523        FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
524
525        try {
526            fsp.setFaultyMode(false);
527            Path fakeRoot = fs.getRoot();
528            // validate setting
529            try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
530                String[] result = s.map(path -> path.getFileName().toString())
531                                   .toArray(String[]::new);
532                assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
533            }
534
535            try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
536                String[] result = s.map(path -> path.getFileName().toString())
537                                   .toArray(String[]::new);
538                assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
539            }
540
541            if (supportsLinks) {
542                try (Stream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
543                    String[] result = s.map(path -> path.getFileName().toString())
544                                       .toArray(String[]::new);
545                    assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
546                }
547            }
548
549            // execute test
550            fsp.setFaultyMode(true);
551            // ignore file cause SecurityException
552            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
553                String[] result = s.map(path -> path.getFileName().toString())
554                                   .toArray(String[]::new);
555                assertEqualsNoOrder(result, new String[] { "empty", "sample" });
556            }
557            // skip folder cause SecurityException
558            try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
559                String[] result = s.map(path -> path.getFileName().toString())
560                                   .toArray(String[]::new);
561                assertEqualsNoOrder(result, new String[] { "dir2", "file" });
562            }
563
564            if (supportsLinks) {
565                // not following links
566                try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
567                    String[] result = s.map(path -> path.getFileName().toString())
568                                       .toArray(String[]::new);
569                    assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
570                }
571
572                // following links
573                try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
574                    String[] result = s.map(path -> path.getFileName().toString())
575                                       .toArray(String[]::new);
576                    // ?? Should fileInSE show up?
577                    // With FaultyFS, it does as no exception thrown for link to "SecurityException" with read on "lnXxxSE"
578                    assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "file", "lnDirSE", "lnFileSE", "fileInSE" });
579                }
580            }
581
582            // list instead of walk
583            try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
584                String[] result = s.map(path -> path.getFileName().toString())
585                                   .toArray(String[]::new);
586                assertEqualsNoOrder(result, new String[] { "sample" });
587            }
588            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
589                String[] result = s.map(path -> path.getFileName().toString())
590                                   .toArray(String[]::new);
591                assertEqualsNoOrder(result, new String[] { "file" });
592            }
593
594            // root cause SecurityException should be reported
595            try (Stream<Path> s = Files.walk(
596                fakeRoot.resolve("dir2").resolve("SecurityException")))
597            {
598                String[] result = s.map(path -> path.getFileName().toString())
599                                   .toArray(String[]::new);
600                fail("should not reach here due to SecurityException");
601            } catch (SecurityException se) {
602                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
603            }
604
605            // Walk a file cause SecurityException, we should get SE
606            try (Stream<Path> s = Files.walk(
607                fakeRoot.resolve("dir").resolve("SecurityException")))
608            {
609                String[] result = s.map(path -> path.getFileName().toString())
610                                   .toArray(String[]::new);
611                fail("should not reach here due to SecurityException");
612            } catch (SecurityException se) {
613                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
614            }
615
616            // List a file cause SecurityException, we should get SE as cannot read attribute
617            try (Stream<Path> s = Files.list(
618                fakeRoot.resolve("dir2").resolve("SecurityException")))
619            {
620                String[] result = s.map(path -> path.getFileName().toString())
621                                   .toArray(String[]::new);
622                fail("should not reach here due to SecurityException");
623            } catch (SecurityException se) {
624                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
625            }
626
627            try (Stream<Path> s = Files.list(
628                fakeRoot.resolve("dir").resolve("SecurityException")))
629            {
630                String[] result = s.map(path -> path.getFileName().toString())
631                                   .toArray(String[]::new);
632                fail("should not reach here due to SecurityException");
633            } catch (SecurityException se) {
634                assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
635            }
636         } finally {
637            // Cleanup
638            if (fs != null) {
639                fs.close();
640            }
641            if (supportsLinks) {
642                Files.delete(triggerLink);
643                Files.delete(linkTriggerDir);
644                Files.delete(linkTriggerFile);
645            }
646            Files.delete(triggerFile);
647            Files.delete(sampleFile);
648            Files.delete(sample);
649            TestUtil.removeAll(triggerDir);
650        }
651    }
652
653    public void testConstructException() {
654        try (Stream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
655            s.forEach(l -> fail("File is not even exist!"));
656        } catch (IOException ioe) {
657            assertTrue(ioe instanceof NoSuchFileException);
658        }
659    }
660
661    public void testClosedStream() throws IOException {
662        try (Stream<Path> s = Files.list(testFolder)) {
663            s.close();
664            Object[] actual = s.sorted().toArray();
665            fail("Operate on closed stream should throw IllegalStateException");
666        } catch (IllegalStateException ex) {
667            // expected
668        }
669
670        try (Stream<Path> s = Files.walk(testFolder)) {
671            s.close();
672            Object[] actual = s.sorted().toArray();
673            fail("Operate on closed stream should throw IllegalStateException");
674        } catch (IllegalStateException ex) {
675            // expected
676        }
677
678        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
679                    (p, attr) -> true)) {
680            s.close();
681            Object[] actual = s.sorted().toArray();
682            fail("Operate on closed stream should throw IllegalStateException");
683        } catch (IllegalStateException ex) {
684            // expected
685        }
686    }
687}
688