/* * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 4313887 6907737 * @summary Tests that walkFileTree is consistent with the native find program * @requires (os.family != "windows") * @library /test/lib * @build jdk.test.lib.Utils * jdk.test.lib.Asserts * jdk.test.lib.JDKToolFinder * jdk.test.lib.JDKToolLauncher * jdk.test.lib.Platform * jdk.test.lib.process.* * CreateFileTree * @run testng/othervm -Djava.io.tmpdir=. FindTest */ import java.io.IOException; import java.nio.file.FileSystemLoopException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import java.util.stream.Collectors; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; public class FindTest { private static final Random rand = new Random(); private static final boolean isAIX = System.getProperty("os.name").equals("AIX"); private static Path top; private static String TOP; @BeforeClass public static void createFileTree() throws Exception { top = CreateFileTree.create(); TOP = top.toAbsolutePath().toString(); } @Test public void printTreeTest() throws Throwable { // print the file tree and compare output with find(1) assertOutputEquals(printFileTree(top), runFind("find", TOP)); } @Test public void printTreeFollowLinkTest() throws Throwable { // print the file tree, following links, and compare output with find(1). // On AIX "find -follow" may core dump on recursive links without '-L' // see: http://www-01.ibm.com/support/docview.wss?uid=isg1IV28143 String[] cmds = isAIX ? new String[]{"find", "-L", TOP, "-follow"} : new String[]{"find", TOP, "-follow"}; OutputAnalyzer expected = runFind(cmds); // Some versions of find(1) output cycles (sym links to ancestor // directories), other versions do not. For that reason we run // PrintFileTree with the -printCycles option when the output without // this option differs to find(1). try { assertOutputEquals(printFileTree(top, "-follow"), expected); } catch (AssertionError x) { assertOutputEquals(printFileTree(top, "-follow", "-printCycles"), expected); } } private void assertOutputEquals(List actual, OutputAnalyzer expected) throws IOException { List expectedList = Arrays.asList(expected.getStdout() .split(System.lineSeparator())); assertEquals(actual.size(), expectedList.size()); assertTrue(actual.removeAll(expectedList)); } private OutputAnalyzer runFind(String... cmds) throws Throwable { return ProcessTools.executeCommand(cmds); } /** * Invokes Files.walkFileTree to traverse a file tree and prints * each of the directories and files. The -follow option causes symbolic * links to be followed and the -printCycles option will print links * where the target of the link is an ancestor directory. */ private static List printFileTree(Path dir, String... opts) throws Exception { List fileTreeList = new ArrayList<>(); List optsList = Arrays.asList(opts); boolean followLinks = optsList.contains("-follow"); boolean reportCycles = optsList.contains("-printCycles"); Set options = new HashSet<>(); if (followLinks) options.add(FileVisitOption.FOLLOW_LINKS); Files.walkFileTree(dir, options, Integer.MAX_VALUE, new FileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { fileTreeList.add(dir); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { fileTreeList.add(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (exc != null) throw exc; return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (followLinks && (exc instanceof FileSystemLoopException)) { if (reportCycles) fileTreeList.add(file); return FileVisitResult.CONTINUE; } else { throw exc; } } }); return fileTreeList.stream() .map(f -> f.toAbsolutePath().toString()) .collect(Collectors.toCollection(ArrayList::new)); } }