1/* 2 * Copyright (C) 2015 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 */ 16package libcore.tzdata.update; 17 18import junit.framework.TestCase; 19 20import android.system.Os; 21import android.system.OsConstants; 22import android.system.StructStat; 23 24import java.io.BufferedWriter; 25import java.io.File; 26import java.io.FileOutputStream; 27import java.io.IOException; 28import java.io.OutputStreamWriter; 29import java.nio.charset.StandardCharsets; 30import java.util.ArrayList; 31import java.util.Arrays; 32import java.util.Collections; 33import java.util.List; 34import libcore.io.IoUtils; 35import libcore.io.Libcore; 36 37/** 38 * Tests for {@link FileUtils}. 39 */ 40public class FileUtilsTest extends TestCase { 41 42 private List<File> testFiles = new ArrayList<>(); 43 44 @Override 45 public void tearDown() throws Exception { 46 // Delete in reverse order 47 Collections.reverse(testFiles); 48 for (File tempFile : testFiles) { 49 tempFile.delete(); 50 } 51 super.tearDown(); 52 } 53 54 public void testCalculateChecksum() throws Exception { 55 final String content = "Content"; 56 File file1 = createTextFile(content); 57 File file2 = createTextFile(content); 58 File file3 = createTextFile(content + "!"); 59 60 long file1CheckSum = FileUtils.calculateChecksum(file1); 61 long file2CheckSum = FileUtils.calculateChecksum(file2); 62 long file3Checksum = FileUtils.calculateChecksum(file3); 63 64 assertEquals(file1CheckSum, file2CheckSum); 65 assertTrue(file1CheckSum != file3Checksum); 66 } 67 68 public void testDeleteRecursive() throws Exception { 69 File dir = createTempDir(); 70 File file1 = createRegularFile(dir, "file1"); 71 File file2 = createRegularFile(dir, "file2"); 72 File symLink1 = createSymlink(file1, dir, "symLink1"); 73 File subDir = createDir(dir, "subDir"); 74 File file3 = createRegularFile(subDir, "subFile1"); 75 File file4 = createRegularFile(subDir, "subFile2"); 76 File symLink2 = createSymlink(file1, dir, "symLink2"); 77 78 File otherDir = createTempDir(); 79 File otherFile = createRegularFile(otherDir, "kept"); 80 81 File linkToOtherDir = createSymlink(otherDir, subDir, "linkToOtherDir"); 82 File linkToOtherFile = createSymlink(otherFile, subDir, "linkToOtherFile"); 83 84 File[] filesToDelete = { dir, file1, file2, symLink1, subDir, file3, file4, symLink2, 85 linkToOtherDir, linkToOtherFile }; 86 File[] filesToKeep = { otherDir, otherFile }; 87 assertFilesExist(filesToDelete); 88 assertFilesExist(filesToKeep); 89 90 FileUtils.deleteRecursive(dir); 91 assertFilesDoNotExist(filesToDelete); 92 assertFilesExist(filesToKeep); 93 } 94 95 public void testIsSymlink() throws Exception { 96 File dir = createTempDir(); 97 File subDir = createDir(dir, "subDir"); 98 File fileInSubDir = createRegularFile(subDir, "fileInSubDir"); 99 File normalFile = createRegularFile(dir, "normalFile"); 100 File symlinkToDir = createSymlink(subDir, dir, "symlinkToDir"); 101 File symlinkToFile = createSymlink(fileInSubDir, dir, "symlinkToFile"); 102 File symlinkToFileInSubDir = createSymlink(fileInSubDir, dir, "symlinkToFileInSubDir"); 103 File normalFileViaSymlink = new File(symlinkToDir, "normalFile"); 104 105 assertFalse(FileUtils.isSymlink(dir)); 106 assertFalse(FileUtils.isSymlink(subDir)); 107 assertFalse(FileUtils.isSymlink(fileInSubDir)); 108 assertFalse(FileUtils.isSymlink(normalFile)); 109 assertTrue(FileUtils.isSymlink(symlinkToDir)); 110 assertTrue(FileUtils.isSymlink(symlinkToFile)); 111 assertTrue(FileUtils.isSymlink(symlinkToFileInSubDir)); 112 assertFalse(FileUtils.isSymlink(normalFileViaSymlink)); 113 } 114 115 public void testCreateSubFile() throws Exception { 116 File dir1 = createTempDir().getCanonicalFile(); 117 118 File actualSubFile = FileUtils.createSubFile(dir1, "file"); 119 assertEquals(new File(dir1, "file"), actualSubFile); 120 121 File existingSubFile = createRegularFile(dir1, "file"); 122 actualSubFile = FileUtils.createSubFile(dir1, "file"); 123 assertEquals(existingSubFile, actualSubFile); 124 125 File existingSubDir = createDir(dir1, "subdir"); 126 actualSubFile = FileUtils.createSubFile(dir1, "subdir"); 127 assertEquals(existingSubDir, actualSubFile); 128 129 assertCreateSubFileThrows(dir1, "../file"); 130 assertCreateSubFileThrows(dir1, "../../file"); 131 assertCreateSubFileThrows(dir1, "../otherdir/file"); 132 133 File dir2 = createTempDir().getCanonicalFile(); 134 createSymlink(dir2, dir1, "symlinkToDir2"); 135 assertCreateSubFileThrows(dir1, "symlinkToDir2"); 136 137 assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir"); 138 139 createRegularFile(dir1, "symlinkToDir2/fileInSymlinkedDir"); 140 assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir"); 141 } 142 143 public void testEnsureDirectoryExists() throws Exception { 144 File dir = createTempDir(); 145 146 File exists = new File(dir, "exists"); 147 assertTrue(exists.mkdir()); 148 assertTrue(exists.setReadable(true /* readable */, true /* ownerOnly */)); 149 assertTrue(exists.setExecutable(true /* readable */, true /* ownerOnly */)); 150 FileUtils.ensureDirectoriesExist(exists, true /* makeWorldReadable */); 151 assertDirExistsAndIsAccessible(exists, false /* requireWorldReadable */); 152 153 File subDir = new File(dir, "subDir"); 154 assertFalse(subDir.exists()); 155 FileUtils.ensureDirectoriesExist(subDir, true /* makeWorldReadable */); 156 assertDirExistsAndIsAccessible(subDir, true /* requireWorldReadable */); 157 158 File one = new File(dir, "one"); 159 File two = new File(one, "two"); 160 File three = new File(two, "three"); 161 FileUtils.ensureDirectoriesExist(three, true /* makeWorldReadable */); 162 assertDirExistsAndIsAccessible(one, true /* requireWorldReadable */); 163 assertDirExistsAndIsAccessible(two, true /* requireWorldReadable */); 164 assertDirExistsAndIsAccessible(three, true /* requireWorldReadable */); 165 } 166 167 public void testEnsureDirectoriesExist_noPermissions() throws Exception { 168 File dir = createTempDir(); 169 assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */); 170 171 File unreadableSubDir = new File(dir, "unreadableSubDir"); 172 assertTrue(unreadableSubDir.mkdir()); 173 assertTrue(unreadableSubDir.setReadable(false /* readable */, true /* ownerOnly */)); 174 assertTrue(unreadableSubDir.setExecutable(false /* readable */, true /* ownerOnly */)); 175 176 File toCreate = new File(unreadableSubDir, "toCreate"); 177 try { 178 FileUtils.ensureDirectoriesExist(toCreate, true /* makeWorldReadable */); 179 fail(); 180 } catch (IOException expected) { 181 } 182 assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */); 183 assertFalse(unreadableSubDir.canRead() && unreadableSubDir.canExecute()); 184 assertFalse(toCreate.exists()); 185 } 186 187 public void testEnsureFileDoesNotExist() throws Exception { 188 File dir = createTempDir(); 189 190 FileUtils.ensureFileDoesNotExist(new File(dir, "doesNotExist")); 191 192 File exists1 = createRegularFile(dir, "exists1"); 193 assertTrue(exists1.exists()); 194 FileUtils.ensureFileDoesNotExist(exists1); 195 assertFalse(exists1.exists()); 196 197 exists1 = createRegularFile(dir, "exists1"); 198 File symlink = createSymlink(exists1, dir, "symlinkToFile"); 199 assertTrue(symlink.exists()); 200 FileUtils.ensureFileDoesNotExist(symlink); 201 assertFalse(symlink.exists()); 202 assertTrue(exists1.exists()); 203 204 // Only files and symlinks supported. We do not delete directories. 205 File emptyDir = createTempDir(); 206 try { 207 FileUtils.ensureFileDoesNotExist(emptyDir); 208 fail(); 209 } catch (IOException expected) { 210 } 211 assertTrue(emptyDir.exists()); 212 } 213 214 // This test does not pass when run as root because root can do anything even if the permissions 215 // don't allow it. 216 public void testEnsureFileDoesNotExist_noPermission() throws Exception { 217 File dir = createTempDir(); 218 219 File protectedDir = createDir(dir, "protected"); 220 File undeletable = createRegularFile(protectedDir, "undeletable"); 221 assertTrue(protectedDir.setWritable(false)); 222 assertTrue(undeletable.exists()); 223 try { 224 FileUtils.ensureFileDoesNotExist(undeletable); 225 fail(); 226 } catch (IOException expected) { 227 } finally { 228 assertTrue(protectedDir.setWritable(true)); // Reset for clean-up 229 } 230 assertTrue(undeletable.exists()); 231 } 232 233 public void testCheckFilesExist() throws Exception { 234 File dir = createTempDir(); 235 createRegularFile(dir, "exists1"); 236 File subDir = createDir(dir, "subDir"); 237 createRegularFile(subDir, "exists2"); 238 assertTrue(FileUtils.filesExist(dir, "exists1", "subDir/exists2")); 239 assertFalse(FileUtils.filesExist(dir, "doesNotExist")); 240 assertFalse(FileUtils.filesExist(dir, "subDir/doesNotExist")); 241 } 242 243 public void testReadLines() throws Exception { 244 File file = createTextFile("One\nTwo\nThree\n"); 245 246 List<String> lines = FileUtils.readLines(file); 247 assertEquals(3, lines.size()); 248 assertEquals(lines, Arrays.asList("One", "Two", "Three")); 249 } 250 251 private File createTextFile(String contents) throws IOException { 252 File file = File.createTempFile(getClass().getSimpleName(), ".txt"); 253 try (FileOutputStream fos = new FileOutputStream(file)) { 254 BufferedWriter writer = new BufferedWriter( 255 new OutputStreamWriter(fos, StandardCharsets.UTF_8)); 256 writer.write(contents); 257 writer.close(); 258 } 259 return file; 260 } 261 262 private File createSymlink(File file, File symlinkDir, String symlinkName) throws Exception { 263 assertTrue(file.exists()); 264 265 File symlink = new File(symlinkDir, symlinkName); 266 Os.symlink(file.getAbsolutePath(), symlink.getAbsolutePath()); 267 testFiles.add(symlink); 268 return symlink; 269 } 270 271 private static void assertCreateSubFileThrows(File parentDir, String name) { 272 try { 273 FileUtils.createSubFile(parentDir, name); 274 fail(); 275 } catch (IOException expected) { 276 assertTrue(expected.getMessage().contains("must exist beneath")); 277 } 278 } 279 280 private static void assertFilesDoNotExist(File... files) { 281 for (File f : files) { 282 assertFalse(f + " unexpectedly exists", f.exists()); 283 } 284 } 285 286 private static void assertFilesExist(File... files) { 287 for (File f : files) { 288 assertTrue(f + " expected to exist", f.exists()); 289 } 290 } 291 292 private static void assertDirExistsAndIsAccessible(File dir, boolean requireWorldReadable) 293 throws Exception { 294 assertTrue(dir.exists() && dir.isDirectory() && dir.canRead() && dir.canExecute()); 295 296 String path = dir.getCanonicalPath(); 297 StructStat sb = Libcore.os.stat(path); 298 int mask = OsConstants.S_IXUSR | OsConstants.S_IRUSR; 299 if (requireWorldReadable) { 300 mask = mask | OsConstants.S_IXGRP | OsConstants.S_IRGRP 301 | OsConstants.S_IXOTH | OsConstants.S_IROTH; 302 } 303 assertTrue("Permission mask required: " + Integer.toOctalString(mask), 304 (sb.st_mode & mask) == mask); 305 } 306 307 private File createTempDir() { 308 final String tempPrefix = getClass().getSimpleName(); 309 File tempDir = IoUtils.createTemporaryDirectory(tempPrefix); 310 testFiles.add(tempDir); 311 return tempDir; 312 } 313 314 private File createDir(File parentDir, String name) { 315 File dir = new File(parentDir, name); 316 assertTrue(dir.mkdir()); 317 testFiles.add(dir); 318 return dir; 319 } 320 321 private File createRegularFile(File dir, String name) throws Exception { 322 File file = new File(dir, name); 323 try (FileOutputStream fos = new FileOutputStream(file)) { 324 fos.write("Hello".getBytes()); 325 } 326 testFiles.add(file); 327 return file; 328 } 329} 330