/*
* Copyright 2017 ThoughtWorks, Inc.
*
* 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 com.thoughtworks.go.util;
import com.googlecode.junit.ext.JunitExtRunner;
import com.googlecode.junit.ext.RunIf;
import com.thoughtworks.go.junitext.EnhancedOSChecker;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import static com.thoughtworks.go.junitext.EnhancedOSChecker.DO_NOT_RUN_ON;
import static com.thoughtworks.go.junitext.EnhancedOSChecker.WINDOWS;
import static com.thoughtworks.go.util.FileUtil.isSubdirectoryOf;
import static com.thoughtworks.go.util.FileUtil.normalizePath;
import static com.thoughtworks.go.util.TestUtils.isEquivalentPathName;
import static com.thoughtworks.go.util.TestUtils.isSameAsPath;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
@RunWith(JunitExtRunner.class)
public class FileUtilTest {
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Before
public void setUp() throws Exception {
temporaryFolder.create();
}
@After
public void tearDown() {
temporaryFolder.delete();
}
@Test
public void shouldReadTillEnd() throws Exception {
String content = "Hello" + FileUtil.lineSeparator() + "World";
File file = temporaryFolder.newFile("foo.txt");
FileUtils.writeStringToFile(file, content, Charset.defaultCharset());
String message = FileUtil.readToEnd(file);
assertThat(message, is(content));
}
@Test
public void shouldWriteContentToFile() throws IOException {
String content = "content";
File targetFile = temporaryFolder.newFile("test1.txt");
FileUtil.writeContentToFile(content, targetFile);
FileInputStream input = new FileInputStream(targetFile);
String actual = IOUtils.toString(input);
assertThat(actual, is(content));
input.close();
targetFile.delete();
}
@Test
public void shouldBeHiddenIfFileStartWithDot() {
assertTrue(FileUtil.isHidden(new File(".svn")));
}
@Test
public void shouldBeHiddenIfFileIsHidden() {
File mockFile = Mockito.mock(File.class);
Mockito.when(mockFile.isHidden()).thenReturn(true);
assertTrue(FileUtil.isHidden(mockFile));
}
@Test
public void shouldReadContentFromFile() throws IOException {
String content = "content";
File targetFile = temporaryFolder.newFile("test1.txt");
FileUtil.writeContentToFile(content, targetFile);
String actual = FileUtil.readContentFromFile(targetFile);
assertThat(actual, is(content));
}
@Test
public void shouldNormailzeFilepaths() throws IOException {
assertThat(normalizePath(new File("foo\\bar")), isEquivalentPathName("foo/bar"));
assertThat(normalizePath(new File("foo\\bar\\")), isEquivalentPathName("foo/bar/"));
assertThat(normalizePath(new File("foo\\bar bar\\")), isEquivalentPathName("foo/bar bar/"));
}
@Test
public void shouldUseSpeficiedFolderIfAbsolute() throws Exception {
final File absolutePath = new File("zx").getAbsoluteFile();
assertThat(FileUtil.applyBaseDirIfRelative(new File("xyz"), absolutePath), is(absolutePath));
}
@Test
public void shouldUseSpeficiedFolderIfBaseDirIsEmpty() throws Exception {
assertThat(FileUtil.applyBaseDirIfRelative(new File(""), new File("zx")), is(new File("zx")));
}
@Test
public void shouldAppendToDefaultIfRelative() throws Exception {
final File relativepath = new File("zx");
assertThat(FileUtil.applyBaseDirIfRelative(new File("xyz"), relativepath),
is(new File("xyz", relativepath.getPath())));
}
@Test
public void shouldUseDefaultIfActualisNull() throws Exception {
final File baseFile = new File("xyz");
assertThat(FileUtil.applyBaseDirIfRelative(baseFile, null), is(baseFile));
}
@Test
public void shouldReturnTrueWhenTwoFolderHasSameStructure() throws Exception {
File root = temporaryFolder.newFolder();
File folder1 = new File(root, "folder1");
folder1.mkdirs();
File file1 = new File(folder1, "readme.txt");
file1.createNewFile();
File folder2 = new File(root, "folder2");
folder2.mkdirs();
File file2 = new File(folder2, "readme.txt");
file2.createNewFile();
assertThat(FileUtil.isStructureSame(folder1, folder2), is(true));
}
@Test
public void shouldReturnFalseWhenTwoFolderHasDifferentStructure() throws Exception {
File root = temporaryFolder.newFolder();
File folder1 = new File(root, "folder1");
folder1.mkdirs();
File file1 = new File(folder1, "readme.txt");
file1.createNewFile();
File folder2 = new File(root, "folder2");
folder2.mkdirs();
File file2 = new File(folder2, "readx.txt");
file2.createNewFile();
assertThat(FileUtil.isStructureSame(folder1, folder2), is(false));
}
@Test
public void shouldCreateUniqueHashForFolders() throws Exception {
File file = new File("c:a/b/c/d/e");
File file2 = new File("c:foo\\bar\\baz");
assertThat(FileUtil.filesystemSafeFileHash(file).matches("[0-9a-zA-Z\\.\\-]*"), is(true));
assertThat(FileUtil.filesystemSafeFileHash(file2), not(FileUtil.filesystemSafeFileHash(file)));
}
@Test
public void shouldDetectSubfolders() throws Exception {
assertThat(isSubdirectoryOf(new File("a"), new File("a")), is(true));
assertThat(isSubdirectoryOf(new File("a"), new File("a/b")), is(true));
assertThat(isSubdirectoryOf(new File("a"), new File("aaaa")), is(false));
assertThat(isSubdirectoryOf(new File("a/b/c/d"), new File("a/b/c/d/e")), is(true));
assertThat(isSubdirectoryOf(new File("a/b/c/d/e"), new File("a/b/c/d")), is(false));
assertThat(isSubdirectoryOf(new File("/a/b"), new File("c/d")), is(false));
}
@Test
public void shouldDetectSubfoldersWhenUsingRelativePaths() throws Exception {
File parent = new File("/a/b");
assertThat(isSubdirectoryOf(parent, new File(parent, "../../..")), is(false));
}
@Test
public void shouldGetFileNameFromLinuxSlash() throws Exception {
assertThat(FileUtil.fileNameFromPath("/consoleout/console.log"), is("console.log"));
}
@Test
public void shouldGetFileNameFromWindowsSlash() throws Exception {
assertThat(FileUtil.fileNameFromPath("\\consoleout\\console.log"), is("console.log"));
}
@Test
public void shouldConvertBytes() {
assertThat(FileUtil.byteCountToDisplaySize(1023), is("1023 bytes"));
}
@Test
public void shouldConvertBytesToKilo() {
assertThat(FileUtil.byteCountToDisplaySize(1024 + 512), is("1.5 KB"));
}
@Test
public void shouldOnlyKeep() {
assertThat(FileUtil.byteCountToDisplaySize(1024 + 512 + 256), is("1.8 KB"));
}
@Test
public void shouldConvertBytesToMega() {
assertThat(FileUtil.byteCountToDisplaySize(1024 * 1024), is("1.0 MB"));
}
@Test
public void shouldConvertBytesToMegaForFloat() {
assertThat(FileUtil.byteCountToDisplaySize(1 * 1024 * 1024 + 512 * 1024), is("1.5 MB"));
}
@Test
public void shouldConvertBytesToGiga() {
long twoGiga = 2L * 1024 * 1024 * 1024 + 512 * 1024 * 1024;
assertThat(FileUtil.byteCountToDisplaySize(twoGiga), is("2.5 GB"));
}
@Test
public void shouldConvertBytesToTB() {
long twoGiga = 2L * 1024 * 1024 * 1024 * 1024 + 512L * 1024 * 1024 * 1024;
assertThat(FileUtil.byteCountToDisplaySize(twoGiga), is("2.5 TB"));
}
@Test
public void shouldConvertBytesToPB() {
long twoGiga = 2L * 1024 * 1024 * 1024 * 1024 * 1024 + 512L * 1024 * 1024 * 1024 * 1024;
assertThat(FileUtil.byteCountToDisplaySize(twoGiga), is("2.5 PB"));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldCreateFileURIForFile() {
assertThat(FileUtil.toFileURI(new File("/var/lib/foo/")), is("file:///var/lib/foo"));
assertThat(FileUtil.toFileURI(new File("/var/a dir with spaces/foo")), is("file:///var/a%20dir%20with%20spaces/foo"));
assertThat(FileUtil.toFileURI(new File("/var/司徒空在此/foo")), is("file:///var/%E5%8F%B8%E5%BE%92%E7%A9%BA%E5%9C%A8%E6%AD%A4/foo"));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {EnhancedOSChecker.WINDOWS})
public void shouldCreateFileURIForFileOnWindows() {
assertThat(FileUtil.toFileURI(new File("c:\\foo")).startsWith("file:///c:/foo"), is(true));
assertThat(FileUtil.toFileURI(new File("c:\\a dir with spaces\\foo")).startsWith("file:///c:/a%20dir%20with%20spaces/foo"), is(true));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {EnhancedOSChecker.WINDOWS})
public void shouldReturnFalseIfGivenFolderIsAbsolute() {
assertThat(FileUtil.isFolderInsideSandbox("c:\\foo"), is(false));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {EnhancedOSChecker.WINDOWS})
public void shouldReturnFalseForInvalidWindowsUNCFilePath() {
assertThat(FileUtil.isAbsolutePath("\\\\host\\"), is(false));
assertThat(FileUtil.isAbsolutePath("\\\\host"), is(false));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {EnhancedOSChecker.WINDOWS})
public void shouldReturnTrueForValidWindowsUNCFilePath() {
assertThat(FileUtil.isAbsolutePath("\\\\host\\share"), is(true));
assertThat(FileUtil.isAbsolutePath("\\\\host\\share\\dir"), is(true));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldReturnFalseIfGivenFolderIsAbsoluteUnderLinux() {
assertThat(FileUtil.isFolderInsideSandbox("/tmp"), is(false));
}
@Test
public void shouldReturnFalseIfGivenFolderWithRelativeTakesYouOutOfSandbox() {
assertThat(FileUtil.isFolderInsideSandbox("../tmp"), is(false));
assertThat(FileUtil.isFolderInsideSandbox("tmp/../../../pavan"), is(false));
}
@Test
public void shouldReturnTrueIfGivenFolderWithRelativeKeepsYouInsideSandbox() {
assertThat(FileUtil.isFolderInsideSandbox("tmp/../home/cruise"), is(true));
}
@Test
public void shouldReturnFalseEvenIfAnAbsolutePathKeepsYouInsideSandbox() {
File file = new File("somethingInsideCurrentFolder");
assertThat(FileUtil.isFolderInsideSandbox(file.getAbsolutePath()), is(false));
}
@Test
public void FolderIsEmptyWhenItHasNoContents() throws Exception {
File folder = temporaryFolder.newFolder("foo");
assertThat(FileUtil.isFolderEmpty(folder), is(true));
}
@Test
public void FolderIsNotEmptyWhenItHasContents() throws Exception {
File folder = temporaryFolder.newFolder("foo");
new File(folder, "subfolder").createNewFile();
assertThat(FileUtil.isFolderEmpty(folder), is(false));
}
@Test
public void shouldReturnCanonicalPath() throws IOException {
File f = temporaryFolder.newFolder();
assertThat(FileUtil.getCanonicalPath(f), is(f.getCanonicalPath()));
File spyFile = spy(new File("/xyz/non-existent-file"));
IOException canonicalPathException = new IOException("Failed to build the canonical path");
stub(spyFile.getCanonicalPath()).toThrow(canonicalPathException);
try {
FileUtil.getCanonicalPath(spyFile);
} catch (RuntimeException e) {
assertThat(e.getCause(), is(canonicalPathException));
}
}
@Test
public void shouldRemoveLeadingFilePathFromAFilePath() throws Exception {
File file = new File("/var/command-repo/default/windows/echo.xml");
File base = new File("/var/command-repo/default");
assertThat(FileUtil.removeLeadingPath(base.getAbsolutePath(), file.getAbsolutePath()), isSameAsPath("/windows/echo.xml"));
assertThat(FileUtil.removeLeadingPath(new File("/var/command-repo/default/").getAbsolutePath(), new File("/var/command-repo/default/windows/echo.xml").getAbsolutePath()), isSameAsPath("/windows/echo.xml"));
assertThat(FileUtil.removeLeadingPath("/some/random/path", "/var/command-repo/default/windows/echo.xml"), is("/var/command-repo/default/windows/echo.xml"));
assertThat(FileUtil.removeLeadingPath(new File("C:/blah").getAbsolutePath(), new File("C:/blah/abcd.txt").getAbsolutePath()), isSameAsPath("/abcd.txt"));
assertThat(FileUtil.removeLeadingPath(new File("C:/blah/").getAbsolutePath(), new File("C:/blah/abcd.txt").getAbsolutePath()), isSameAsPath("/abcd.txt"));
assertThat(FileUtil.removeLeadingPath(null, new File("/blah/abcd.txt").getAbsolutePath()), isSameAsPath(new File("/blah/abcd.txt").getAbsolutePath()));
assertThat(FileUtil.removeLeadingPath("", new File("/blah/abcd.txt").getAbsolutePath()), isSameAsPath(new File("/blah/abcd.txt").getAbsolutePath()));
}
@Test
public void shouldReturnTrueIfDirectoryIsReadable() throws IOException {
File readableDirectory = mock(File.class);
when(readableDirectory.canRead()).thenReturn(true);
when(readableDirectory.canExecute()).thenReturn(true);
when(readableDirectory.listFiles()).thenReturn(new File[]{});
assertThat(FileUtil.isDirectoryReadable(readableDirectory), is(true));
File unreadableDirectory = mock(File.class);
when(readableDirectory.canRead()).thenReturn(false);
when(readableDirectory.canExecute()).thenReturn(false);
assertThat(FileUtil.isDirectoryReadable(unreadableDirectory), is(false));
verify(readableDirectory).canRead();
verify(readableDirectory).canExecute();
verify(readableDirectory).listFiles();
verify(unreadableDirectory).canRead();
verify(unreadableDirectory, never()).canExecute();
}
}