1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package libcore.java.io; 18 19import java.io.BufferedReader; 20import java.io.File; 21import java.io.FileFilter; 22import java.io.FilenameFilter; 23import java.io.InputStreamReader; 24import java.io.IOException; 25import java.util.UUID; 26import libcore.io.Libcore; 27 28public class FileTest extends junit.framework.TestCase { 29 private static File createTemporaryDirectory() throws Exception { 30 String base = System.getProperty("java.io.tmpdir"); 31 File directory = new File(base, UUID.randomUUID().toString()); 32 assertTrue(directory.mkdirs()); 33 return directory; 34 } 35 36 private static String longString(int n) { 37 StringBuilder result = new StringBuilder(); 38 for (int i = 0; i < n; ++i) { 39 result.append('x'); 40 } 41 return result.toString(); 42 } 43 44 private static File createDeepStructure(File base) throws Exception { 45 // ext has a limit of around 256 characters for each path entry. 46 // 128 characters should be safe for everything but FAT. 47 String longString = longString(128); 48 // Keep creating subdirectories until the path length is greater than 1KiB. 49 // Ubuntu 8.04's kernel is happy up to about 4KiB. 50 File f = base; 51 for (int i = 0; f.toString().length() <= 1024; ++i) { 52 f = new File(f, longString); 53 assertTrue(f.mkdir()); 54 } 55 return f; 56 } 57 58 // Rather than test all methods, assume that if createTempFile creates a long path and 59 // exists can see it, the code for coping with long paths (shared by all methods) works. 60 public void test_longPath() throws Exception { 61 File base = createTemporaryDirectory(); 62 assertTrue(createDeepStructure(base).exists()); 63 } 64 65 // readlink(2) is a special case,. 66 public void test_longReadlink() throws Exception { 67 File base = createTemporaryDirectory(); 68 File target = createDeepStructure(base); 69 File source = new File(base, "source"); 70 assertFalse(source.exists()); 71 assertTrue(target.exists()); 72 assertTrue(target.getCanonicalPath().length() > 1024); 73 ln_s(target, source); 74 assertTrue(source.exists()); 75 assertEquals(target.getCanonicalPath(), source.getCanonicalPath()); 76 } 77 78 // TODO: File.list is a special case too, but I haven't fixed it yet, and the new code, 79 // like the old code, will die of a native buffer overrun if we exercise it. 80 81 public void test_emptyFilename() throws Exception { 82 // The behavior of the empty filename is an odd mixture. 83 File f = new File(""); 84 // Mostly it behaves like an invalid path... 85 assertFalse(f.canExecute()); 86 assertFalse(f.canRead()); 87 assertFalse(f.canWrite()); 88 try { 89 f.createNewFile(); 90 fail("expected IOException"); 91 } catch (IOException expected) { 92 } 93 assertFalse(f.delete()); 94 f.deleteOnExit(); 95 assertFalse(f.exists()); 96 assertEquals("", f.getName()); 97 assertEquals(null, f.getParent()); 98 assertEquals(null, f.getParentFile()); 99 assertEquals("", f.getPath()); 100 assertFalse(f.isAbsolute()); 101 assertFalse(f.isDirectory()); 102 assertFalse(f.isFile()); 103 assertFalse(f.isHidden()); 104 assertEquals(0, f.lastModified()); 105 assertEquals(0, f.length()); 106 assertEquals(null, f.list()); 107 assertEquals(null, f.list(null)); 108 assertEquals(null, f.listFiles()); 109 assertEquals(null, f.listFiles((FileFilter) null)); 110 assertEquals(null, f.listFiles((FilenameFilter) null)); 111 assertFalse(f.mkdir()); 112 assertFalse(f.mkdirs()); 113 assertFalse(f.renameTo(f)); 114 assertFalse(f.setLastModified(123)); 115 assertFalse(f.setExecutable(true)); 116 assertFalse(f.setReadOnly()); 117 assertFalse(f.setReadable(true)); 118 assertFalse(f.setWritable(true)); 119 // ...but sometimes it behaves like "user.dir". 120 String cwd = System.getProperty("user.dir"); 121 assertEquals(new File(cwd), f.getAbsoluteFile()); 122 assertEquals(cwd, f.getAbsolutePath()); 123 // TODO: how do we test these without hard-coding assumptions about where our temporary 124 // directory is? (In practice, on Android, our temporary directory is accessed through 125 // a symbolic link, so the canonical file/path will be different.) 126 //assertEquals(new File(cwd), f.getCanonicalFile()); 127 //assertEquals(cwd, f.getCanonicalPath()); 128 } 129 130 // http://b/2486943 - between eclair and froyo, we added a call to 131 // isAbsolute from the File constructor, potentially breaking subclasses. 132 public void test_subclassing() throws Exception { 133 class MyFile extends File { 134 private String field; 135 MyFile(String s) { 136 super(s); 137 field = ""; 138 } 139 @Override public boolean isAbsolute() { 140 field.length(); 141 return super.isAbsolute(); 142 } 143 } 144 new MyFile(""); 145 } 146 147 // http://b/3047893 - getCanonicalPath wasn't actually resolving symbolic links. 148 public void test_getCanonicalPath() throws Exception { 149 // This assumes you can create symbolic links in the temporary directory. This isn't 150 // true on Android if you're using /sdcard. It will work in /data/local though. 151 File base = createTemporaryDirectory(); 152 File target = new File(base, "target"); 153 target.createNewFile(); // The RI won't follow a dangling symlink, which seems like a bug! 154 File linkName = new File(base, "link"); 155 ln_s(target, linkName); 156 assertEquals(target.getCanonicalPath(), linkName.getCanonicalPath()); 157 158 // .../subdir/shorter -> .../target (using a link to ../target). 159 File subdir = new File(base, "subdir"); 160 assertTrue(subdir.mkdir()); 161 linkName = new File(subdir, "shorter"); 162 ln_s("../target", linkName.toString()); 163 assertEquals(target.getCanonicalPath(), linkName.getCanonicalPath()); 164 165 // .../l -> .../subdir/longer (using a relative link to subdir/longer). 166 linkName = new File(base, "l"); 167 ln_s("subdir/longer", linkName.toString()); 168 File longer = new File(base, "subdir/longer"); 169 longer.createNewFile(); // The RI won't follow a dangling symlink, which seems like a bug! 170 assertEquals(longer.getCanonicalPath(), linkName.getCanonicalPath()); 171 172 // .../double -> .../target (via a link into subdir and a link back out). 173 linkName = new File(base, "double"); 174 ln_s("subdir/shorter", linkName.toString()); 175 assertEquals(target.getCanonicalPath(), linkName.getCanonicalPath()); 176 } 177 178 private static void ln_s(File target, File linkName) throws Exception { 179 ln_s(target.toString(), linkName.toString()); 180 } 181 182 private static void ln_s(String target, String linkName) throws Exception { 183 Libcore.os.symlink(target, linkName); 184 } 185 186 public void test_createNewFile() throws Exception { 187 File f = File.createTempFile("FileTest", "tmp"); 188 assertFalse(f.createNewFile()); // EEXIST -> false 189 assertFalse(f.getParentFile().createNewFile()); // EEXIST -> false, even if S_ISDIR 190 try { 191 new File(f, "poop").createNewFile(); // ENOTDIR -> throw 192 fail(); 193 } catch (IOException expected) { 194 } 195 try { 196 new File("").createNewFile(); // ENOENT -> throw 197 fail(); 198 } catch (IOException expected) { 199 } 200 } 201 202 public void test_rename() throws Exception { 203 File f = File.createTempFile("FileTest", "tmp"); 204 assertFalse(f.renameTo(new File(""))); 205 assertFalse(new File("").renameTo(f)); 206 assertFalse(f.renameTo(new File("."))); 207 assertTrue(f.renameTo(f)); 208 } 209 210 public void test_getAbsolutePath() throws Exception { 211 String originalUserDir = System.getProperty("user.dir"); 212 try { 213 File f = new File("poop"); 214 System.setProperty("user.dir", "/a"); 215 assertEquals("/a/poop", f.getAbsolutePath()); 216 System.setProperty("user.dir", "/b"); 217 assertEquals("/b/poop", f.getAbsolutePath()); 218 } finally { 219 System.setProperty("user.dir", originalUserDir); 220 } 221 } 222 223 public void test_getSpace() throws Exception { 224 assertTrue(new File("/").getFreeSpace() >= 0); 225 assertTrue(new File("/").getTotalSpace() >= 0); 226 assertTrue(new File("/").getUsableSpace() >= 0); 227 } 228 229 public void test_mkdirs() throws Exception { 230 // Set up a directory to test in. 231 File base = createTemporaryDirectory(); 232 233 // mkdirs returns true only if it _creates_ a directory. 234 // So we get false for a directory that already exists... 235 assertTrue(base.exists()); 236 assertFalse(base.mkdirs()); 237 // But true if we had to create something. 238 File a = new File(base, "a"); 239 assertFalse(a.exists()); 240 assertTrue(a.mkdirs()); 241 assertTrue(a.exists()); 242 243 // Test the recursive case where we need to create multiple parents. 244 File b = new File(a, "b"); 245 File c = new File(b, "c"); 246 File d = new File(c, "d"); 247 assertTrue(a.exists()); 248 assertFalse(b.exists()); 249 assertFalse(c.exists()); 250 assertFalse(d.exists()); 251 assertTrue(d.mkdirs()); 252 assertTrue(a.exists()); 253 assertTrue(b.exists()); 254 assertTrue(c.exists()); 255 assertTrue(d.exists()); 256 257 // Test the case where the 'directory' exists as a file. 258 File existsAsFile = new File(base, "existsAsFile"); 259 existsAsFile.createNewFile(); 260 assertTrue(existsAsFile.exists()); 261 assertFalse(existsAsFile.mkdirs()); 262 263 // Test the case where the parent exists as a file. 264 File badParent = new File(existsAsFile, "sub"); 265 assertTrue(existsAsFile.exists()); 266 assertFalse(badParent.exists()); 267 assertFalse(badParent.mkdirs()); 268 } 269} 270