package org.limewire.util; import java.io.File; import java.io.IOException; import java.util.Properties; import org.limewire.util.SystemUtils.SpecialLocations; import junit.framework.Test; /** * Class for testing the FileUtils utility methods. */ public final class FileUtilsTest extends BaseTestCase { /** * @param name */ public FileUtilsTest(String name) { super(name); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static Test suite() { return buildTestSuite(FileUtilsTest.class); } /** * Tests the method for extracting the file extension from a file. * * @throws Exception if any error occurs. */ public void testGetFileExtension() throws Exception { final String EXT = "ext"; File[] testFiles = new File[] { new File("standard." + EXT), new File("a.little.weird." + EXT), new File(".ext." + EXT), }; for (File testFile : testFiles) { assertEquals("unexpected extension extracted", EXT, FileUtils .getFileExtension(testFile)); } // test files that should return null File[] nullFiles = new File[] { new File("standard."), new File("." + EXT), new File("noextension"), }; for (File nullFile : nullFiles) { assertEquals("extension should be empty string", "", FileUtils .getFileExtension(nullFile)); } } public void testGetFilesRecursive() throws Exception { File tmpFile = File.createTempFile("tmp", "file"); File tmpDir = tmpFile.getParentFile(); tmpFile.delete(); File emptyDir = new File(tmpDir, "emptydir"); File emptyNameDir = new File(tmpDir, "emptyname"); File emptyExtensionDir = new File(tmpDir, "emptyextension"); File recursiveDir = new File(tmpDir, "recursivedir"); emptyDir.mkdir(); emptyNameDir.mkdir(); emptyExtensionDir.mkdir(); recursiveDir.mkdir(); emptyDir.deleteOnExit(); emptyNameDir.deleteOnExit(); emptyExtensionDir.deleteOnExit(); recursiveDir.deleteOnExit(); File subDir = new File(emptyDir, "subdir"); subDir.mkdir(); subDir.deleteOnExit(); File f = new File(emptyNameDir, ".emptyname"); f.createNewFile(); f.deleteOnExit(); f = new File(emptyExtensionDir, "emptyextension."); f.createNewFile(); f.deleteOnExit(); f = new File(recursiveDir, "afile.txt"); f.createNewFile(); f.deleteOnExit(); f = new File(recursiveDir, "subdir"); f.mkdir(); f.deleteOnExit(); f = new File(f, "subfile.txt"); f.createNewFile(); f.deleteOnExit(); File[] fa = FileUtils.getFilesRecursive(emptyDir); assertEquals("directory should have no files, only a subdir", 0, fa.length); fa = FileUtils.getFilesRecursive(emptyNameDir); assertEquals("directory should have 1 hidden file", 1, fa.length); fa = FileUtils.getFilesRecursive(emptyNameDir, new String[] { "emptyname" }); assertEquals("directory should have no file matching extension \"emptyname\"", 0, fa.length); fa = FileUtils.getFilesRecursive(emptyExtensionDir); assertEquals("directory should have one file", 1, fa.length); fa = FileUtils.getFilesRecursive(emptyExtensionDir, new String[] { "" }); assertEquals("directory should have no file matching empty extension", 0, fa.length); // test if files in subdirectories are found too fa = FileUtils.getFilesRecursive(recursiveDir); assertEquals("wrong number of files found", 2, fa.length); // test if files in subdirectories are found with filter fa = FileUtils.getFilesRecursive(recursiveDir, new String[] { "unmatchedextension", "", "txt" }); assertEquals("wrong number of matching files found", 2, fa.length); } /** * Tests the setWriteable method. */ public void testSetWriteable() throws Exception { PrivilegedAccessor.setValue(SystemUtils.class, "isLoaded", Boolean.TRUE); File testFile = File.createTempFile("test", "file"); testFile.deleteOnExit(); testFile.setReadOnly(); assertTrue(testFile.exists()); assertTrue(testFile.isFile()); assertTrue(!FileUtils.canWrite(testFile)); assertTrue("Cannot set file writable: " + testFile, FileUtils.setWriteable(testFile)); assertTrue(FileUtils.canWrite(testFile)); SystemUtils.setWriteable(testFile.getPath()); assertTrue(FileUtils.setWriteable(testFile)); File testDir = new File("directory"); testDir.deleteOnExit(); testDir.mkdirs(); assertTrue(testDir.exists()); assertTrue(testDir.isDirectory()); testDir.setReadOnly(); assertTrue(!FileUtils.canWrite(testDir)); File testInTestDir = new File(testDir, "testDirTest"); testInTestDir.deleteOnExit(); try { testInTestDir.createNewFile(); // This test doesn't work and is not important. // fail("created file in test dir"); } catch (IOException expected) { } assertTrue(FileUtils.setWriteable(testDir)); testInTestDir.delete(); assertTrue(testInTestDir.createNewFile()); assertTrue(FileUtils.canWrite(testDir)); // Make sure it doesn't die if called on a file that doesn't exist File nowhere = new File("m'kay"); assertTrue(!nowhere.exists()); assertTrue(FileUtils.setWriteable(nowhere)); assertTrue(!FileUtils.canWrite(nowhere)); // doesn't exist, can't write. } public void testIsReallyParent() throws Exception { /* Simple benign case */ File testFile = new File("/a/b/c/d.txt"); File testDirectory = new File("/a/b/c"); assertTrue("Simple benign case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Simple malicious case */ testFile = new File("/e/a/b/c/d.txt"); testDirectory = new File("/a/b/c"); assertFalse("Simple malicious case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Benign use of ../ */ testDirectory = new File("/a/b/c"); testFile = new File("/a/b/../b/c/../c/d.txt"); assertTrue("Benign ../ case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Malicious use of ../ */ testDirectory = new File("/a/b/c"); testFile = new File("/a/b/c/../e/d.txt"); assertFalse("Malicious ../ case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Complex benign case */ testDirectory = new File("/a/b/c"); testFile = new File("/a/e/../b/c/d.txt"); assertTrue("Complex benign case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Complex malicious case */ testDirectory = new File("/a/b/c"); testFile = new File("/a/e/../b/c/d.txt"); assertTrue("Complex benign case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Simple relative benign case */ testDirectory = new File("a/b/c"); testFile = new File("a/b/c/d.txt"); assertTrue("Simple relative benign case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Simple relative malicious case */ testDirectory = new File("a/b/c"); testFile = new File("a/e/c/d.txt"); assertFalse("Simple relative malicious case failed.", FileUtils.isReallyParent( testDirectory, testFile)); /* Benign use of ../ in relative paths */ testDirectory = new File("a/b/c"); testFile = new File("a/b/../b/c/../c/d.txt"); assertTrue("Benign use of ../ in relative case failed.", FileUtils.isReallyParent( testDirectory, testFile)); /* Malicious use of ../ in relative paths */ testDirectory = new File("a/b/c"); testFile = new File("a/b/c/../e/d.txt"); assertFalse("Malicious use of ../ in relative case failed.", FileUtils.isReallyParent( testDirectory, testFile)); /* Multi-level benign case */ testDirectory = new File("a/b/c"); testFile = new File("a/b/c/../../../a/b/c/d.txt"); assertTrue("Multi-level benign case failed.", FileUtils.isReallyParent(testDirectory, testFile)); /* Multi-level malicious case */ testDirectory = new File("a/b/c"); testFile = new File("a/b/c/../../../e/b/c/d.txt"); assertFalse("Multi-level malicious case failed.", FileUtils.isReallyParent(testDirectory, testFile)); } public void testReallyInParentPath() throws Exception { File testDirectory; File testFile; testDirectory = new File("a/b/c"); testFile = new File("a/b/c/../../../a/b/c/d/e/f.txt"); assertTrue(FileUtils.isReallyInParentPath(testDirectory, testFile)); testFile = new File("a/b/c/../../../e/b/c/d.txt"); assertFalse(FileUtils.isReallyInParentPath(testDirectory, testFile)); testFile = new File("/"); assertNull(testFile.getParentFile()); assertFalse(FileUtils.isReallyInParentPath(testDirectory, testFile)); } private File createHierarchy() throws IOException { File tmpFile = File.createTempFile("test", "test"); tmpFile.deleteOnExit(); File tmpDir = tmpFile.getParentFile(); File dir = new File(tmpDir, "testRecursiveDeleteDir"); assertTrue(dir.mkdirs()); dir.deleteOnExit(); File hiddenFile = new File(dir, ".hidden"); assertTrue(hiddenFile.createNewFile()); hiddenFile.deleteOnExit(); File file = new File(dir, "file.file"); assertTrue(file.createNewFile()); file.deleteOnExit(); File subDir = new File(dir, "subdir"); assertTrue(subDir.mkdirs()); subDir.deleteOnExit(); File hiddenSubFile = new File(subDir, ".hidden.file"); assertTrue(hiddenSubFile.createNewFile()); hiddenSubFile.deleteOnExit(); File hiddenSubdir = new File(dir, ".hiddenSubdir"); assertTrue(hiddenSubdir.mkdirs()); hiddenSubdir.deleteOnExit(); return dir; } public void testDeleteRecursive() throws IOException { File dir = createHierarchy(); assertTrue(FileUtils.deleteRecursive(dir)); assertFalse(dir.exists()); } public void testForceDeleteRecursive() throws IOException { File dir = createHierarchy(); assertTrue(FileUtils.forceDeleteRecursive(dir)); assertFalse(dir.exists()); } public void testGetJarFromClasspath() throws Exception { assertNull(FileUtils.getJarFromClasspath("does/not/exist")); File file = FileUtils.getJarFromClasspath("org/apache/commons/logging/Log.class"); assertNotNull(file); assertTrue(file.exists()); // there might be version numbers between commons-logging & .jar, so // ignore them. assertTrue(file.getName(), file.getName().startsWith("commons-logging")); assertTrue(file.getName(), file.getName().endsWith(".jar")); } public void testGetJarFromClasspathClassLoader() throws Exception { ClassLoader classLoader = FileUtils.class.getClassLoader(); assertNull(FileUtils.getJarFromClasspath(classLoader, "does/not/exist")); File file = FileUtils.getJarFromClasspath(classLoader, "org/apache/commons/logging/Log.class"); assertNotNull(file); assertTrue(file.exists()); // there might be version numbers between commons-logging & .jar, so // ignore them. assertTrue(file.getName(), file.getName().startsWith("commons-logging")); assertTrue(file.getName(), file.getName().endsWith(".jar")); try { FileUtils.getJarFromClasspath(null, "org/apache/commons/logging/Log.class"); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException expected) { } } public void testReadAndWriteProperties() throws Exception { File path = null; try { // clean up beforehand path = new File("test.props"); if (path.exists()) path.delete(); // make some properties Properties p = new Properties(); p.setProperty("name1", "value1"); p.setProperty("name2", "value2"); p.setProperty("name3", "value3"); // write them to disk FileUtils.writeProperties(path, p); // read them from disk Properties p2 = FileUtils.readProperties(path); // confirm that didn't change them assertTrue(p.equals(p2)); } finally { // clean it up if (path != null) path.delete(); } } public void testResolveSpecialPath() throws Exception { File expected, actual; // current working directory expected = (new File("")).getCanonicalFile(); actual = FileUtils.resolveSpecialPath(""); assertEquals(expected, actual); // current working directory, with subfolders expected = (new File("folder")).getCanonicalFile(); actual = FileUtils.resolveSpecialPath("folder"); assertEquals(expected, actual); expected = (new File("folder/subfolder")).getCanonicalFile(); actual = FileUtils.resolveSpecialPath("folder/subfolder"); assertEquals(expected, actual); // moving up expected = (new File("..")).getCanonicalFile(); actual = FileUtils.resolveSpecialPath(".."); assertEquals(expected, actual); expected = (new File("../folder")).getCanonicalFile(); actual = FileUtils.resolveSpecialPath("../folder"); assertEquals(expected, actual); expected = (new File("../folder/subfolder")).getCanonicalFile(); actual = FileUtils.resolveSpecialPath("../folder/subfolder"); assertEquals(expected, actual); // user's home directory expected = (new File(System.getProperty("user.home"))); actual = FileUtils.resolveSpecialPath("Home>"); assertEquals(expected, actual); expected = (new File(System.getProperty("user.home"), "folder")); actual = FileUtils.resolveSpecialPath("Home>folder"); assertEquals(expected, actual); expected = (new File(System.getProperty("user.home"), "folder/subfolder")); actual = FileUtils.resolveSpecialPath("Home>folder/subfolder"); assertEquals(expected, actual); // platform shell documents directory expected = new File(SystemUtils.getSpecialPath(SpecialLocations.DOCUMENTS)); actual = FileUtils.resolveSpecialPath("Documents>"); assertEquals(expected, actual); expected = new File(SystemUtils.getSpecialPath(SpecialLocations.DOCUMENTS), "folder"); actual = FileUtils.resolveSpecialPath("Documents>folder"); assertEquals(expected, actual); expected = new File(SystemUtils.getSpecialPath(SpecialLocations.DOCUMENTS), "folder/subfolder"); actual = FileUtils.resolveSpecialPath("Documents>folder/subfolder"); assertEquals(expected, actual); // platform shell desktop directory expected = new File(SystemUtils.getSpecialPath(SpecialLocations.DESKTOP)); actual = FileUtils.resolveSpecialPath("Desktop>"); assertEquals(expected, actual); expected = new File(SystemUtils.getSpecialPath(SpecialLocations.DESKTOP), "folder"); actual = FileUtils.resolveSpecialPath("Desktop>folder"); assertEquals(expected, actual); expected = new File(SystemUtils.getSpecialPath(SpecialLocations.DESKTOP), "folder/subfolder"); actual = FileUtils.resolveSpecialPath("Desktop>folder/subfolder"); assertEquals(expected, actual); } public void testMakeFolder() throws Exception { File path = null; try { // clean up beforehand path = new File("testfolder"); if (path.isDirectory()) path.delete(); // make a folder that isn't there FileUtils.makeFolder(path); // confirm it's there now assertTrue(path.isDirectory()); // use the same method to check that it's there FileUtils.makeFolder(path); } finally { // clean it up if (path != null) path.delete(); } } public void testCantMakeFolder() throws Exception { File path = null; try { // write a little properties file path = new File("testfile.props"); Properties p = new Properties(); p.put("hello", "you"); FileUtils.writeProperties(path, p); // we shouldn't be able to make a folder there try { FileUtils.makeFolder(path); fail("expected exception"); } catch (IOException e) { } } finally { // clean it up if (path != null) path.delete(); } } public void testCopyDirectory() throws Exception { File folder = new File("testfolder"); File file = new File("testfolder/test.props"); File subfolder = new File("testfolder/subfolder"); File destinationFolder = new File("testdestination"); File destinationFile = new File("testdestination/test.props"); File destinationSubfolder = new File("testdestination/subfolder"); try { // clean up beforehand copyDirectoryClean(); // make a folder of files folder.mkdir(); file.createNewFile(); subfolder.mkdir(); // copy it to a new location FileUtils.copyDirectory(folder, destinationFolder); // confirm its there assertTrue(destinationFolder.isDirectory()); assertTrue(destinationFile.exists()); assertTrue(destinationSubfolder.isDirectory()); } finally { // clean it up copyDirectoryClean(); } } // Don't use tests as reminders for TODOs, use JIRA. // Otherwise people stop looking at failures as "things gone wrong" // and failures stop being things that are bad (and become things // that are expected and thus ignored). // public void testCopyNonExistingFile() { // File nonexistent = new File("dkfdnslkdfa"); // File tmpDir = new File(System.getProperty("java.io.tmpdir")); // assertTrue(tmpDir.isDirectory()); // assertTrue(!nonexistent.exists()); // // TODO: what's the expected API behavior? return false if file to copy // does not exist // // check usage of return value // assertFalse(FileUtils.copy(nonexistent, new File(tmpDir, // nonexistent.getName()))); // } private void copyDirectoryClean() throws Exception { (new File("testfolder/test.props")).delete(); (new File("testfolder/subfolder")).delete(); (new File("testfolder")).delete(); (new File("testdestination/test.props")).delete(); (new File("testdestination/subfolder")).delete(); (new File("testdestination")).delete(); } }