Path: blob/master/test/jdk/java/io/pathNames/General.java
41149 views
/*1* Copyright (c) 1998, 2017, 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/*24@summary Common definitions for general exhaustive pathname tests25@author Mark Reinhold26*/2728import java.io.*;29import java.util.*;30import java.nio.file.*;313233public class General {3435public static boolean debug = false;3637private static boolean win32 = (File.separatorChar == '\\');3839private static int gensymCounter = 0;4041protected static final String userDir = System.getProperty("user.dir");42protected static final String workSubDir = "tmp";4344protected static String baseDir = null;45protected static String relative = null;4647/* Generate a filename unique to this run */48private static String gensym() {49return "x." + ++gensymCounter;50}5152/**53* Create files and folders in the test working directory.54* The purpose is to make sure the test will not go out of55* its user dir when walking the file tree.56*57* @param depth The number of directory levels to be created under58* the user directory. It should be the maximum value59* of the depths passed to checkNames method (including60* direct or indirect calling) in a whole test.61*/62protected static void initTestData(int depth) throws IOException {63File parent = new File(userDir + File.separator + workSubDir);64if (!parent.mkdir()) {65throw new IOException("Fail to create directory: " + parent);66}67for (int i = 0; i < depth; i++) {68File tmp = new File(parent, gensym());69tmp.createNewFile();70tmp = new File(parent, gensym());71if (tmp.mkdir())72parent = tmp;73else74throw new IOException("Fail to create directory, " + tmp);75}76baseDir = parent.getAbsolutePath();77relative = baseDir.substring(userDir.length() + 1);78}7980/**81* Find a file in the given subdirectory, or descend into further82* subdirectories, if any, if no file is found here. Return null if no83* file can be found anywhere beneath the given subdirectory.84* @param dir Directory at which we started85* @param subdir Subdirectory that we're exploring86* @param dl Listing of subdirectory87*/88private static String findSomeFile(String dir, String subdir, String[] dl) {89for (int i = 0; i < dl.length; i++) {90File f = new File(subdir, dl[i]);91File df = new File(dir, f.getPath());92if (Files.isRegularFile(df.toPath(), LinkOption.NOFOLLOW_LINKS)) {93return f.getPath();94}95}96for (int i = 0; i < dl.length; i++) {97File f = (subdir.length() == 0) ? new File(dl[i])98: new File(subdir, dl[i]);99File df = new File(dir, f.getPath());100if (Files.isDirectory(df.toPath(), LinkOption.NOFOLLOW_LINKS)) {101String[] dl2 = df.list();102if (dl2 != null) {103String ff = findSomeFile(dir, f.getPath(), dl2);104if (ff != null) return ff;105}106}107}108return null;109}110111112/**113* Construct a string that names a file in the given directory. If create114* is true, then create a file if none is found, and throw an exception if115* that is not possible; otherwise, return null if no file can be found.116*/117private static String findSomeFile(String dir, boolean create) {118File d = new File(dir);119String[] dl = d.list();120if (dl == null) {121throw new RuntimeException("Can't list " + dir);122}123for (int i = 0; i < dl.length; i++) {124File f = new File(dir, dl[i]);125if (Files.isRegularFile(f.toPath(), LinkOption.NOFOLLOW_LINKS)) {126return dl[i];127}128}129String f = findSomeFile(dir, "", dl);130if (f != null) {131return f;132}133if (create) {134File nf = new File(d, gensym());135OutputStream os;136try {137os = new FileOutputStream(nf);138os.close();139} catch (IOException x) {140throw new RuntimeException("Can't create a file in " + dir);141}142return nf.getName();143}144return null;145}146147148/**149* Construct a string that names a subdirectory of the given directory.150* If create is true, then create a subdirectory if none is found, and151* throw an exception if that is not possible; otherwise, return null if152* no subdirectory can be found.153*/154private static String findSomeDir(String dir, boolean create) {155File d = new File(dir);156String[] dl = d.list();157if (dl == null) {158throw new RuntimeException("Can't list " + dir);159}160for (int i = 0; i < dl.length; i++) {161File f = new File(d, dl[i]);162if (Files.isDirectory(f.toPath(), LinkOption.NOFOLLOW_LINKS)) {163String[] dl2 = f.list();164if (dl2 == null || dl2.length >= 250) {165/* Heuristic to avoid scanning huge directories */166continue;167}168return dl[i];169}170}171if (create) {172File sd = new File(d, gensym());173if (sd.mkdir()) return sd.getName();174}175return null;176}177178179/** Construct a string that does not name a file in the given directory */180private static String findNon(String dir) {181File d = new File(dir);182String[] x = new String[] { "foo", "bar", "baz" };183for (int i = 0; i < x.length; i++) {184File f = new File(d, x[i]);185if (!f.exists()) {186return x[i];187}188}189for (int i = 0; i < 1024; i++) {190String n = "xx" + Integer.toString(i);191File f = new File(d, n);192if (!f.exists()) {193return n;194}195}196throw new RuntimeException("Can't find a non-existent file in " + dir);197}198199200/** Ensure that the named file does not exist */201public static void ensureNon(String fn) {202if ((new File(fn)).exists()) {203throw new RuntimeException("Test path " + fn + " exists");204}205}206207208/** Tell whether the given character is a "slash" on this platform */209private static boolean isSlash(char x) {210if (x == File.separatorChar) return true;211if (win32 && (x == '/')) return true;212return false;213}214215216/**217* Trim trailing slashes from the given string, but leave singleton slashes218* alone (they denote root directories)219*/220private static String trimTrailingSlashes(String s) {221int n = s.length();222if (n == 0) return s;223n--;224while ((n > 0) && isSlash(s.charAt(n))) {225if ((n >= 1) && s.charAt(n - 1) == ':') break;226n--;227}228return s.substring(0, n + 1);229}230231232/** Concatenate two paths, trimming slashes as needed */233private static String pathConcat(String a, String b) {234if (a.length() == 0) return b;235if (b.length() == 0) return a;236if (isSlash(a.charAt(a.length() - 1))237|| isSlash(b.charAt(0))238|| (win32 && (a.charAt(a.length() - 1) == ':'))) {239return a + b;240} else {241return a + File.separatorChar + b;242}243}244245246247/** Hash table of input pathnames, used to detect duplicates */248private static Hashtable<String, String> checked = new Hashtable<>();249250/**251* Check the given pathname. Its canonical pathname should be the given252* answer. If the path names a file that exists and is readable, then253* FileInputStream and RandomAccessFile should both be able to open it.254*/255public static void check(String answer, String path) throws IOException {256String ans = trimTrailingSlashes(answer);257if (path.length() == 0) return;258if (checked.get(path) != null) {259System.err.println("DUP " + path);260return;261}262checked.put(path, path);263264String cpath;265try {266File f = new File(path);267cpath = f.getCanonicalPath();268if (f.exists() && f.isFile() && f.canRead()) {269InputStream in = new FileInputStream(path);270in.close();271RandomAccessFile raf = new RandomAccessFile(path, "r");272raf.close();273}274} catch (IOException x) {275System.err.println(ans + " <-- " + path + " ==> " + x);276if (debug) return;277else throw x;278}279if (cpath.equals(ans)) {280System.err.println(ans + " <== " + path);281} else {282System.err.println(ans + " <-- " + path + " ==> " + cpath + " MISMATCH");283if (!debug) {284throw new RuntimeException("Mismatch: " + path + " ==> " + cpath +285", should be " + ans);286}287}288}289290291292/*293* The following three mutually-recursive methods generate and check a tree294* of filenames of arbitrary depth. Each method has (at least) these295* arguments:296*297* int depth Remaining tree depth298* boolean create Controls whether test files and directories299* will be created as needed300* String ans Expected answer for the check method (above)301* String ask Input pathname to be passed to the check method302*/303304305/** Check a single slash case, plus its children */306private static void checkSlash(int depth, boolean create,307String ans, String ask, String slash)308throws Exception309{310check(ans, ask + slash);311checkNames(depth, create,312ans.endsWith(File.separator) ? ans : ans + File.separator,313ask + slash);314}315316317/** Check slash cases for the given ask string */318public static void checkSlashes(int depth, boolean create,319String ans, String ask)320throws Exception321{322check(ans, ask);323if (depth == 0) return;324325checkSlash(depth, create, ans, ask, "/");326checkSlash(depth, create, ans, ask, "//");327checkSlash(depth, create, ans, ask, "///");328if (win32) {329checkSlash(depth, create, ans, ask, "\\");330checkSlash(depth, create, ans, ask, "\\\\");331checkSlash(depth, create, ans, ask, "\\/");332checkSlash(depth, create, ans, ask, "/\\");333checkSlash(depth, create, ans, ask, "\\\\\\");334}335}336337338/** Check name cases for the given ask string */339public static void checkNames(int depth, boolean create,340String ans, String ask)341throws Exception342{343int d = depth - 1;344File f = new File(ans);345String n;346347/* Normal name */348if (f.exists()) {349if (Files.isDirectory(f.toPath(), LinkOption.NOFOLLOW_LINKS) && f.list() != null) {350if ((n = findSomeFile(ans, create)) != null)351checkSlashes(d, create, ans + n, ask + n);352if ((n = findSomeDir(ans, create)) != null)353checkSlashes(d, create, ans + n, ask + n);354}355n = findNon(ans);356checkSlashes(d, create, ans + n, ask + n);357} else {358n = "foo" + depth;359checkSlashes(d, create, ans + n, ask + n);360}361362/* "." */363checkSlashes(d, create, trimTrailingSlashes(ans), ask + ".");364365/* ".." */366if ((n = f.getParent()) != null) {367String n2;368if (win32369&& ((n2 = f.getParentFile().getParent()) != null)370&& n2.equals("\\\\")) {371/* Win32 resolves \\foo\bar\.. to \\foo\bar */372checkSlashes(d, create, ans, ask + "..");373} else {374checkSlashes(d, create, n, ask + "..");375}376}377else {378if (win32)379checkSlashes(d, create, ans, ask + "..");380else {381// Fix for 4237875. We must ensure that we are sufficiently382// deep in the path hierarchy to test parents this high up383File thisPath = new File(ask);384File nextPath = new File(ask + "..");385if (!thisPath.getCanonicalPath().equals(nextPath.getCanonicalPath()))386checkSlashes(d, create, ans + "..", ask + "..");387}388}389}390}391392393