26 * @summary Unit test for java.nio.file.Files
27 * @library ..
28 * @build PassThroughFileSystem FaultyFileSystem
29 * @run testng StreamTest
30 */
31
32 import java.io.IOException;
33 import java.io.UncheckedIOException;
34 import java.nio.charset.Charset;
35 import java.nio.charset.MalformedInputException;
36 import java.nio.file.DirectoryIteratorException;
37 import java.nio.file.DirectoryStream;
38 import java.nio.file.FileSystemLoopException;
39 import java.nio.file.FileVisitOption;
40 import java.nio.file.Files;
41 import java.nio.file.NoSuchFileException;
42 import java.nio.file.Path;
43 import java.nio.file.Paths;
44 import java.nio.file.attribute.BasicFileAttributes;
45 import java.util.Arrays;
46 import java.util.Comparator;
47 import java.util.Iterator;
48 import java.util.List;
49 import java.util.Objects;
50 import java.util.Set;
51 import java.util.TreeSet;
52 import java.util.function.BiPredicate;
53 import java.util.stream.CloseableStream;
54 import java.util.stream.Collectors;
55 import org.testng.annotations.AfterClass;
56 import org.testng.annotations.BeforeClass;
57 import org.testng.annotations.Test;
58 import static org.testng.Assert.*;
59
60 @Test(groups = "unit")
61 public class StreamTest {
62 /**
63 * Default test folder
64 * testFolder - empty
65 * - file
66 * - dir - d1
67 * - f1
68 * - lnDir2 (../dir2)
69 * - dir2
70 * - linkDir (./dir)
71 * - linkFile(./file)
72 */
73 static Path testFolder;
121 set.add(testFolder);
122 all = set.toArray(new Path[0]);
123
124 // Follow links
125 if (supportsLinks) {
126 tmp = testFolder.resolve("linkDir");
127 set.add(tmp.resolve("d1"));
128 set.add(tmp.resolve("f1"));
129 tmp = tmp.resolve("lnDir2");
130 set.add(tmp);
131 }
132 all_folowLinks = set.toArray(new Path[0]);
133 }
134
135 @AfterClass
136 void cleanupTestFolder() throws IOException {
137 TestUtil.removeAll(testFolder);
138 }
139
140 public void testBasic() {
141 try (CloseableStream<Path> s = Files.list(testFolder)) {
142 Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
143 assertEquals(actual, level1);
144 } catch (IOException ioe) {
145 fail("Unexpected IOException");
146 }
147
148 try (CloseableStream<Path> s = Files.list(testFolder.resolve("empty"))) {
149 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
150 assertEquals(count, 0, "Expect empty stream.");
151 } catch (IOException ioe) {
152 fail("Unexpected IOException");
153 }
154 }
155
156 public void testWalk() {
157 try (CloseableStream<Path> s = Files.walk(testFolder)) {
158 Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
159 assertEquals(actual, all);
160 } catch (IOException ioe) {
161 fail("Unexpected IOException");
162 }
163 }
164
165 public void testWalkOneLevel() {
166 try (CloseableStream<Path> s = Files.walk(testFolder, 1)) {
167 Object[] actual = s.filter(path -> ! path.equals(testFolder))
168 .sorted(Comparator.naturalOrder())
169 .toArray();
170 assertEquals(actual, level1);
171 } catch (IOException ioe) {
172 fail("Unexpected IOException");
173 }
174 }
175
176 public void testWalkFollowLink() {
177 // If link is not supported, the directory structure won't have link.
178 // We still want to test the behavior with FOLLOW_LINKS option.
179 try (CloseableStream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
180 Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
181 assertEquals(actual, all_folowLinks);
182 } catch (IOException ioe) {
183 fail("Unexpected IOException");
184 }
185 }
186
187 private void validateFileSystemLoopException(Path start, Path... causes) {
188 try (CloseableStream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
189 try {
190 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
191 fail("Should got FileSystemLoopException, but got " + count + "elements.");
192 } catch (UncheckedIOException uioe) {
193 IOException ioe = uioe.getCause();
194 if (ioe instanceof FileSystemLoopException) {
195 FileSystemLoopException fsle = (FileSystemLoopException) ioe;
196 boolean match = false;
197 for (Path cause: causes) {
198 if (fsle.getFile().equals(cause.toString())) {
199 match = true;
200 break;
201 }
202 }
203 assertTrue(match);
204 } else {
205 fail("Unexpected UncheckedIOException cause " + ioe.toString());
206 }
207 }
208 } catch(IOException ex) {
265 private final BiPredicate<Path, BasicFileAttributes> pred;
266 private final Set<Path> visited = new TreeSet<Path>();
267
268 PathBiPredicate(BiPredicate<Path, BasicFileAttributes> pred) {
269 this.pred = Objects.requireNonNull(pred);
270 }
271
272 public boolean test(Path path, BasicFileAttributes attrs) {
273 visited.add(path);
274 return pred.test(path, attrs);
275 }
276
277 public Path[] visited() {
278 return visited.toArray(new Path[0]);
279 }
280 }
281
282 public void testFind() throws IOException {
283 PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
284
285 try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
286 Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
287 assertEquals(pred.visited(), all);
288 assertEquals(result.toArray(new Path[0]), pred.visited());
289 }
290
291 pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
292 try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
293 s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
294 assertEquals(pred.visited(), all);
295 }
296
297 pred = new PathBiPredicate((path, attrs) ->
298 path.getFileName().toString().startsWith("e"));
299 try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
300 s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
301 assertEquals(pred.visited(), all);
302 }
303
304 pred = new PathBiPredicate((path, attrs) ->
305 path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
306 try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
307 s.forEach(path -> fail("Expect empty stream"));
308 assertEquals(pred.visited(), all);
309 }
310 }
311
312 // Test borrowed from BytesAndLines
313 public void testLines() throws IOException {
314 final Charset US_ASCII = Charset.forName("US-ASCII");
315 Path tmpfile = Files.createTempFile("blah", "txt");
316
317 try {
318 // zero lines
319 assertTrue(Files.size(tmpfile) == 0, "File should be empty");
320 try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
321 assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
322 }
323
324 // one line
325 byte[] hi = { (byte)'h', (byte)'i' };
326 Files.write(tmpfile, hi);
327 try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
328 List<String> lines = s.collect(Collectors.toList());
329 assertTrue(lines.size() == 1, "One line expected");
330 assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
331 }
332
333 // two lines using platform's line separator
334 List<String> expected = Arrays.asList("hi", "there");
335 Files.write(tmpfile, expected, US_ASCII);
336 assertTrue(Files.size(tmpfile) > 0, "File is empty");
337 try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
338 List<String> lines = s.collect(Collectors.toList());
339 assertTrue(lines.equals(expected), "Unexpected lines");
340 }
341
342 // MalformedInputException
343 byte[] bad = { (byte)0xff, (byte)0xff };
344 Files.write(tmpfile, bad);
345 try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
346 try {
347 List<String> lines = s.collect(Collectors.toList());
348 throw new RuntimeException("UncheckedIOException expected");
349 } catch (UncheckedIOException ex) {
350 assertTrue(ex.getCause() instanceof MalformedInputException,
351 "MalformedInputException expected");
352 }
353 }
354
355 // NullPointerException
356 try {
357 Files.lines(null, US_ASCII);
358 throw new RuntimeException("NullPointerException expected");
359 } catch (NullPointerException ignore) { }
360 try {
361 Files.lines(tmpfile, null);
362 throw new RuntimeException("NullPointerException expected");
363 } catch (NullPointerException ignore) { }
364
365 } finally {
366 Files.delete(tmpfile);
367 }
368 }
369
370 public void testDirectoryIteratorException() throws IOException {
371 Path dir = testFolder.resolve("dir2");
372 Path trigger = dir.resolve("DirectoryIteratorException");
373 Files.createFile(trigger);
374 FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
375 FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);
376
377 try {
378 fsp.setFaultyMode(false);
379 Path fakeRoot = fs.getRoot();
380 try {
381 try (CloseableStream<Path> s = Files.list(fakeRoot)) {
382 s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
383 }
384 } catch (UncheckedIOException uioe) {
385 fail("Unexpected exception.");
386 }
387
388 fsp.setFaultyMode(true);
389 try {
390 try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {
391 Iterator<Path> itor = ds.iterator();
392 while (itor.hasNext()) {
393 itor.next();
394 }
395 }
396 fail("Shoule throw DirectoryIteratorException");
397 } catch (DirectoryIteratorException die) {
398 }
399
400 try {
401 try (CloseableStream<Path> s = Files.list(fakeRoot)) {
402 s.forEach(path -> fail("should not get here"));
403 }
404 } catch (UncheckedIOException uioe) {
405 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
406 } catch (DirectoryIteratorException die) {
407 fail("Should have been converted into UncheckedIOException.");
408 }
409 } finally {
410 // Cleanup
411 if (fs != null) {
412 fs.close();
413 }
414 Files.delete(trigger);
415 }
416 }
417
418 public void testUncheckedIOException() throws IOException {
419 Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));
420 Files.createFile(triggerFile);
421 Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));
422 Files.createDirectories(triggerDir);
423 Files.createFile(triggerDir.resolve("file"));
424 FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
425 FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
426
427 try {
428 fsp.setFaultyMode(false);
429 Path fakeRoot = fs.getRoot();
430 try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
431 // only one file
432 s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
433 }
434
435 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
436 String[] result = s.map(path -> path.getFileName().toString())
437 .toArray(String[]::new);
438 // ordered as depth-first
439 assertEquals(result, new String[] { "empty", "IOException", "file"});
440 }
441
442 fsp.setFaultyMode(true);
443 try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
444 s.forEach(path -> fail("should have caused exception"));
445 } catch (UncheckedIOException uioe) {
446 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
447 }
448
449 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
450 String[] result = s.map(path -> path.getFileName().toString())
451 .toArray(String[]::new);
452 fail("should not reach here due to IOException");
453 } catch (UncheckedIOException uioe) {
454 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
455 }
456
457 try (CloseableStream<Path> s = Files.walk(
458 fakeRoot.resolve("empty").resolve("IOException")))
459 {
460 String[] result = s.map(path -> path.getFileName().toString())
461 .toArray(String[]::new);
462 fail("should not reach here due to IOException");
463 } catch (IOException ioe) {
464 assertTrue(ioe instanceof FaultyFileSystem.FaultyException);
465 } catch (UncheckedIOException ex) {
466 fail("Top level should be repored as is");
467 }
468 } finally {
469 // Cleanup
470 if (fs != null) {
471 fs.close();
472 }
473 Files.delete(triggerFile);
474 TestUtil.removeAll(triggerDir);
475 }
476 }
477
485 Files.createFile(triggerDir.resolve("fileInSE"));
486 Path sample = Files.createFile(dir2.resolve("file"));
487
488 Path triggerLink = null;
489 Path linkTriggerDir = null;
490 Path linkTriggerFile = null;
491 if (supportsLinks) {
492 Path dir = testFolder.resolve("dir");
493 triggerLink = Files.createSymbolicLink(dir.resolve("SecurityException"), empty);
494 linkTriggerDir = Files.createSymbolicLink(dir.resolve("lnDirSE"), triggerDir);
495 linkTriggerFile = Files.createSymbolicLink(dir.resolve("lnFileSE"), triggerFile);
496 }
497
498 FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
499 FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
500
501 try {
502 fsp.setFaultyMode(false);
503 Path fakeRoot = fs.getRoot();
504 // validate setting
505 try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
506 String[] result = s.map(path -> path.getFileName().toString())
507 .toArray(String[]::new);
508 assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
509 }
510
511 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
512 String[] result = s.map(path -> path.getFileName().toString())
513 .toArray(String[]::new);
514 assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
515 }
516
517 if (supportsLinks) {
518 try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
519 String[] result = s.map(path -> path.getFileName().toString())
520 .toArray(String[]::new);
521 assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
522 }
523 }
524
525 // execute test
526 fsp.setFaultyMode(true);
527 // ignore file cause SecurityException
528 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
529 String[] result = s.map(path -> path.getFileName().toString())
530 .toArray(String[]::new);
531 assertEqualsNoOrder(result, new String[] { "empty", "sample" });
532 }
533 // skip folder cause SecurityException
534 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
535 String[] result = s.map(path -> path.getFileName().toString())
536 .toArray(String[]::new);
537 assertEqualsNoOrder(result, new String[] { "dir2", "file" });
538 }
539
540 if (supportsLinks) {
541 // not following links
542 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
543 String[] result = s.map(path -> path.getFileName().toString())
544 .toArray(String[]::new);
545 assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
546 }
547
548 // following links
549 try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
550 String[] result = s.map(path -> path.getFileName().toString())
551 .toArray(String[]::new);
552 // ?? Should fileInSE show up?
553 // With FaultyFS, it does as no exception thrown for link to "SecurityException" with read on "lnXxxSE"
554 assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "file", "lnDirSE", "lnFileSE", "fileInSE" });
555 }
556 }
557
558 // list instead of walk
559 try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
560 String[] result = s.map(path -> path.getFileName().toString())
561 .toArray(String[]::new);
562 assertEqualsNoOrder(result, new String[] { "sample" });
563 }
564 try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
565 String[] result = s.map(path -> path.getFileName().toString())
566 .toArray(String[]::new);
567 assertEqualsNoOrder(result, new String[] { "file" });
568 }
569
570 // root cause SecurityException should be reported
571 try (CloseableStream<Path> s = Files.walk(
572 fakeRoot.resolve("dir2").resolve("SecurityException")))
573 {
574 String[] result = s.map(path -> path.getFileName().toString())
575 .toArray(String[]::new);
576 fail("should not reach here due to SecurityException");
577 } catch (SecurityException se) {
578 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
579 }
580
581 // Walk a file cause SecurityException, we should get SE
582 try (CloseableStream<Path> s = Files.walk(
583 fakeRoot.resolve("dir").resolve("SecurityException")))
584 {
585 String[] result = s.map(path -> path.getFileName().toString())
586 .toArray(String[]::new);
587 fail("should not reach here due to SecurityException");
588 } catch (SecurityException se) {
589 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
590 }
591
592 // List a file cause SecurityException, we should get SE as cannot read attribute
593 try (CloseableStream<Path> s = Files.list(
594 fakeRoot.resolve("dir2").resolve("SecurityException")))
595 {
596 String[] result = s.map(path -> path.getFileName().toString())
597 .toArray(String[]::new);
598 fail("should not reach here due to SecurityException");
599 } catch (SecurityException se) {
600 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
601 }
602
603 try (CloseableStream<Path> s = Files.list(
604 fakeRoot.resolve("dir").resolve("SecurityException")))
605 {
606 String[] result = s.map(path -> path.getFileName().toString())
607 .toArray(String[]::new);
608 fail("should not reach here due to SecurityException");
609 } catch (SecurityException se) {
610 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
611 }
612 } finally {
613 // Cleanup
614 if (fs != null) {
615 fs.close();
616 }
617 if (supportsLinks) {
618 Files.delete(triggerLink);
619 Files.delete(linkTriggerDir);
620 Files.delete(linkTriggerFile);
621 }
622 Files.delete(triggerFile);
623 Files.delete(sampleFile);
624 Files.delete(sample);
625 TestUtil.removeAll(triggerDir);
626 }
627 }
628
629 public void testConstructException() {
630 try (CloseableStream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
631 s.forEach(l -> fail("File is not even exist!"));
632 } catch (IOException ioe) {
633 assertTrue(ioe instanceof NoSuchFileException);
634 }
635 }
636
637 public void testClosedStream() throws IOException {
638 try (CloseableStream<Path> s = Files.list(testFolder)) {
639 s.close();
640 Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
641 assertTrue(actual.length <= level1.length);
642 }
643
644 try (CloseableStream<Path> s = Files.walk(testFolder)) {
645 s.close();
646 Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
647 fail("Operate on closed stream should throw IllegalStateException");
648 } catch (IllegalStateException ex) {
649 // expected
650 }
651
652 try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
653 (p, attr) -> true)) {
654 s.close();
655 Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
656 fail("Operate on closed stream should throw IllegalStateException");
657 } catch (IllegalStateException ex) {
658 // expected
659 }
660 }
661 }
|
26 * @summary Unit test for java.nio.file.Files
27 * @library ..
28 * @build PassThroughFileSystem FaultyFileSystem
29 * @run testng StreamTest
30 */
31
32 import java.io.IOException;
33 import java.io.UncheckedIOException;
34 import java.nio.charset.Charset;
35 import java.nio.charset.MalformedInputException;
36 import java.nio.file.DirectoryIteratorException;
37 import java.nio.file.DirectoryStream;
38 import java.nio.file.FileSystemLoopException;
39 import java.nio.file.FileVisitOption;
40 import java.nio.file.Files;
41 import java.nio.file.NoSuchFileException;
42 import java.nio.file.Path;
43 import java.nio.file.Paths;
44 import java.nio.file.attribute.BasicFileAttributes;
45 import java.util.Arrays;
46 import java.util.Iterator;
47 import java.util.List;
48 import java.util.Objects;
49 import java.util.Set;
50 import java.util.TreeSet;
51 import java.util.function.BiPredicate;
52 import java.util.stream.Stream;
53 import java.util.stream.Collectors;
54 import org.testng.annotations.AfterClass;
55 import org.testng.annotations.BeforeClass;
56 import org.testng.annotations.Test;
57 import static org.testng.Assert.*;
58
59 @Test(groups = "unit")
60 public class StreamTest {
61 /**
62 * Default test folder
63 * testFolder - empty
64 * - file
65 * - dir - d1
66 * - f1
67 * - lnDir2 (../dir2)
68 * - dir2
69 * - linkDir (./dir)
70 * - linkFile(./file)
71 */
72 static Path testFolder;
120 set.add(testFolder);
121 all = set.toArray(new Path[0]);
122
123 // Follow links
124 if (supportsLinks) {
125 tmp = testFolder.resolve("linkDir");
126 set.add(tmp.resolve("d1"));
127 set.add(tmp.resolve("f1"));
128 tmp = tmp.resolve("lnDir2");
129 set.add(tmp);
130 }
131 all_folowLinks = set.toArray(new Path[0]);
132 }
133
134 @AfterClass
135 void cleanupTestFolder() throws IOException {
136 TestUtil.removeAll(testFolder);
137 }
138
139 public void testBasic() {
140 try (Stream<Path> s = Files.list(testFolder)) {
141 Object[] actual = s.sorted().toArray();
142 assertEquals(actual, level1);
143 } catch (IOException ioe) {
144 fail("Unexpected IOException");
145 }
146
147 try (Stream<Path> s = Files.list(testFolder.resolve("empty"))) {
148 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
149 assertEquals(count, 0, "Expect empty stream.");
150 } catch (IOException ioe) {
151 fail("Unexpected IOException");
152 }
153 }
154
155 public void testWalk() {
156 try (Stream<Path> s = Files.walk(testFolder)) {
157 Object[] actual = s.sorted().toArray();
158 assertEquals(actual, all);
159 } catch (IOException ioe) {
160 fail("Unexpected IOException");
161 }
162 }
163
164 public void testWalkOneLevel() {
165 try (Stream<Path> s = Files.walk(testFolder, 1)) {
166 Object[] actual = s.filter(path -> ! path.equals(testFolder))
167 .sorted()
168 .toArray();
169 assertEquals(actual, level1);
170 } catch (IOException ioe) {
171 fail("Unexpected IOException");
172 }
173 }
174
175 public void testWalkFollowLink() {
176 // If link is not supported, the directory structure won't have link.
177 // We still want to test the behavior with FOLLOW_LINKS option.
178 try (Stream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
179 Object[] actual = s.sorted().toArray();
180 assertEquals(actual, all_folowLinks);
181 } catch (IOException ioe) {
182 fail("Unexpected IOException");
183 }
184 }
185
186 private void validateFileSystemLoopException(Path start, Path... causes) {
187 try (Stream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
188 try {
189 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
190 fail("Should got FileSystemLoopException, but got " + count + "elements.");
191 } catch (UncheckedIOException uioe) {
192 IOException ioe = uioe.getCause();
193 if (ioe instanceof FileSystemLoopException) {
194 FileSystemLoopException fsle = (FileSystemLoopException) ioe;
195 boolean match = false;
196 for (Path cause: causes) {
197 if (fsle.getFile().equals(cause.toString())) {
198 match = true;
199 break;
200 }
201 }
202 assertTrue(match);
203 } else {
204 fail("Unexpected UncheckedIOException cause " + ioe.toString());
205 }
206 }
207 } catch(IOException ex) {
264 private final BiPredicate<Path, BasicFileAttributes> pred;
265 private final Set<Path> visited = new TreeSet<Path>();
266
267 PathBiPredicate(BiPredicate<Path, BasicFileAttributes> pred) {
268 this.pred = Objects.requireNonNull(pred);
269 }
270
271 public boolean test(Path path, BasicFileAttributes attrs) {
272 visited.add(path);
273 return pred.test(path, attrs);
274 }
275
276 public Path[] visited() {
277 return visited.toArray(new Path[0]);
278 }
279 }
280
281 public void testFind() throws IOException {
282 PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
283
284 try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
285 Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
286 assertEquals(pred.visited(), all);
287 assertEquals(result.toArray(new Path[0]), pred.visited());
288 }
289
290 pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
291 try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
292 s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
293 assertEquals(pred.visited(), all);
294 }
295
296 pred = new PathBiPredicate((path, attrs) ->
297 path.getFileName().toString().startsWith("e"));
298 try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
299 s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
300 assertEquals(pred.visited(), all);
301 }
302
303 pred = new PathBiPredicate((path, attrs) ->
304 path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
305 try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
306 s.forEach(path -> fail("Expect empty stream"));
307 assertEquals(pred.visited(), all);
308 }
309 }
310
311 // Test borrowed from BytesAndLines
312 public void testLines() throws IOException {
313 final Charset US_ASCII = Charset.forName("US-ASCII");
314 Path tmpfile = Files.createTempFile("blah", "txt");
315
316 try {
317 // zero lines
318 assertTrue(Files.size(tmpfile) == 0, "File should be empty");
319 try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
320 assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
321 }
322
323 // one line
324 byte[] hi = { (byte)'h', (byte)'i' };
325 Files.write(tmpfile, hi);
326 try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
327 List<String> lines = s.collect(Collectors.toList());
328 assertTrue(lines.size() == 1, "One line expected");
329 assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
330 }
331
332 // two lines using platform's line separator
333 List<String> expected = Arrays.asList("hi", "there");
334 Files.write(tmpfile, expected, US_ASCII);
335 assertTrue(Files.size(tmpfile) > 0, "File is empty");
336 try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
337 List<String> lines = s.collect(Collectors.toList());
338 assertTrue(lines.equals(expected), "Unexpected lines");
339 }
340
341 // MalformedInputException
342 byte[] bad = { (byte)0xff, (byte)0xff };
343 Files.write(tmpfile, bad);
344 try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
345 try {
346 List<String> lines = s.collect(Collectors.toList());
347 throw new RuntimeException("UncheckedIOException expected");
348 } catch (UncheckedIOException ex) {
349 assertTrue(ex.getCause() instanceof MalformedInputException,
350 "MalformedInputException expected");
351 }
352 }
353
354 // NullPointerException
355 try {
356 Files.lines(null, US_ASCII);
357 throw new RuntimeException("NullPointerException expected");
358 } catch (NullPointerException ignore) { }
359 try {
360 Files.lines(tmpfile, null);
361 throw new RuntimeException("NullPointerException expected");
362 } catch (NullPointerException ignore) { }
363
364 } finally {
365 Files.delete(tmpfile);
366 }
367 }
368
369 public void testDirectoryIteratorException() throws IOException {
370 Path dir = testFolder.resolve("dir2");
371 Path trigger = dir.resolve("DirectoryIteratorException");
372 Files.createFile(trigger);
373 FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
374 FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);
375
376 try {
377 fsp.setFaultyMode(false);
378 Path fakeRoot = fs.getRoot();
379 try {
380 try (Stream<Path> s = Files.list(fakeRoot)) {
381 s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
382 }
383 } catch (UncheckedIOException uioe) {
384 fail("Unexpected exception.");
385 }
386
387 fsp.setFaultyMode(true);
388 try {
389 try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {
390 Iterator<Path> itor = ds.iterator();
391 while (itor.hasNext()) {
392 itor.next();
393 }
394 }
395 fail("Shoule throw DirectoryIteratorException");
396 } catch (DirectoryIteratorException die) {
397 }
398
399 try {
400 try (Stream<Path> s = Files.list(fakeRoot)) {
401 s.forEach(path -> fail("should not get here"));
402 }
403 } catch (UncheckedIOException uioe) {
404 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
405 } catch (DirectoryIteratorException die) {
406 fail("Should have been converted into UncheckedIOException.");
407 }
408 } finally {
409 // Cleanup
410 if (fs != null) {
411 fs.close();
412 }
413 Files.delete(trigger);
414 }
415 }
416
417 public void testUncheckedIOException() throws IOException {
418 Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));
419 Files.createFile(triggerFile);
420 Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));
421 Files.createDirectories(triggerDir);
422 Files.createFile(triggerDir.resolve("file"));
423 FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
424 FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
425
426 try {
427 fsp.setFaultyMode(false);
428 Path fakeRoot = fs.getRoot();
429 try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
430 // only one file
431 s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
432 }
433
434 try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
435 String[] result = s.map(path -> path.getFileName().toString())
436 .toArray(String[]::new);
437 // ordered as depth-first
438 assertEquals(result, new String[] { "empty", "IOException", "file"});
439 }
440
441 fsp.setFaultyMode(true);
442 try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
443 s.forEach(path -> fail("should have caused exception"));
444 } catch (UncheckedIOException uioe) {
445 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
446 }
447
448 try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
449 String[] result = s.map(path -> path.getFileName().toString())
450 .toArray(String[]::new);
451 fail("should not reach here due to IOException");
452 } catch (UncheckedIOException uioe) {
453 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
454 }
455
456 try (Stream<Path> s = Files.walk(
457 fakeRoot.resolve("empty").resolve("IOException")))
458 {
459 String[] result = s.map(path -> path.getFileName().toString())
460 .toArray(String[]::new);
461 fail("should not reach here due to IOException");
462 } catch (IOException ioe) {
463 assertTrue(ioe instanceof FaultyFileSystem.FaultyException);
464 } catch (UncheckedIOException ex) {
465 fail("Top level should be repored as is");
466 }
467 } finally {
468 // Cleanup
469 if (fs != null) {
470 fs.close();
471 }
472 Files.delete(triggerFile);
473 TestUtil.removeAll(triggerDir);
474 }
475 }
476
484 Files.createFile(triggerDir.resolve("fileInSE"));
485 Path sample = Files.createFile(dir2.resolve("file"));
486
487 Path triggerLink = null;
488 Path linkTriggerDir = null;
489 Path linkTriggerFile = null;
490 if (supportsLinks) {
491 Path dir = testFolder.resolve("dir");
492 triggerLink = Files.createSymbolicLink(dir.resolve("SecurityException"), empty);
493 linkTriggerDir = Files.createSymbolicLink(dir.resolve("lnDirSE"), triggerDir);
494 linkTriggerFile = Files.createSymbolicLink(dir.resolve("lnFileSE"), triggerFile);
495 }
496
497 FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();
498 FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);
499
500 try {
501 fsp.setFaultyMode(false);
502 Path fakeRoot = fs.getRoot();
503 // validate setting
504 try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
505 String[] result = s.map(path -> path.getFileName().toString())
506 .toArray(String[]::new);
507 assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
508 }
509
510 try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
511 String[] result = s.map(path -> path.getFileName().toString())
512 .toArray(String[]::new);
513 assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
514 }
515
516 if (supportsLinks) {
517 try (Stream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
518 String[] result = s.map(path -> path.getFileName().toString())
519 .toArray(String[]::new);
520 assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
521 }
522 }
523
524 // execute test
525 fsp.setFaultyMode(true);
526 // ignore file cause SecurityException
527 try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
528 String[] result = s.map(path -> path.getFileName().toString())
529 .toArray(String[]::new);
530 assertEqualsNoOrder(result, new String[] { "empty", "sample" });
531 }
532 // skip folder cause SecurityException
533 try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
534 String[] result = s.map(path -> path.getFileName().toString())
535 .toArray(String[]::new);
536 assertEqualsNoOrder(result, new String[] { "dir2", "file" });
537 }
538
539 if (supportsLinks) {
540 // not following links
541 try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
542 String[] result = s.map(path -> path.getFileName().toString())
543 .toArray(String[]::new);
544 assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
545 }
546
547 // following links
548 try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
549 String[] result = s.map(path -> path.getFileName().toString())
550 .toArray(String[]::new);
551 // ?? Should fileInSE show up?
552 // With FaultyFS, it does as no exception thrown for link to "SecurityException" with read on "lnXxxSE"
553 assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "file", "lnDirSE", "lnFileSE", "fileInSE" });
554 }
555 }
556
557 // list instead of walk
558 try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
559 String[] result = s.map(path -> path.getFileName().toString())
560 .toArray(String[]::new);
561 assertEqualsNoOrder(result, new String[] { "sample" });
562 }
563 try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
564 String[] result = s.map(path -> path.getFileName().toString())
565 .toArray(String[]::new);
566 assertEqualsNoOrder(result, new String[] { "file" });
567 }
568
569 // root cause SecurityException should be reported
570 try (Stream<Path> s = Files.walk(
571 fakeRoot.resolve("dir2").resolve("SecurityException")))
572 {
573 String[] result = s.map(path -> path.getFileName().toString())
574 .toArray(String[]::new);
575 fail("should not reach here due to SecurityException");
576 } catch (SecurityException se) {
577 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
578 }
579
580 // Walk a file cause SecurityException, we should get SE
581 try (Stream<Path> s = Files.walk(
582 fakeRoot.resolve("dir").resolve("SecurityException")))
583 {
584 String[] result = s.map(path -> path.getFileName().toString())
585 .toArray(String[]::new);
586 fail("should not reach here due to SecurityException");
587 } catch (SecurityException se) {
588 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
589 }
590
591 // List a file cause SecurityException, we should get SE as cannot read attribute
592 try (Stream<Path> s = Files.list(
593 fakeRoot.resolve("dir2").resolve("SecurityException")))
594 {
595 String[] result = s.map(path -> path.getFileName().toString())
596 .toArray(String[]::new);
597 fail("should not reach here due to SecurityException");
598 } catch (SecurityException se) {
599 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
600 }
601
602 try (Stream<Path> s = Files.list(
603 fakeRoot.resolve("dir").resolve("SecurityException")))
604 {
605 String[] result = s.map(path -> path.getFileName().toString())
606 .toArray(String[]::new);
607 fail("should not reach here due to SecurityException");
608 } catch (SecurityException se) {
609 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
610 }
611 } finally {
612 // Cleanup
613 if (fs != null) {
614 fs.close();
615 }
616 if (supportsLinks) {
617 Files.delete(triggerLink);
618 Files.delete(linkTriggerDir);
619 Files.delete(linkTriggerFile);
620 }
621 Files.delete(triggerFile);
622 Files.delete(sampleFile);
623 Files.delete(sample);
624 TestUtil.removeAll(triggerDir);
625 }
626 }
627
628 public void testConstructException() {
629 try (Stream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
630 s.forEach(l -> fail("File is not even exist!"));
631 } catch (IOException ioe) {
632 assertTrue(ioe instanceof NoSuchFileException);
633 }
634 }
635
636 public void testClosedStream() throws IOException {
637 try (Stream<Path> s = Files.list(testFolder)) {
638 s.close();
639 Object[] actual = s.sorted().toArray();
640 fail("Operate on closed stream should throw IllegalStateException");
641 } catch (IllegalStateException ex) {
642 // expected
643 }
644
645 try (Stream<Path> s = Files.walk(testFolder)) {
646 s.close();
647 Object[] actual = s.sorted().toArray();
648 fail("Operate on closed stream should throw IllegalStateException");
649 } catch (IllegalStateException ex) {
650 // expected
651 }
652
653 try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
654 (p, attr) -> true)) {
655 s.close();
656 Object[] actual = s.sorted().toArray();
657 fail("Operate on closed stream should throw IllegalStateException");
658 } catch (IllegalStateException ex) {
659 // expected
660 }
661 }
662 }
|