/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package libcore.java.io; import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.io.IOException; import java.util.UUID; import libcore.io.Libcore; public class FileTest extends junit.framework.TestCase { static { System.loadLibrary("javacoretests"); } private static File createTemporaryDirectory() throws Exception { String base = System.getProperty("java.io.tmpdir"); File directory = new File(base, UUID.randomUUID().toString()); assertTrue(directory.mkdirs()); return directory; } private static String longString(int n) { StringBuilder result = new StringBuilder(); for (int i = 0; i < n; ++i) { result.append('x'); } return result.toString(); } private static File createDeepStructure(File base) throws Exception { // ext has a limit of around 256 characters for each path entry. // 128 characters should be safe for everything but FAT. String longString = longString(128); // Keep creating subdirectories until the path length is greater than 1KiB. // Ubuntu 8.04's kernel is happy up to about 4KiB. File f = base; for (int i = 0; f.toString().length() <= 1024; ++i) { f = new File(f, longString); assertTrue(f.mkdir()); } return f; } // Rather than test all methods, assume that if createTempFile creates a long path and // exists can see it, the code for coping with long paths (shared by all methods) works. public void test_longPath() throws Exception { File base = createTemporaryDirectory(); assertTrue(createDeepStructure(base).exists()); } /* * readlink(2) is a special case,. * * This test assumes you can create symbolic links in the temporary directory. This * isn't true on Android if you're using /sdcard (which is used if this test is * run using vogar). It will work in /data/data/ though. */ public void test_longReadlink() throws Exception { File base = createTemporaryDirectory(); File target = createDeepStructure(base); File source = new File(base, "source"); assertFalse(source.exists()); assertTrue(target.exists()); assertTrue(target.getCanonicalPath().length() > 1024); ln_s(target, source); assertTrue(source.exists()); assertEquals(target.getCanonicalPath(), source.getCanonicalPath()); } // TODO: File.list is a special case too, but I haven't fixed it yet, and the new code, // like the old code, will die of a native buffer overrun if we exercise it. public void test_emptyFilename() throws Exception { // The behavior of the empty filename is an odd mixture. File f = new File(""); // Mostly it behaves like an invalid path... assertFalse(f.canExecute()); assertFalse(f.canRead()); assertFalse(f.canWrite()); try { f.createNewFile(); fail("expected IOException"); } catch (IOException expected) { } assertFalse(f.delete()); f.deleteOnExit(); assertFalse(f.exists()); assertEquals("", f.getName()); assertEquals(null, f.getParent()); assertEquals(null, f.getParentFile()); assertEquals("", f.getPath()); assertFalse(f.isAbsolute()); assertFalse(f.isDirectory()); assertFalse(f.isFile()); assertFalse(f.isHidden()); assertEquals(0, f.lastModified()); assertEquals(0, f.length()); assertEquals(null, f.list()); assertEquals(null, f.list(null)); assertEquals(null, f.listFiles()); assertEquals(null, f.listFiles((FileFilter) null)); assertEquals(null, f.listFiles((FilenameFilter) null)); assertFalse(f.mkdir()); assertFalse(f.mkdirs()); assertFalse(f.renameTo(f)); assertFalse(f.setLastModified(123)); assertFalse(f.setExecutable(true)); assertFalse(f.setReadOnly()); assertFalse(f.setReadable(true)); assertFalse(f.setWritable(true)); // ...but sometimes it behaves like "user.dir". String cwd = System.getProperty("user.dir"); assertEquals(new File(cwd), f.getAbsoluteFile()); assertEquals(cwd, f.getAbsolutePath()); // TODO: how do we test these without hard-coding assumptions about where our temporary // directory is? (In practice, on Android, our temporary directory is accessed through // a symbolic link, so the canonical file/path will be different.) //assertEquals(new File(cwd), f.getCanonicalFile()); //assertEquals(cwd, f.getCanonicalPath()); } // http://b/2486943 - between eclair and froyo, we added a call to // isAbsolute from the File constructor, potentially breaking subclasses. public void test_subclassing() throws Exception { class MyFile extends File { private String field; MyFile(String s) { super(s); field = ""; } @Override public boolean isAbsolute() { field.length(); return super.isAbsolute(); } } new MyFile(""); } /* * http://b/3047893 - getCanonicalPath wasn't actually resolving symbolic links. * * This test assumes you can create symbolic links in the temporary directory. This * isn't true on Android if you're using /sdcard (which is used if this test is * run using vogar). It will work in /data/data/ though. */ public void test_getCanonicalPath() throws Exception { File base = createTemporaryDirectory(); File target = new File(base, "target"); target.createNewFile(); // The RI won't follow a dangling symlink, which seems like a bug! File linkName = new File(base, "link"); ln_s(target, linkName); assertEquals(target.getCanonicalPath(), linkName.getCanonicalPath()); // .../subdir/shorter -> .../target (using a link to ../target). File subdir = new File(base, "subdir"); assertTrue(subdir.mkdir()); linkName = new File(subdir, "shorter"); ln_s("../target", linkName.toString()); assertEquals(target.getCanonicalPath(), linkName.getCanonicalPath()); // .../l -> .../subdir/longer (using a relative link to subdir/longer). linkName = new File(base, "l"); ln_s("subdir/longer", linkName.toString()); File longer = new File(base, "subdir/longer"); longer.createNewFile(); // The RI won't follow a dangling symlink, which seems like a bug! assertEquals(longer.getCanonicalPath(), linkName.getCanonicalPath()); // .../double -> .../target (via a link into subdir and a link back out). linkName = new File(base, "double"); ln_s("subdir/shorter", linkName.toString()); assertEquals(target.getCanonicalPath(), linkName.getCanonicalPath()); } private static void ln_s(File target, File linkName) throws Exception { ln_s(target.toString(), linkName.toString()); } private static void ln_s(String target, String linkName) throws Exception { Libcore.os.symlink(target, linkName); } public void test_createNewFile() throws Exception { File f = File.createTempFile("FileTest", "tmp"); assertFalse(f.createNewFile()); // EEXIST -> false assertFalse(f.getParentFile().createNewFile()); // EEXIST -> false, even if S_ISDIR try { new File(f, "poop").createNewFile(); // ENOTDIR -> throw fail(); } catch (IOException expected) { } try { new File("").createNewFile(); // ENOENT -> throw fail(); } catch (IOException expected) { } } public void test_rename() throws Exception { File f = File.createTempFile("FileTest", "tmp"); assertFalse(f.renameTo(new File(""))); assertFalse(new File("").renameTo(f)); assertFalse(f.renameTo(new File("."))); assertTrue(f.renameTo(f)); } public void test_getAbsolutePath() throws Exception { String userDir = System.getProperty("user.dir"); if (!userDir.endsWith(File.separator)) { userDir = userDir + File.separator; } File f = new File("poop"); assertEquals(userDir + "poop", f.getAbsolutePath()); } public void test_getSpace() throws Exception { assertTrue(new File("/").getFreeSpace() >= 0); assertTrue(new File("/").getTotalSpace() >= 0); assertTrue(new File("/").getUsableSpace() >= 0); } public void test_mkdirs() throws Exception { // Set up a directory to test in. File base = createTemporaryDirectory(); // mkdirs returns true only if it _creates_ a directory. // So we get false for a directory that already exists... assertTrue(base.exists()); assertFalse(base.mkdirs()); // But true if we had to create something. File a = new File(base, "a"); assertFalse(a.exists()); assertTrue(a.mkdirs()); assertTrue(a.exists()); // Test the recursive case where we need to create multiple parents. File b = new File(a, "b"); File c = new File(b, "c"); File d = new File(c, "d"); assertTrue(a.exists()); assertFalse(b.exists()); assertFalse(c.exists()); assertFalse(d.exists()); assertTrue(d.mkdirs()); assertTrue(a.exists()); assertTrue(b.exists()); assertTrue(c.exists()); assertTrue(d.exists()); // Test the case where the 'directory' exists as a file. File existsAsFile = new File(base, "existsAsFile"); existsAsFile.createNewFile(); assertTrue(existsAsFile.exists()); assertFalse(existsAsFile.mkdirs()); // Test the case where the parent exists as a file. File badParent = new File(existsAsFile, "sub"); assertTrue(existsAsFile.exists()); assertFalse(badParent.exists()); assertFalse(badParent.mkdirs()); } // http://b/23523042 : Test that creating a directory and file with // a surrogate pair in the name works as expected and roundtrips correctly. public void testFilesWithSurrogatePairs() throws Exception { File base = createTemporaryDirectory(); // U+13000 encodes to the surrogate pair D80C + DC00 in UTF16 // and the 4 byte UTF-8 sequence [ 0xf0, 0x93, 0x80, 0x80 ]. The // file name must be encoded using the 4 byte UTF-8 sequence before // it reaches the file system. File subDir = new File(base, "dir_\uD80C\uDC00"); assertTrue(subDir.mkdir()); File subFile = new File(subDir, "file_\uD80C\uDC00"); assertTrue(subFile.createNewFile()); File[] files = base.listFiles(); assertEquals(1, files.length); assertEquals("dir_\uD80C\uDC00", files[0].getName()); files = subDir.listFiles(); assertEquals(1, files.length); assertEquals("file_\uD80C\uDC00", files[0].getName()); // Throws on error. nativeTestFilesWithSurrogatePairs(base.getAbsolutePath()); } // http://b/25878034 // // SELinux prevents stat(2) from working on some parts of the system partition, and there // isn't currently a CTS test that enforces this for the system partition as a whole (and it // isn't clear that there can be one). This particular file has a special label // (see file_contexts) that makes sure it isn't unstattable but then again this file might // disappear soon or be absent on some devices. // // TODO: This isn't a very good test. uncrypt is scheduled to disappear somewhere // in the near future. Is there a better candidate file ? public void testExistsOnSystem() { File sh = new File("/system/bin/uncrypt"); assertTrue(sh.exists()); try { android.system.Os.stat(sh.getAbsolutePath()); fail(); } catch (android.system.ErrnoException expected) { } } // http://b/25859957 // // OpenJdk is treating empty parent string as a special case, // it substitutes parent string with the filesystem default parent value "/" // This wasn't the case before the switch to openJdk. public void testEmptyParentString() { File f1 = new File("", "foo.bar"); File f2 = new File((String)null, "foo.bar"); assertEquals("foo.bar", f1.toString()); assertEquals("foo.bar", f2.toString()); } // http://b/27273930 public void testJavaIoTmpdirMutable() throws Exception { final String oldTmpDir = System.getProperty("java.io.tmpdir"); final String directoryName = "/newTemp" + Integer.toString(Math.randomIntInternal()); final String newTmpDir = oldTmpDir + directoryName; File subDir = new File(oldTmpDir, directoryName); assertTrue(subDir.mkdir()); try { System.setProperty("java.io.tmpdir", newTmpDir); File tempFile = File.createTempFile("foo", ".bar"); assertTrue(tempFile.getAbsolutePath().contains(directoryName)); } finally { System.setProperty("java.io.tmpdir", oldTmpDir); } } private static native void nativeTestFilesWithSurrogatePairs(String base); // http://b/27731686 public void testBug27731686() { File file = new File("/test1", "/"); assertEquals("/test1", file.getPath()); assertEquals("test1", file.getName()); } public void testFileNameNormalization() { assertEquals("/", new File("/", "/").getPath()); assertEquals("/", new File("/", "").getPath()); assertEquals("/", new File("", "/").getPath()); assertEquals("", new File("", "").getPath()); assertEquals("/foo/bar", new File("/foo/", "/bar/").getPath()); assertEquals("/foo/bar", new File("/foo", "/bar//").getPath()); } }