1/* 2 * Copyright (C) 2008 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 android.os; 18 19import static android.text.format.DateUtils.DAY_IN_MILLIS; 20import static android.text.format.DateUtils.HOUR_IN_MILLIS; 21import static android.text.format.DateUtils.WEEK_IN_MILLIS; 22 23import android.content.Context; 24import android.provider.DocumentsContract.Document; 25import android.test.AndroidTestCase; 26import android.test.suitebuilder.annotation.MediumTest; 27 28import com.google.android.collect.Sets; 29 30import libcore.io.IoUtils; 31 32import java.io.ByteArrayInputStream; 33import java.io.File; 34import java.io.FileOutputStream; 35import java.io.FileWriter; 36import java.util.Arrays; 37import java.util.HashSet; 38 39@MediumTest 40public class FileUtilsTest extends AndroidTestCase { 41 private static final String TEST_DATA = 42 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 43 44 private File mDir; 45 private File mTestFile; 46 private File mCopyFile; 47 private File mTarget; 48 49 50 @Override 51 protected void setUp() throws Exception { 52 super.setUp(); 53 mDir = getContext().getDir("testing", Context.MODE_PRIVATE); 54 mTestFile = new File(mDir, "test.file"); 55 mCopyFile = new File(mDir, "copy.file"); 56 57 mTarget = getContext().getFilesDir(); 58 FileUtils.deleteContents(mTarget); 59 } 60 61 @Override 62 protected void tearDown() throws Exception { 63 IoUtils.deleteContents(mDir); 64 FileUtils.deleteContents(mTarget); 65 } 66 67 // TODO: test setPermissions(), getPermissions() 68 69 public void testCopyFile() throws Exception { 70 stageFile(mTestFile, TEST_DATA); 71 assertFalse(mCopyFile.exists()); 72 FileUtils.copyFile(mTestFile, mCopyFile); 73 assertTrue(mCopyFile.exists()); 74 assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null)); 75 } 76 77 public void testCopyToFile() throws Exception { 78 final String s = "Foo Bar"; 79 assertFalse(mCopyFile.exists()); 80 FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile); 81 assertTrue(mCopyFile.exists()); 82 assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null)); 83 } 84 85 public void testIsFilenameSafe() throws Exception { 86 assertTrue(FileUtils.isFilenameSafe(new File("foobar"))); 87 assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23"))); 88 assertFalse(FileUtils.isFilenameSafe(new File("foo*bar"))); 89 assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar"))); 90 } 91 92 public void testReadTextFile() throws Exception { 93 stageFile(mTestFile, TEST_DATA); 94 95 assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null)); 96 97 assertEquals("ABCDE", FileUtils.readTextFile(mTestFile, 5, null)); 98 assertEquals("ABCDE<>", FileUtils.readTextFile(mTestFile, 5, "<>")); 99 assertEquals(TEST_DATA.substring(0, 51) + "<>", 100 FileUtils.readTextFile(mTestFile, 51, "<>")); 101 assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 52, "<>")); 102 assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 100, "<>")); 103 104 assertEquals("vwxyz", FileUtils.readTextFile(mTestFile, -5, null)); 105 assertEquals("<>vwxyz", FileUtils.readTextFile(mTestFile, -5, "<>")); 106 assertEquals("<>" + TEST_DATA.substring(1, 52), 107 FileUtils.readTextFile(mTestFile, -51, "<>")); 108 assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -52, "<>")); 109 assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>")); 110 } 111 112 public void testReadTextFileWithZeroLengthFile() throws Exception { 113 stageFile(mTestFile, TEST_DATA); 114 new FileOutputStream(mTestFile).close(); // Zero out the file 115 assertEquals("", FileUtils.readTextFile(mTestFile, 0, null)); 116 assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>")); 117 assertEquals("", FileUtils.readTextFile(mTestFile, 10, "<>")); 118 assertEquals("", FileUtils.readTextFile(mTestFile, -1, "<>")); 119 assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>")); 120 } 121 122 public void testContains() throws Exception { 123 assertTrue(FileUtils.contains(new File("/"), new File("/moo.txt"))); 124 assertTrue(FileUtils.contains(new File("/"), new File("/"))); 125 126 assertTrue(FileUtils.contains(new File("/sdcard"), new File("/sdcard"))); 127 assertTrue(FileUtils.contains(new File("/sdcard/"), new File("/sdcard/"))); 128 129 assertTrue(FileUtils.contains(new File("/sdcard"), new File("/sdcard/moo.txt"))); 130 assertTrue(FileUtils.contains(new File("/sdcard/"), new File("/sdcard/moo.txt"))); 131 132 assertFalse(FileUtils.contains(new File("/sdcard"), new File("/moo.txt"))); 133 assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/moo.txt"))); 134 135 assertFalse(FileUtils.contains(new File("/sdcard"), new File("/sdcard.txt"))); 136 assertFalse(FileUtils.contains(new File("/sdcard/"), new File("/sdcard.txt"))); 137 } 138 139 public void testDeleteOlderEmptyDir() throws Exception { 140 FileUtils.deleteOlderFiles(mDir, 10, WEEK_IN_MILLIS); 141 assertDirContents(); 142 } 143 144 public void testDeleteOlderTypical() throws Exception { 145 touch("file1", HOUR_IN_MILLIS); 146 touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 147 touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 148 touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 149 touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 150 assertTrue(FileUtils.deleteOlderFiles(mDir, 3, DAY_IN_MILLIS)); 151 assertDirContents("file1", "file2", "file3"); 152 } 153 154 public void testDeleteOlderInFuture() throws Exception { 155 touch("file1", -HOUR_IN_MILLIS); 156 touch("file2", HOUR_IN_MILLIS); 157 touch("file3", WEEK_IN_MILLIS); 158 assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); 159 assertDirContents("file1", "file2"); 160 161 touch("file1", -HOUR_IN_MILLIS); 162 touch("file2", HOUR_IN_MILLIS); 163 touch("file3", WEEK_IN_MILLIS); 164 assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); 165 assertDirContents("file1", "file2"); 166 } 167 168 public void testDeleteOlderOnlyAge() throws Exception { 169 touch("file1", HOUR_IN_MILLIS); 170 touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 171 touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 172 touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 173 touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 174 assertTrue(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); 175 assertFalse(FileUtils.deleteOlderFiles(mDir, 0, DAY_IN_MILLIS)); 176 assertDirContents("file1"); 177 } 178 179 public void testDeleteOlderOnlyCount() throws Exception { 180 touch("file1", HOUR_IN_MILLIS); 181 touch("file2", 1 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 182 touch("file3", 2 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 183 touch("file4", 3 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 184 touch("file5", 4 * DAY_IN_MILLIS + HOUR_IN_MILLIS); 185 assertTrue(FileUtils.deleteOlderFiles(mDir, 2, 0)); 186 assertFalse(FileUtils.deleteOlderFiles(mDir, 2, 0)); 187 assertDirContents("file1", "file2"); 188 } 189 190 public void testValidExtFilename() throws Exception { 191 assertTrue(FileUtils.isValidExtFilename("a")); 192 assertTrue(FileUtils.isValidExtFilename("foo.bar")); 193 assertTrue(FileUtils.isValidExtFilename("foo bar.baz")); 194 assertTrue(FileUtils.isValidExtFilename("foo.bar.baz")); 195 assertTrue(FileUtils.isValidExtFilename(".bar")); 196 assertTrue(FileUtils.isValidExtFilename("foo~!@#$%^&*()_[]{}+bar")); 197 198 assertFalse(FileUtils.isValidExtFilename(null)); 199 assertFalse(FileUtils.isValidExtFilename(".")); 200 assertFalse(FileUtils.isValidExtFilename("../foo")); 201 assertFalse(FileUtils.isValidExtFilename("/foo")); 202 203 assertEquals(".._foo", FileUtils.buildValidExtFilename("../foo")); 204 assertEquals("_foo", FileUtils.buildValidExtFilename("/foo")); 205 assertEquals("foo_bar", FileUtils.buildValidExtFilename("foo\0bar")); 206 assertEquals(".foo", FileUtils.buildValidExtFilename(".foo")); 207 assertEquals("foo.bar", FileUtils.buildValidExtFilename("foo.bar")); 208 } 209 210 public void testValidFatFilename() throws Exception { 211 assertTrue(FileUtils.isValidFatFilename("a")); 212 assertTrue(FileUtils.isValidFatFilename("foo bar.baz")); 213 assertTrue(FileUtils.isValidFatFilename("foo.bar.baz")); 214 assertTrue(FileUtils.isValidFatFilename(".bar")); 215 assertTrue(FileUtils.isValidFatFilename("foo.bar")); 216 assertTrue(FileUtils.isValidFatFilename("foo bar")); 217 assertTrue(FileUtils.isValidFatFilename("foo+bar")); 218 assertTrue(FileUtils.isValidFatFilename("foo,bar")); 219 220 assertFalse(FileUtils.isValidFatFilename("foo*bar")); 221 assertFalse(FileUtils.isValidFatFilename("foo?bar")); 222 assertFalse(FileUtils.isValidFatFilename("foo<bar")); 223 assertFalse(FileUtils.isValidFatFilename(null)); 224 assertFalse(FileUtils.isValidFatFilename(".")); 225 assertFalse(FileUtils.isValidFatFilename("../foo")); 226 assertFalse(FileUtils.isValidFatFilename("/foo")); 227 228 assertEquals(".._foo", FileUtils.buildValidFatFilename("../foo")); 229 assertEquals("_foo", FileUtils.buildValidFatFilename("/foo")); 230 assertEquals(".foo", FileUtils.buildValidFatFilename(".foo")); 231 assertEquals("foo.bar", FileUtils.buildValidFatFilename("foo.bar")); 232 assertEquals("foo_bar__baz", FileUtils.buildValidFatFilename("foo?bar**baz")); 233 } 234 235 public void testTrimFilename() throws Exception { 236 assertEquals("short.txt", FileUtils.trimFilename("short.txt", 16)); 237 assertEquals("extrem...eme.txt", FileUtils.trimFilename("extremelylongfilename.txt", 16)); 238 239 final String unicode = "a\u03C0\u03C0\u03C0\u03C0z"; 240 assertEquals("a\u03C0\u03C0\u03C0\u03C0z", FileUtils.trimFilename(unicode, 10)); 241 assertEquals("a\u03C0...\u03C0z", FileUtils.trimFilename(unicode, 9)); 242 assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 8)); 243 assertEquals("a...\u03C0z", FileUtils.trimFilename(unicode, 7)); 244 assertEquals("a...z", FileUtils.trimFilename(unicode, 6)); 245 } 246 247 public void testBuildUniqueFile_normal() throws Exception { 248 assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test")); 249 assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); 250 assertNameEquals("test.jpeg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpeg")); 251 assertNameEquals("TEst.JPeg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "TEst.JPeg")); 252 assertNameEquals("test.png.jpg", 253 FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.png.jpg")); 254 assertNameEquals("test.png.jpg", 255 FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.png")); 256 257 assertNameEquals("test.flac", FileUtils.buildUniqueFile(mTarget, "audio/flac", "test")); 258 assertNameEquals("test.flac", FileUtils.buildUniqueFile(mTarget, "audio/flac", "test.flac")); 259 assertNameEquals("test.flac", 260 FileUtils.buildUniqueFile(mTarget, "application/x-flac", "test")); 261 assertNameEquals("test.flac", 262 FileUtils.buildUniqueFile(mTarget, "application/x-flac", "test.flac")); 263 } 264 265 public void testBuildUniqueFile_unknown() throws Exception { 266 assertNameEquals("test", 267 FileUtils.buildUniqueFile(mTarget, "application/octet-stream", "test")); 268 assertNameEquals("test.jpg", 269 FileUtils.buildUniqueFile(mTarget, "application/octet-stream", "test.jpg")); 270 assertNameEquals(".test", 271 FileUtils.buildUniqueFile(mTarget, "application/octet-stream", ".test")); 272 273 assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, "lolz/lolz", "test")); 274 assertNameEquals("test.lolz", FileUtils.buildUniqueFile(mTarget, "lolz/lolz", "test.lolz")); 275 } 276 277 public void testBuildUniqueFile_dir() throws Exception { 278 assertNameEquals("test", FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test")); 279 new File(mTarget, "test").mkdir(); 280 assertNameEquals("test (1)", 281 FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test")); 282 283 assertNameEquals("test.jpg", 284 FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test.jpg")); 285 new File(mTarget, "test.jpg").mkdir(); 286 assertNameEquals("test.jpg (1)", 287 FileUtils.buildUniqueFile(mTarget, Document.MIME_TYPE_DIR, "test.jpg")); 288 } 289 290 public void testBuildUniqueFile_increment() throws Exception { 291 assertNameEquals("test.jpg", FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); 292 new File(mTarget, "test.jpg").createNewFile(); 293 assertNameEquals("test (1).jpg", 294 FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); 295 new File(mTarget, "test (1).jpg").createNewFile(); 296 assertNameEquals("test (2).jpg", 297 FileUtils.buildUniqueFile(mTarget, "image/jpeg", "test.jpg")); 298 } 299 300 private static void assertNameEquals(String expected, File actual) { 301 assertEquals(expected, actual.getName()); 302 } 303 304 private void touch(String name, long age) throws Exception { 305 final File file = new File(mDir, name); 306 file.createNewFile(); 307 file.setLastModified(System.currentTimeMillis() - age); 308 } 309 310 private void stageFile(File file, String data) throws Exception { 311 FileWriter writer = new FileWriter(file); 312 try { 313 writer.write(data, 0, data.length()); 314 } finally { 315 writer.close(); 316 } 317 } 318 319 private void assertDirContents(String... expected) { 320 final HashSet<String> expectedSet = Sets.newHashSet(expected); 321 String[] actual = mDir.list(); 322 if (actual == null) actual = new String[0]; 323 324 assertEquals( 325 "Expected " + Arrays.toString(expected) + " but actual " + Arrays.toString(actual), 326 expected.length, actual.length); 327 for (String actualFile : actual) { 328 assertTrue("Unexpected actual file " + actualFile, expectedSet.contains(actualFile)); 329 } 330 } 331} 332