Path: blob/master/test/jdk/java/nio/file/Files/StreamTest.java
41153 views
/*1* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @bug 8006884 8019526 813253925* @library ..26* @build PassThroughFileSystem FaultyFileSystem27* @run testng StreamTest28* @summary Unit test for java.nio.file.Files methods that return a Stream29*/3031import java.io.IOException;32import java.io.UncheckedIOException;33import java.nio.charset.Charset;34import java.nio.charset.MalformedInputException;35import java.nio.file.DirectoryIteratorException;36import java.nio.file.DirectoryStream;37import java.nio.file.FileSystemLoopException;38import java.nio.file.FileVisitOption;39import java.nio.file.Files;40import java.nio.file.NoSuchFileException;41import java.nio.file.Path;42import java.nio.file.Paths;43import java.nio.file.attribute.BasicFileAttributes;44import java.util.Arrays;45import java.util.Collections;46import java.util.Iterator;47import java.util.List;48import java.util.Objects;49import java.util.Set;50import java.util.TreeSet;51import java.util.concurrent.Callable;52import java.util.function.BiPredicate;53import java.util.stream.Stream;54import java.util.stream.Collectors;55import org.testng.annotations.AfterClass;56import org.testng.annotations.BeforeClass;57import org.testng.annotations.Test;58import static org.testng.Assert.*;5960@Test(groups = "unit")61public class StreamTest {62/**63* Default test folder64* testFolder - empty65* - file66* - dir - d167* - f168* - lnDir2 (../dir2)69* - dir270* - linkDir (./dir)71* - linkFile(./file)72*/73static Path testFolder;74static boolean supportsLinks;75static Path[] level1;76static Path[] all;77static Path[] all_folowLinks;7879@BeforeClass80void setupTestFolder() throws IOException {81testFolder = TestUtil.createTemporaryDirectory();82supportsLinks = TestUtil.supportsLinks(testFolder);83TreeSet<Path> set = new TreeSet<>();8485// Level 186Path empty = testFolder.resolve("empty");87Path file = testFolder.resolve("file");88Path dir = testFolder.resolve("dir");89Path dir2 = testFolder.resolve("dir2");90Files.createDirectory(empty);91Files.createFile(file);92Files.createDirectory(dir);93Files.createDirectory(dir2);94set.add(empty);95set.add(file);96set.add(dir);97set.add(dir2);98if (supportsLinks) {99Path tmp = testFolder.resolve("linkDir");100Files.createSymbolicLink(tmp, dir);101set.add(tmp);102tmp = testFolder.resolve("linkFile");103Files.createSymbolicLink(tmp, file);104set.add(tmp);105}106level1 = set.toArray(new Path[0]);107108// Level 2109Path tmp = dir.resolve("d1");110Files.createDirectory(tmp);111set.add(tmp);112tmp = dir.resolve("f1");113Files.createFile(tmp);114set.add(tmp);115if (supportsLinks) {116tmp = dir.resolve("lnDir2");117Files.createSymbolicLink(tmp, dir2);118set.add(tmp);119}120// walk include starting folder121set.add(testFolder);122all = set.toArray(new Path[0]);123124// Follow links125if (supportsLinks) {126tmp = testFolder.resolve("linkDir");127set.add(tmp.resolve("d1"));128set.add(tmp.resolve("f1"));129tmp = tmp.resolve("lnDir2");130set.add(tmp);131}132all_folowLinks = set.toArray(new Path[0]);133}134135@AfterClass136void cleanupTestFolder() throws IOException {137TestUtil.removeAll(testFolder);138}139140public void testBasic() {141try (Stream<Path> s = Files.list(testFolder)) {142Object[] actual = s.sorted().toArray();143assertEquals(actual, level1);144} catch (IOException ioe) {145fail("Unexpected IOException");146}147148try (Stream<Path> s = Files.list(testFolder.resolve("empty"))) {149int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);150assertEquals(count, 0, "Expect empty stream.");151} catch (IOException ioe) {152fail("Unexpected IOException");153}154}155156public void testWalk() {157try (Stream<Path> s = Files.walk(testFolder)) {158Object[] actual = s.sorted().toArray();159assertEquals(actual, all);160} catch (IOException ioe) {161fail("Unexpected IOException");162}163}164165public void testWalkOneLevel() {166try (Stream<Path> s = Files.walk(testFolder, 1)) {167Object[] actual = s.filter(path -> ! path.equals(testFolder))168.sorted()169.toArray();170assertEquals(actual, level1);171} catch (IOException ioe) {172fail("Unexpected IOException");173}174}175176public 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.179try (Stream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {180Object[] actual = s.sorted().toArray();181assertEquals(actual, all_folowLinks);182} catch (IOException ioe) {183fail("Unexpected IOException");184}185}186187private void validateFileSystemLoopException(Path start, Path... causes) {188try (Stream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {189try {190int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);191fail("Should got FileSystemLoopException, but got " + count + "elements.");192} catch (UncheckedIOException uioe) {193IOException ioe = uioe.getCause();194if (ioe instanceof FileSystemLoopException) {195FileSystemLoopException fsle = (FileSystemLoopException) ioe;196boolean match = false;197for (Path cause: causes) {198if (fsle.getFile().equals(cause.toString())) {199match = true;200break;201}202}203assertTrue(match);204} else {205fail("Unexpected UncheckedIOException cause " + ioe.toString());206}207}208} catch(IOException ex) {209fail("Unexpected IOException " + ex);210}211}212213public void testWalkFollowLinkLoop() {214if (!supportsLinks) {215return;216}217218// Loops.219try {220Path dir = testFolder.resolve("dir");221Path linkdir = testFolder.resolve("linkDir");222Path d1 = dir.resolve("d1");223Path cause = d1.resolve("lnSelf");224Files.createSymbolicLink(cause, d1);225226// loop in descendant.227validateFileSystemLoopException(dir, cause);228// loop in self229validateFileSystemLoopException(d1, cause);230// start from other place via link231validateFileSystemLoopException(linkdir,232linkdir.resolve(Paths.get("d1", "lnSelf")));233Files.delete(cause);234235// loop to parent.236cause = d1.resolve("lnParent");237Files.createSymbolicLink(cause, dir);238239// loop should be detected at test/dir/d1/lnParent/d1240validateFileSystemLoopException(d1, cause.resolve("d1"));241// loop should be detected at link242validateFileSystemLoopException(dir, cause);243// loop should be detected at test/linkdir/d1/lnParent244// which is test/dir we have visited via test/linkdir245validateFileSystemLoopException(linkdir,246linkdir.resolve(Paths.get("d1", "lnParent")));247Files.delete(cause);248249// cross loop250Path dir2 = testFolder.resolve("dir2");251cause = dir2.resolve("lnDir");252Files.createSymbolicLink(cause, dir);253validateFileSystemLoopException(dir,254dir.resolve(Paths.get("lnDir2", "lnDir")));255validateFileSystemLoopException(dir2,256dir2.resolve(Paths.get("lnDir", "lnDir2")));257validateFileSystemLoopException(linkdir,258linkdir.resolve(Paths.get("lnDir2", "lnDir")));259} catch(IOException ioe) {260fail("Unexpected IOException " + ioe);261}262}263264private static class PathBiPredicate implements BiPredicate<Path, BasicFileAttributes> {265private final BiPredicate<Path, BasicFileAttributes> pred;266private final Set<Path> visited = new TreeSet<Path>();267268PathBiPredicate(BiPredicate<Path, BasicFileAttributes> pred) {269this.pred = Objects.requireNonNull(pred);270}271272public boolean test(Path path, BasicFileAttributes attrs) {273visited.add(path);274return pred.test(path, attrs);275}276277public Path[] visited() {278return visited.toArray(new Path[0]);279}280}281282public void testFind() throws IOException {283PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);284285try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {286Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));287assertEquals(pred.visited(), all);288assertEquals(result.toArray(new Path[0]), pred.visited());289}290291pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());292try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {293s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));294assertEquals(pred.visited(), all);295}296297pred = new PathBiPredicate((path, attrs) ->298path.getFileName().toString().startsWith("e"));299try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {300s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));301assertEquals(pred.visited(), all);302}303304pred = new PathBiPredicate((path, attrs) ->305path.getFileName().toString().startsWith("l") && attrs.isRegularFile());306try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {307s.forEach(path -> fail("Expect empty stream"));308assertEquals(pred.visited(), all);309}310}311312// Test borrowed from BytesAndLines313public void testLines() throws IOException {314final Charset US_ASCII = Charset.forName("US-ASCII");315Path tmpfile = Files.createTempFile("blah", "txt");316317try {318// zero lines319assertTrue(Files.size(tmpfile) == 0, "File should be empty");320try (Stream<String> s = Files.lines(tmpfile)) {321checkLines(s, Collections.emptyList());322}323try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {324checkLines(s, Collections.emptyList());325}326327// one line328List<String> oneLine = Arrays.asList("hi");329Files.write(tmpfile, oneLine, US_ASCII);330try (Stream<String> s = Files.lines(tmpfile)) {331checkLines(s, oneLine);332}333try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {334checkLines(s, oneLine);335}336337// two lines using platform's line separator338List<String> twoLines = Arrays.asList("hi", "there");339Files.write(tmpfile, twoLines, US_ASCII);340try (Stream<String> s = Files.lines(tmpfile)) {341checkLines(s, twoLines);342}343try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {344checkLines(s, twoLines);345}346347// MalformedInputException348byte[] bad = { (byte)0xff, (byte)0xff };349Files.write(tmpfile, bad);350try (Stream<String> s = Files.lines(tmpfile)) {351checkMalformedInputException(s);352}353try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {354checkMalformedInputException(s);355}356357// NullPointerException358checkNullPointerException(() -> Files.lines(null));359checkNullPointerException(() -> Files.lines(null, US_ASCII));360checkNullPointerException(() -> Files.lines(tmpfile, null));361362} finally {363Files.delete(tmpfile);364}365}366367private void checkLines(Stream<String> s, List<String> expected) {368List<String> lines = s.collect(Collectors.toList());369assertTrue(lines.size() == expected.size(), "Unexpected number of lines");370assertTrue(lines.equals(expected), "Unexpected content");371}372373private void checkMalformedInputException(Stream<String> s) {374try {375List<String> lines = s.collect(Collectors.toList());376fail("UncheckedIOException expected");377} catch (UncheckedIOException ex) {378IOException cause = ex.getCause();379assertTrue(cause instanceof MalformedInputException,380"MalformedInputException expected");381}382}383384private void checkNullPointerException(Callable<?> c) {385try {386c.call();387fail("NullPointerException expected");388} catch (NullPointerException ignore) {389} catch (Exception e) {390fail(e + " not expected");391}392}393394public void testDirectoryIteratorException() throws IOException {395Path dir = testFolder.resolve("dir2");396Path trigger = dir.resolve("DirectoryIteratorException");397Files.createFile(trigger);398FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();399FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(dir, null);400401try {402fsp.setFaultyMode(false);403Path fakeRoot = fs.getRoot();404try {405try (Stream<Path> s = Files.list(fakeRoot)) {406s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));407}408} catch (UncheckedIOException uioe) {409fail("Unexpected exception.");410}411412fsp.setFaultyMode(true);413try {414try (DirectoryStream<Path> ds = Files.newDirectoryStream(fakeRoot)) {415Iterator<Path> itor = ds.iterator();416while (itor.hasNext()) {417itor.next();418}419}420fail("Shoule throw DirectoryIteratorException");421} catch (DirectoryIteratorException die) {422}423424try {425try (Stream<Path> s = Files.list(fakeRoot)) {426s.forEach(path -> fail("should not get here"));427}428} catch (UncheckedIOException uioe) {429assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);430} catch (DirectoryIteratorException die) {431fail("Should have been converted into UncheckedIOException.");432}433} finally {434// Cleanup435if (fs != null) {436fs.close();437}438Files.delete(trigger);439}440}441442public void testUncheckedIOException() throws IOException {443Path triggerFile = testFolder.resolve(Paths.get("dir2", "IOException"));444Files.createFile(triggerFile);445Path triggerDir = testFolder.resolve(Paths.get("empty", "IOException"));446Files.createDirectories(triggerDir);447Files.createFile(triggerDir.resolve("file"));448FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();449FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);450451try {452fsp.setFaultyMode(false);453Path fakeRoot = fs.getRoot();454try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {455// only one file456s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));457}458459try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {460String[] result = s.map(path -> path.getFileName().toString())461.toArray(String[]::new);462// ordered as depth-first463assertEquals(result, new String[] { "empty", "IOException", "file"});464}465466fsp.setFaultyMode(true);467try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {468s.forEach(path -> fail("should have caused exception"));469} catch (UncheckedIOException uioe) {470assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);471}472473try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {474String[] result = s.map(path -> path.getFileName().toString())475.toArray(String[]::new);476fail("should not reach here due to IOException");477} catch (UncheckedIOException uioe) {478assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);479}480481try (Stream<Path> s = Files.walk(482fakeRoot.resolve("empty").resolve("IOException")))483{484String[] result = s.map(path -> path.getFileName().toString())485.toArray(String[]::new);486fail("should not reach here due to IOException");487} catch (IOException ioe) {488assertTrue(ioe instanceof FaultyFileSystem.FaultyException);489} catch (UncheckedIOException ex) {490fail("Top level should be repored as is");491}492} finally {493// Cleanup494if (fs != null) {495fs.close();496}497Files.delete(triggerFile);498TestUtil.removeAll(triggerDir);499}500}501502public void testSecurityException() throws IOException {503Path empty = testFolder.resolve("empty");504Path triggerFile = Files.createFile(empty.resolve("SecurityException"));505Path sampleFile = Files.createDirectories(empty.resolve("sample"));506507Path dir2 = testFolder.resolve("dir2");508Path triggerDir = Files.createDirectories(dir2.resolve("SecurityException"));509Files.createFile(triggerDir.resolve("fileInSE"));510Path sample = Files.createFile(dir2.resolve("file"));511512Path triggerLink = null;513Path linkTriggerDir = null;514Path linkTriggerFile = null;515if (supportsLinks) {516Path dir = testFolder.resolve("dir");517triggerLink = Files.createSymbolicLink(dir.resolve("SecurityException"), empty);518linkTriggerDir = Files.createSymbolicLink(dir.resolve("lnDirSE"), triggerDir);519linkTriggerFile = Files.createSymbolicLink(dir.resolve("lnFileSE"), triggerFile);520}521522FaultyFileSystem.FaultyFSProvider fsp = FaultyFileSystem.FaultyFSProvider.getInstance();523FaultyFileSystem fs = (FaultyFileSystem) fsp.newFileSystem(testFolder, null);524525try {526fsp.setFaultyMode(false);527Path fakeRoot = fs.getRoot();528// validate setting529try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {530String[] result = s.map(path -> path.getFileName().toString())531.toArray(String[]::new);532assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });533}534535try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {536String[] result = s.map(path -> path.getFileName().toString())537.toArray(String[]::new);538assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });539}540541if (supportsLinks) {542try (Stream<Path> s = Files.list(fakeRoot.resolve("dir"))) {543String[] result = s.map(path -> path.getFileName().toString())544.toArray(String[]::new);545assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });546}547}548549// execute test550fsp.setFaultyMode(true);551// ignore file cause SecurityException552try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {553String[] result = s.map(path -> path.getFileName().toString())554.toArray(String[]::new);555assertEqualsNoOrder(result, new String[] { "empty", "sample" });556}557// skip folder cause SecurityException558try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {559String[] result = s.map(path -> path.getFileName().toString())560.toArray(String[]::new);561assertEqualsNoOrder(result, new String[] { "dir2", "file" });562}563564if (supportsLinks) {565// not following links566try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {567String[] result = s.map(path -> path.getFileName().toString())568.toArray(String[]::new);569assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });570}571572// following links573try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {574String[] 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"578assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "file", "lnDirSE", "lnFileSE", "fileInSE" });579}580}581582// list instead of walk583try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {584String[] result = s.map(path -> path.getFileName().toString())585.toArray(String[]::new);586assertEqualsNoOrder(result, new String[] { "sample" });587}588try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {589String[] result = s.map(path -> path.getFileName().toString())590.toArray(String[]::new);591assertEqualsNoOrder(result, new String[] { "file" });592}593594// root cause SecurityException should be reported595try (Stream<Path> s = Files.walk(596fakeRoot.resolve("dir2").resolve("SecurityException")))597{598String[] result = s.map(path -> path.getFileName().toString())599.toArray(String[]::new);600fail("should not reach here due to SecurityException");601} catch (SecurityException se) {602assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);603}604605// Walk a file cause SecurityException, we should get SE606try (Stream<Path> s = Files.walk(607fakeRoot.resolve("dir").resolve("SecurityException")))608{609String[] result = s.map(path -> path.getFileName().toString())610.toArray(String[]::new);611fail("should not reach here due to SecurityException");612} catch (SecurityException se) {613assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);614}615616// List a file cause SecurityException, we should get SE as cannot read attribute617try (Stream<Path> s = Files.list(618fakeRoot.resolve("dir2").resolve("SecurityException")))619{620String[] result = s.map(path -> path.getFileName().toString())621.toArray(String[]::new);622fail("should not reach here due to SecurityException");623} catch (SecurityException se) {624assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);625}626627try (Stream<Path> s = Files.list(628fakeRoot.resolve("dir").resolve("SecurityException")))629{630String[] result = s.map(path -> path.getFileName().toString())631.toArray(String[]::new);632fail("should not reach here due to SecurityException");633} catch (SecurityException se) {634assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);635}636} finally {637// Cleanup638if (fs != null) {639fs.close();640}641if (supportsLinks) {642Files.delete(triggerLink);643Files.delete(linkTriggerDir);644Files.delete(linkTriggerFile);645}646Files.delete(triggerFile);647Files.delete(sampleFile);648Files.delete(sample);649TestUtil.removeAll(triggerDir);650}651}652653public void testConstructException() {654try (Stream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {655s.forEach(l -> fail("File is not even exist!"));656} catch (IOException ioe) {657assertTrue(ioe instanceof NoSuchFileException);658}659}660661public void testClosedStream() throws IOException {662try (Stream<Path> s = Files.list(testFolder)) {663s.close();664Object[] actual = s.sorted().toArray();665fail("Operate on closed stream should throw IllegalStateException");666} catch (IllegalStateException ex) {667// expected668}669670try (Stream<Path> s = Files.walk(testFolder)) {671s.close();672Object[] actual = s.sorted().toArray();673fail("Operate on closed stream should throw IllegalStateException");674} catch (IllegalStateException ex) {675// expected676}677678try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,679(p, attr) -> true)) {680s.close();681Object[] actual = s.sorted().toArray();682fail("Operate on closed stream should throw IllegalStateException");683} catch (IllegalStateException ex) {684// expected685}686}687688public void testProcFile() throws IOException {689if (System.getProperty("os.name").equals("Linux")) {690Path path = Paths.get("/proc/cpuinfo");691if (Files.exists(path)) {692String NEW_LINE = System.getProperty("line.separator");693String s =694Files.lines(path).collect(Collectors.joining(NEW_LINE));695if (s.length() == 0) {696fail("Files.lines(\"" + path + "\") returns no data");697}698}699}700}701}702703704