| // Copyright 2014 The Bazel Authors. All rights reserved. | |
| // | |
| // 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.google.devtools.build.lib.vfs; | |
| import static com.google.common.truth.Truth.assertThat; | |
| import static java.nio.charset.StandardCharsets.UTF_8; | |
| import static org.junit.Assert.fail; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.common.io.BaseEncoding; | |
| import com.google.devtools.build.lib.testutil.MoreAsserts; | |
| import com.google.devtools.build.lib.testutil.TestUtils; | |
| import com.google.devtools.build.lib.unix.NativePosixFiles; | |
| import com.google.devtools.build.lib.util.Fingerprint; | |
| import java.io.File; | |
| import java.io.FileNotFoundException; | |
| import java.io.IOException; | |
| import java.io.InputStream; | |
| import java.io.OutputStream; | |
| import java.nio.file.FileAlreadyExistsException; | |
| import java.util.Collection; | |
| import java.util.regex.Matcher; | |
| import java.util.regex.Pattern; | |
| import org.junit.After; | |
| import org.junit.Before; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.Parameterized; | |
| import org.junit.runners.Parameterized.Parameter; | |
| import org.junit.runners.Parameterized.Parameters; | |
| /** | |
| * This class handles the generic tests that any filesystem must pass. | |
| * | |
| * <p>Each filesystem-test should inherit from this class, thereby obtaining | |
| * all the tests. | |
| */ | |
| @RunWith(Parameterized.class) | |
| public abstract class FileSystemTest { | |
| private long savedTime; | |
| protected FileSystem testFS; | |
| protected Path workingDir; | |
| // Some useful examples of various kinds of files (mnemonic: "x" = "eXample") | |
| protected Path xNothing; | |
| protected Path xLink; | |
| protected Path xFile; | |
| protected Path xNonEmptyDirectory; | |
| protected Path xNonEmptyDirectoryFoo; | |
| protected Path xEmptyDirectory; | |
| @Parameters(name = "{index}: digestHashFunction={0}") | |
| public static Collection<DigestHashFunction[]> hashFunctions() { | |
| // TODO(b/112537387): Remove the array-ification and return Collection<DigestHashFunction>. This | |
| // is possible in Junit4.12, but 4.11 requires the array. Bazel 0.18 will have Junit4.12, so | |
| // this can change then. | |
| return DigestHashFunction.getPossibleHashFunctions() | |
| .stream() | |
| .map(dhf -> new DigestHashFunction[] {dhf}) | |
| .collect(ImmutableList.toImmutableList()); | |
| } | |
| @Parameter public DigestHashFunction digestHashFunction; | |
| @Before | |
| public final void createDirectories() throws Exception { | |
| testFS = getFreshFileSystem(digestHashFunction); | |
| workingDir = testFS.getPath(getTestTmpDir()); | |
| cleanUpWorkingDirectory(workingDir); | |
| // % ls -lR | |
| // -rw-rw-r-- xFile | |
| // drwxrwxr-x xNonEmptyDirectory | |
| // -rw-rw-r-- xNonEmptyDirectory/foo | |
| // drwxrwxr-x xEmptyDirectory | |
| xNothing = absolutize("xNothing"); | |
| xLink = absolutize("xLink"); | |
| xFile = absolutize("xFile"); | |
| xNonEmptyDirectory = absolutize("xNonEmptyDirectory"); | |
| xNonEmptyDirectoryFoo = xNonEmptyDirectory.getChild("foo"); | |
| xEmptyDirectory = absolutize("xEmptyDirectory"); | |
| FileSystemUtils.createEmptyFile(xFile); | |
| xNonEmptyDirectory.createDirectory(); | |
| FileSystemUtils.createEmptyFile(xNonEmptyDirectoryFoo); | |
| xEmptyDirectory.createDirectory(); | |
| } | |
| @After | |
| public final void destroyFileSystem() throws Exception { | |
| destroyFileSystem(testFS); | |
| } | |
| /** | |
| * Returns an instance of the file system to test. | |
| */ | |
| protected abstract FileSystem getFreshFileSystem(DigestHashFunction digestHashFunction) | |
| throws IOException; | |
| protected boolean isSymbolicLink(File file) { | |
| return NativePosixFiles.isSymbolicLink(file); | |
| } | |
| protected void setWritable(File file) throws IOException { | |
| NativePosixFiles.setWritable(file); | |
| } | |
| protected void setExecutable(File file) throws IOException { | |
| NativePosixFiles.setExecutable(file); | |
| } | |
| private static final Pattern STAT_SUBDIR_ERROR = Pattern.compile("(.*) \\(Not a directory\\)"); | |
| // Test that file is not present, using statIfFound. Base implementation throws an exception, but | |
| // subclasses may override statIfFound to return null, in which case their tests should override | |
| // this method. | |
| @SuppressWarnings("unused") // Subclasses may throw. | |
| protected void expectNotFound(Path path) throws IOException { | |
| try { | |
| assertThat(path.statIfFound()).isNull(); | |
| } catch (IOException e) { | |
| // May be because of a non-directory path component. Parse exception to check this. | |
| Matcher matcher = STAT_SUBDIR_ERROR.matcher(e.getMessage()); | |
| if (!matcher.matches() || !path.getPathString().startsWith(matcher.group(1))) { | |
| // Throw if this doesn't match what an ENOTDIR error looks like. | |
| throw e; | |
| } | |
| } | |
| } | |
| /** | |
| * Removes all stuff from the test filesystem. | |
| */ | |
| protected void destroyFileSystem(FileSystem fileSystem) throws IOException { | |
| Preconditions.checkArgument(fileSystem.equals(workingDir.getFileSystem())); | |
| cleanUpWorkingDirectory(workingDir); | |
| } | |
| /** | |
| * Cleans up the working directory by removing everything. | |
| */ | |
| protected void cleanUpWorkingDirectory(Path workingPath) | |
| throws IOException { | |
| if (workingPath.exists()) { | |
| removeEntireDirectory(workingPath.getPathFile()); // uses java.io.File! | |
| } | |
| workingPath.createDirectoryAndParents(); | |
| } | |
| /** | |
| * This function removes an entire directory and all of its contents. | |
| * Much like rm -rf directoryToRemove | |
| */ | |
| protected void removeEntireDirectory(File directoryToRemove) | |
| throws IOException { | |
| // make sure that we do not remove anything outside the test directory | |
| Path testDirPath = testFS.getPath(getTestTmpDir()); | |
| if (!testFS.getPath(directoryToRemove.getAbsolutePath()).startsWith(testDirPath)) { | |
| throw new IOException("trying to remove files outside of the testdata directory"); | |
| } | |
| // Some tests set the directories read-only and/or non-executable, so | |
| // override that: | |
| setWritable(directoryToRemove); | |
| setExecutable(directoryToRemove); | |
| File[] files = directoryToRemove.listFiles(); | |
| if (files != null) { | |
| for (File currentFile : files) { | |
| boolean isSymbolicLink = isSymbolicLink(currentFile); | |
| if (!isSymbolicLink && currentFile.isDirectory()) { | |
| removeEntireDirectory(currentFile); | |
| } else { | |
| if (!isSymbolicLink) { | |
| setWritable(currentFile); | |
| } | |
| if (!currentFile.delete()) { | |
| throw new IOException("Failed to delete '" + currentFile + "'"); | |
| } | |
| } | |
| } | |
| } | |
| if (!directoryToRemove.delete()) { | |
| throw new IOException("Failed to delete '" + directoryToRemove + "'"); | |
| } | |
| } | |
| /** | |
| * Returns the directory to use as the FileSystem's working directory. | |
| * Canonicalized to make tests hermetic against symbolic links in TEST_TMPDIR. | |
| */ | |
| protected final String getTestTmpDir() throws IOException { | |
| return new File(TestUtils.tmpDir()).getCanonicalPath() + "/testdir"; | |
| } | |
| /** | |
| * Indirection to create links so we can test FileSystems that do not support | |
| * link creation. For example, JavaFileSystemTest overrides this method | |
| * and creates the link with an alternate FileSystem. | |
| */ | |
| protected void createSymbolicLink(Path link, Path target) throws IOException { | |
| createSymbolicLink(link, target.asFragment()); | |
| } | |
| /** | |
| * Indirection to create links so we can test FileSystems that do not support | |
| * link creation. For example, JavaFileSystemTest overrides this method | |
| * and creates the link with an alternate FileSystem. | |
| */ | |
| protected void createSymbolicLink(Path link, PathFragment target) throws IOException { | |
| link.createSymbolicLink(target); | |
| } | |
| /** | |
| * Indirection to setReadOnly(false) on FileSystems that do not | |
| * support setReadOnly(false). For example, JavaFileSystemTest overrides this | |
| * method and makes the Path writable with an alternate FileSystem. | |
| */ | |
| protected void makeWritable(Path target) throws IOException { | |
| target.setWritable(true); | |
| } | |
| /** | |
| * Indirection to {@link Path#setExecutable(boolean)} on FileSystems that do | |
| * not support setExecutable. For example, JavaFileSystemTest overrides this | |
| * method and makes the Path executable with an alternate FileSystem. | |
| */ | |
| protected void setExecutable(Path target, boolean mode) throws IOException { | |
| target.setExecutable(mode); | |
| } | |
| // TODO(bazel-team): (2011) Put in a setLastModifiedTime into the various objects | |
| // and clobber the current time of the object we're currently handling. | |
| // Otherwise testing the thing might get a little hard, depending on the clock. | |
| void storeReferenceTime(long timeToMark) { | |
| savedTime = timeToMark; | |
| } | |
| boolean isLaterThanreferenceTime(long testTime) { | |
| return (savedTime <= testTime); | |
| } | |
| protected Path absolutize(String relativePathName) { | |
| return workingDir.getRelative(relativePathName); | |
| } | |
| // Here the tests begin. | |
| @Test | |
| public void testIsFileForNonexistingPath() { | |
| Path nonExistingPath = testFS.getPath("/something/strange"); | |
| assertThat(nonExistingPath.isFile()).isFalse(); | |
| } | |
| @Test | |
| public void testIsDirectoryForNonexistingPath() { | |
| Path nonExistingPath = testFS.getPath("/something/strange"); | |
| assertThat(nonExistingPath.isDirectory()).isFalse(); | |
| } | |
| @Test | |
| public void testIsLinkForNonexistingPath() { | |
| Path nonExistingPath = testFS.getPath("/something/strange"); | |
| assertThat(nonExistingPath.isSymbolicLink()).isFalse(); | |
| } | |
| @Test | |
| public void testExistsForNonexistingPath() throws Exception { | |
| Path nonExistingPath = testFS.getPath("/something/strange"); | |
| assertThat(nonExistingPath.exists()).isFalse(); | |
| expectNotFound(nonExistingPath); | |
| } | |
| @Test | |
| public void testBadPermissionsThrowsExceptionOnStatIfFound() throws Exception { | |
| Path inaccessible = absolutize("inaccessible"); | |
| inaccessible.createDirectory(); | |
| Path child = inaccessible.getChild("child"); | |
| FileSystemUtils.createEmptyFile(child); | |
| inaccessible.setExecutable(false); | |
| assertThat(child.exists()).isFalse(); | |
| try { | |
| child.statIfFound(); | |
| fail(); | |
| } catch (IOException expected) { | |
| // Expected. | |
| } | |
| } | |
| @Test | |
| public void testStatIfFoundReturnsNullForChildOfNonDir() throws Exception { | |
| Path foo = absolutize("foo"); | |
| foo.createDirectory(); | |
| Path nonDir = foo.getRelative("bar"); | |
| FileSystemUtils.createEmptyFile(nonDir); | |
| assertThat(nonDir.getRelative("file").statIfFound()).isNull(); | |
| } | |
| // The following tests check the handling of the current working directory. | |
| @Test | |
| public void testCreatePathRelativeToWorkingDirectory() { | |
| Path relativeCreatedPath = absolutize("some-file"); | |
| Path expectedResult = workingDir.getRelative(PathFragment.create("some-file")); | |
| assertThat(relativeCreatedPath).isEqualTo(expectedResult); | |
| } | |
| // The following tests check the handling of the root directory | |
| @Test | |
| public void testRootIsDirectory() { | |
| Path rootPath = testFS.getPath("/"); | |
| assertThat(rootPath.isDirectory()).isTrue(); | |
| } | |
| @Test | |
| public void testRootHasNoParent() { | |
| Path rootPath = testFS.getPath("/"); | |
| assertThat(rootPath.getParentDirectory()).isNull(); | |
| } | |
| // The following functions test the creation of files/links/directories. | |
| @Test | |
| public void testFileExists() throws Exception { | |
| Path someFile = absolutize("some-file"); | |
| FileSystemUtils.createEmptyFile(someFile); | |
| assertThat(someFile.exists()).isTrue(); | |
| assertThat(someFile.statIfFound()).isNotNull(); | |
| } | |
| @Test | |
| public void testFileIsFile() throws Exception { | |
| Path someFile = absolutize("some-file"); | |
| FileSystemUtils.createEmptyFile(someFile); | |
| assertThat(someFile.isFile()).isTrue(); | |
| } | |
| @Test | |
| public void testFileIsNotDirectory() throws Exception { | |
| Path someFile = absolutize("some-file"); | |
| FileSystemUtils.createEmptyFile(someFile); | |
| assertThat(someFile.isDirectory()).isFalse(); | |
| } | |
| @Test | |
| public void testFileIsNotSymbolicLink() throws Exception { | |
| Path someFile = absolutize("some-file"); | |
| FileSystemUtils.createEmptyFile(someFile); | |
| assertThat(someFile.isSymbolicLink()).isFalse(); | |
| } | |
| @Test | |
| public void testDirectoryExists() throws Exception { | |
| Path someDirectory = absolutize("some-dir"); | |
| someDirectory.createDirectory(); | |
| assertThat(someDirectory.exists()).isTrue(); | |
| assertThat(someDirectory.statIfFound()).isNotNull(); | |
| } | |
| @Test | |
| public void testDirectoryIsDirectory() throws Exception { | |
| Path someDirectory = absolutize("some-dir"); | |
| someDirectory.createDirectory(); | |
| assertThat(someDirectory.isDirectory()).isTrue(); | |
| } | |
| @Test | |
| public void testDirectoryIsNotFile() throws Exception { | |
| Path someDirectory = absolutize("some-dir"); | |
| someDirectory.createDirectory(); | |
| assertThat(someDirectory.isFile()).isFalse(); | |
| } | |
| @Test | |
| public void testDirectoryIsNotSymbolicLink() throws Exception { | |
| Path someDirectory = absolutize("some-dir"); | |
| someDirectory.createDirectory(); | |
| assertThat(someDirectory.isSymbolicLink()).isFalse(); | |
| } | |
| @Test | |
| public void testSymbolicFileLinkExists() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xFile); | |
| assertThat(someLink.exists()).isTrue(); | |
| assertThat(someLink.statIfFound()).isNotNull(); | |
| } | |
| } | |
| @Test | |
| public void testSymbolicFileLinkIsSymbolicLink() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xFile); | |
| assertThat(someLink.isSymbolicLink()).isTrue(); | |
| } | |
| } | |
| @Test | |
| public void testSymbolicFileLinkIsFile() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xFile); | |
| assertThat(someLink.isFile()).isTrue(); | |
| } | |
| } | |
| @Test | |
| public void testSymbolicFileLinkIsNotDirectory() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xFile); | |
| assertThat(someLink.isDirectory()).isFalse(); | |
| } | |
| } | |
| @Test | |
| public void testSymbolicDirLinkExists() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xEmptyDirectory); | |
| assertThat(someLink.exists()).isTrue(); | |
| assertThat(someLink.statIfFound()).isNotNull(); | |
| } | |
| } | |
| @Test | |
| public void testSymbolicDirLinkIsSymbolicLink() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xEmptyDirectory); | |
| assertThat(someLink.isSymbolicLink()).isTrue(); | |
| } | |
| } | |
| @Test | |
| public void testSymbolicDirLinkIsDirectory() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xEmptyDirectory); | |
| assertThat(someLink.isDirectory()).isTrue(); | |
| } | |
| } | |
| @Test | |
| public void testSymbolicDirLinkIsNotFile() throws Exception { | |
| Path someLink = absolutize("some-link"); | |
| if (testFS.supportsSymbolicLinksNatively(someLink)) { | |
| someLink.createSymbolicLink(xEmptyDirectory); | |
| assertThat(someLink.isFile()).isFalse(); | |
| } | |
| } | |
| @Test | |
| public void testChildOfNonDirectory() throws Exception { | |
| Path somePath = absolutize("file-name"); | |
| FileSystemUtils.createEmptyFile(somePath); | |
| Path childOfNonDir = somePath.getChild("child"); | |
| assertThat(childOfNonDir.exists()).isFalse(); | |
| expectNotFound(childOfNonDir); | |
| } | |
| @Test | |
| public void testCreateDirectoryIsEmpty() throws Exception { | |
| Path newPath = xEmptyDirectory.getChild("new-dir"); | |
| newPath.createDirectory(); | |
| assertThat(newPath.getDirectoryEntries()).isEmpty(); | |
| } | |
| @Test | |
| public void testCreateDirectoryIsOnlyChildInParent() throws Exception { | |
| Path newPath = xEmptyDirectory.getChild("new-dir"); | |
| newPath.createDirectory(); | |
| assertThat(newPath.getParentDirectory().getDirectoryEntries()).hasSize(1); | |
| assertThat(newPath.getParentDirectory().getDirectoryEntries()).containsExactly(newPath); | |
| } | |
| @Test | |
| public void testCreateDirectoryAndParents() throws Exception { | |
| Path newPath = absolutize("new-dir/sub/directory"); | |
| newPath.createDirectoryAndParents(); | |
| assertThat(newPath.isDirectory()).isTrue(); | |
| } | |
| @Test | |
| public void testCreateDirectoryAndParentsCreatesEmptyDirectory() throws Exception { | |
| Path newPath = absolutize("new-dir/sub/directory"); | |
| newPath.createDirectoryAndParents(); | |
| assertThat(newPath.getDirectoryEntries()).isEmpty(); | |
| } | |
| @Test | |
| public void testCreateDirectoryAndParentsIsOnlyChildInParent() throws Exception { | |
| Path newPath = absolutize("new-dir/sub/directory"); | |
| newPath.createDirectoryAndParents(); | |
| assertThat(newPath.getParentDirectory().getDirectoryEntries()).hasSize(1); | |
| assertThat(newPath.getParentDirectory().getDirectoryEntries()).containsExactly(newPath); | |
| } | |
| @Test | |
| public void testCreateDirectoryAndParentsWhenAlreadyExistsSucceeds() throws Exception { | |
| Path newPath = absolutize("new-dir"); | |
| newPath.createDirectory(); | |
| newPath.createDirectoryAndParents(); | |
| assertThat(newPath.isDirectory()).isTrue(); | |
| } | |
| @Test | |
| public void testCreateDirectoryAndParentsWhenAncestorIsFile() throws IOException { | |
| Path path = absolutize("somewhere/deep/in"); | |
| path.getParentDirectory().createDirectoryAndParents(); | |
| FileSystemUtils.createEmptyFile(path); | |
| Path theHierarchy = path.getChild("the-hierarchy"); | |
| MoreAsserts.assertThrows(IOException.class, theHierarchy::createDirectoryAndParents); | |
| } | |
| @Test | |
| public void testCreateDirectoryAndParentsWhenSymlinkToDir() throws IOException { | |
| Path somewhereDeepIn = absolutize("somewhere/deep/in"); | |
| somewhereDeepIn.createDirectoryAndParents(); | |
| Path realDir = absolutize("real/dir"); | |
| realDir.createDirectoryAndParents(); | |
| assertThat(realDir.isDirectory()).isTrue(); | |
| Path theHierarchy = somewhereDeepIn.getChild("the-hierarchy"); | |
| theHierarchy.createSymbolicLink(realDir); | |
| assertThat(theHierarchy.isDirectory()).isTrue(); | |
| theHierarchy.createDirectoryAndParents(); | |
| } | |
| @Test | |
| public void testCreateDirectoryAndParentsWhenSymlinkEmbedded() throws IOException { | |
| Path somewhereDeepIn = absolutize("somewhere/deep/in"); | |
| somewhereDeepIn.createDirectoryAndParents(); | |
| Path realDir = absolutize("real/dir"); | |
| realDir.createDirectoryAndParents(); | |
| Path the = somewhereDeepIn.getChild("the"); | |
| the.createSymbolicLink(realDir); | |
| Path theHierarchy = somewhereDeepIn.getChild("hierarchy"); | |
| theHierarchy.createDirectoryAndParents(); | |
| } | |
| @Test | |
| public void testCreateDirectoryAtFileFails() throws Exception { | |
| Path newPath = absolutize("file"); | |
| FileSystemUtils.createEmptyFile(newPath); | |
| MoreAsserts.assertThrows(IOException.class, newPath::createDirectoryAndParents); | |
| } | |
| @Test | |
| public void testCreateEmptyFileIsEmpty() throws Exception { | |
| Path newPath = xEmptyDirectory.getChild("new-file"); | |
| FileSystemUtils.createEmptyFile(newPath); | |
| assertThat(newPath.getFileSize()).isEqualTo(0); | |
| } | |
| @Test | |
| public void testCreateFileIsOnlyChildInParent() throws Exception { | |
| Path newPath = xEmptyDirectory.getChild("new-file"); | |
| FileSystemUtils.createEmptyFile(newPath); | |
| assertThat(newPath.getParentDirectory().getDirectoryEntries()).hasSize(1); | |
| assertThat(newPath.getParentDirectory().getDirectoryEntries()).containsExactly(newPath); | |
| } | |
| // The following functions test the behavior if errors occur during the | |
| // creation of files/links/directories. | |
| @Test | |
| public void testCreateDirectoryWhereDirectoryAlreadyExists() throws Exception { | |
| assertThat(xEmptyDirectory.createDirectory()).isFalse(); | |
| } | |
| @Test | |
| public void testCreateDirectoryWhereFileAlreadyExists() { | |
| try { | |
| xFile.createDirectory(); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xFile + " (File exists)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateDirectoryWithoutExistingParent() throws Exception { | |
| Path newPath = testFS.getPath("/deep/new-dir"); | |
| try { | |
| newPath.createDirectory(); | |
| fail(); | |
| } catch (FileNotFoundException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (No such file or directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateDirectoryWithReadOnlyParent() throws Exception { | |
| xEmptyDirectory.setWritable(false); | |
| Path xChildOfReadonlyDir = xEmptyDirectory.getChild("x"); | |
| try { | |
| xChildOfReadonlyDir.createDirectory(); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xChildOfReadonlyDir + " (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateFileWithoutExistingParent() throws Exception { | |
| Path newPath = testFS.getPath("/non-existing-dir/new-file"); | |
| try { | |
| FileSystemUtils.createEmptyFile(newPath); | |
| fail(); | |
| } catch (FileNotFoundException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (No such file or directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateFileWithReadOnlyParent() throws Exception { | |
| xEmptyDirectory.setWritable(false); | |
| Path xChildOfReadonlyDir = xEmptyDirectory.getChild("x"); | |
| try { | |
| FileSystemUtils.createEmptyFile(xChildOfReadonlyDir); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xChildOfReadonlyDir + " (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateFileWithinFile() throws Exception { | |
| Path newFilePath = absolutize("some-file"); | |
| FileSystemUtils.createEmptyFile(newFilePath); | |
| Path wrongPath = absolutize("some-file/new-file"); | |
| try { | |
| FileSystemUtils.createEmptyFile(wrongPath); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (Not a directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateDirectoryWithinFile() throws Exception { | |
| Path newFilePath = absolutize("some-file"); | |
| FileSystemUtils.createEmptyFile(newFilePath); | |
| Path wrongPath = absolutize("some-file/new-file"); | |
| try { | |
| wrongPath.createDirectory(); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (Not a directory)"); | |
| } | |
| } | |
| // Test directory contents | |
| @Test | |
| public void testCreateMultipleChildren() throws Exception { | |
| Path theDirectory = absolutize("foo/"); | |
| theDirectory.createDirectory(); | |
| Path newPath1 = absolutize("foo/new-file-1"); | |
| Path newPath2 = absolutize("foo/new-file-2"); | |
| Path newPath3 = absolutize("foo/new-file-3"); | |
| FileSystemUtils.createEmptyFile(newPath1); | |
| FileSystemUtils.createEmptyFile(newPath2); | |
| FileSystemUtils.createEmptyFile(newPath3); | |
| assertThat(theDirectory.getDirectoryEntries()).containsExactly(newPath1, newPath2, newPath3); | |
| } | |
| @Test | |
| public void testGetDirectoryEntriesThrowsExceptionWhenRunOnFile() throws Exception { | |
| try { | |
| xFile.getDirectoryEntries(); | |
| fail("No Exception thrown."); | |
| } catch (IOException ex) { | |
| if (ex instanceof FileNotFoundException) { | |
| fail("The method should throw an object of class IOException."); | |
| } | |
| assertThat(ex).hasMessage(xFile + " (Not a directory)"); | |
| } | |
| } | |
| @Test | |
| public void testGetDirectoryEntriesThrowsExceptionForNonexistingPath() { | |
| Path somePath = testFS.getPath("/non-existing-path"); | |
| try { | |
| somePath.getDirectoryEntries(); | |
| fail("FileNotFoundException not thrown."); | |
| } catch (Exception x) { | |
| assertThat(x).hasMessage(somePath + " (No such file or directory)"); | |
| } | |
| } | |
| // Test the removal of items | |
| @Test | |
| public void testDeleteDirectory() throws Exception { | |
| assertThat(xEmptyDirectory.delete()).isTrue(); | |
| } | |
| @Test | |
| public void testDeleteDirectoryIsNotDirectory() throws Exception { | |
| xEmptyDirectory.delete(); | |
| assertThat(xEmptyDirectory.isDirectory()).isFalse(); | |
| } | |
| @Test | |
| public void testDeleteDirectoryParentSize() throws Exception { | |
| int parentSize = workingDir.getDirectoryEntries().size(); | |
| xEmptyDirectory.delete(); | |
| assertThat(parentSize - 1).isEqualTo(workingDir.getDirectoryEntries().size()); | |
| } | |
| @Test | |
| public void testDeleteFile() throws Exception { | |
| assertThat(xFile.delete()).isTrue(); | |
| } | |
| @Test | |
| public void testDeleteFileIsNotFile() throws Exception { | |
| xFile.delete(); | |
| assertThat(xEmptyDirectory.isFile()).isFalse(); | |
| } | |
| @Test | |
| public void testDeleteFileParentSize() throws Exception { | |
| int parentSize = workingDir.getDirectoryEntries().size(); | |
| xFile.delete(); | |
| assertThat(parentSize - 1).isEqualTo(workingDir.getDirectoryEntries().size()); | |
| } | |
| @Test | |
| public void testDeleteRemovesCorrectFile() throws Exception { | |
| Path newPath1 = xEmptyDirectory.getChild("new-file-1"); | |
| Path newPath2 = xEmptyDirectory.getChild("new-file-2"); | |
| Path newPath3 = xEmptyDirectory.getChild("new-file-3"); | |
| FileSystemUtils.createEmptyFile(newPath1); | |
| FileSystemUtils.createEmptyFile(newPath2); | |
| FileSystemUtils.createEmptyFile(newPath3); | |
| assertThat(newPath2.delete()).isTrue(); | |
| assertThat(xEmptyDirectory.getDirectoryEntries()).containsExactly(newPath1, newPath3); | |
| } | |
| @Test | |
| public void testDeleteNonExistingDir() throws Exception { | |
| Path path = xEmptyDirectory.getRelative("non-existing-dir"); | |
| assertThat(path.delete()).isFalse(); | |
| } | |
| @Test | |
| public void testDeleteNotADirectoryPath() throws Exception { | |
| Path path = xFile.getChild("new-file"); | |
| assertThat(path.delete()).isFalse(); | |
| } | |
| // Here we test the situations where delete should throw exceptions. | |
| @Test | |
| public void testDeleteNonEmptyDirectoryThrowsException() throws Exception { | |
| try { | |
| xNonEmptyDirectory.delete(); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xNonEmptyDirectory + " (Directory not empty)"); | |
| } | |
| } | |
| @Test | |
| public void testDeleteNonEmptyDirectoryNotDeletedDirectory() throws Exception { | |
| try { | |
| xNonEmptyDirectory.delete(); | |
| fail(); | |
| } catch (IOException e) { | |
| // Expected | |
| } | |
| assertThat(xNonEmptyDirectory.isDirectory()).isTrue(); | |
| } | |
| @Test | |
| public void testDeleteNonEmptyDirectoryNotDeletedFile() throws Exception { | |
| try { | |
| xNonEmptyDirectory.delete(); | |
| fail(); | |
| } catch (IOException e) { | |
| // Expected | |
| } | |
| assertThat(xNonEmptyDirectoryFoo.isFile()).isTrue(); | |
| } | |
| // Test the date functions | |
| @Test | |
| public void testCreateFileChangesTimeOfDirectory() throws Exception { | |
| storeReferenceTime(workingDir.getLastModifiedTime()); | |
| Path newPath = absolutize("new-file"); | |
| FileSystemUtils.createEmptyFile(newPath); | |
| assertThat(isLaterThanreferenceTime(workingDir.getLastModifiedTime())).isTrue(); | |
| } | |
| @Test | |
| public void testRemoveFileChangesTimeOfDirectory() throws Exception { | |
| Path newPath = absolutize("new-file"); | |
| FileSystemUtils.createEmptyFile(newPath); | |
| storeReferenceTime(workingDir.getLastModifiedTime()); | |
| newPath.delete(); | |
| assertThat(isLaterThanreferenceTime(workingDir.getLastModifiedTime())).isTrue(); | |
| } | |
| // This test is a little bit strange, as we cannot test the progression | |
| // of the time directly. As the Java time and the OS time are slightly different. | |
| // Therefore, we first create an unrelated file to get a notion | |
| // of the current OS time and use that as a baseline. | |
| @Test | |
| public void testCreateFileTimestamp() throws Exception { | |
| Path syncFile = absolutize("sync-file"); | |
| FileSystemUtils.createEmptyFile(syncFile); | |
| Path newFile = absolutize("new-file"); | |
| storeReferenceTime(syncFile.getLastModifiedTime()); | |
| FileSystemUtils.createEmptyFile(newFile); | |
| assertThat(isLaterThanreferenceTime(newFile.getLastModifiedTime())).isTrue(); | |
| } | |
| @Test | |
| public void testCreateDirectoryTimestamp() throws Exception { | |
| Path syncFile = absolutize("sync-file"); | |
| FileSystemUtils.createEmptyFile(syncFile); | |
| Path newPath = absolutize("new-dir"); | |
| storeReferenceTime(syncFile.getLastModifiedTime()); | |
| assertThat(newPath.createDirectory()).isTrue(); | |
| assertThat(isLaterThanreferenceTime(newPath.getLastModifiedTime())).isTrue(); | |
| } | |
| @Test | |
| public void testWriteChangesModifiedTime() throws Exception { | |
| storeReferenceTime(xFile.getLastModifiedTime()); | |
| FileSystemUtils.writeContentAsLatin1(xFile, "abc19"); | |
| assertThat(isLaterThanreferenceTime(xFile.getLastModifiedTime())).isTrue(); | |
| } | |
| @Test | |
| public void testGetLastModifiedTimeThrowsExceptionForNonexistingPath() throws Exception { | |
| Path newPath = testFS.getPath("/non-existing-dir"); | |
| try { | |
| newPath.getLastModifiedTime(); | |
| fail("FileNotFoundException not thrown!"); | |
| } catch (FileNotFoundException x) { | |
| assertThat(x).hasMessage(newPath + " (No such file or directory)"); | |
| } | |
| } | |
| // Test file size | |
| @Test | |
| public void testFileSizeThrowsExceptionForNonexistingPath() throws Exception { | |
| Path newPath = testFS.getPath("/non-existing-file"); | |
| try { | |
| newPath.getFileSize(); | |
| fail("FileNotFoundException not thrown."); | |
| } catch (FileNotFoundException e) { | |
| assertThat(e).hasMessage(newPath + " (No such file or directory)"); | |
| } | |
| } | |
| @Test | |
| public void testFileSizeAfterWrite() throws Exception { | |
| String testData = "abc19"; | |
| FileSystemUtils.writeContentAsLatin1(xFile, testData); | |
| assertThat(xFile.getFileSize()).isEqualTo(testData.length()); | |
| } | |
| // Testing the input/output routines | |
| @Test | |
| public void testFileWriteAndReadAsLatin1() throws Exception { | |
| String testData = "abc19"; | |
| FileSystemUtils.writeContentAsLatin1(xFile, testData); | |
| String resultData = new String(FileSystemUtils.readContentAsLatin1(xFile)); | |
| assertThat(resultData).isEqualTo(testData); | |
| } | |
| @Test | |
| public void testInputAndOutputStreamEOF() throws Exception { | |
| try (OutputStream outStream = xFile.getOutputStream()) { | |
| outStream.write(1); | |
| } | |
| try (InputStream inStream = xFile.getInputStream()) { | |
| inStream.read(); | |
| assertThat(inStream.read()).isEqualTo(-1); | |
| } | |
| } | |
| @Test | |
| public void testInputAndOutputStream() throws Exception { | |
| try (OutputStream outStream = xFile.getOutputStream()) { | |
| for (int i = 33; i < 126; i++) { | |
| outStream.write(i); | |
| } | |
| } | |
| try (InputStream inStream = xFile.getInputStream()) { | |
| for (int i = 33; i < 126; i++) { | |
| int readValue = inStream.read(); | |
| assertThat(readValue).isEqualTo(i); | |
| } | |
| } | |
| } | |
| @Test | |
| public void testInputAndOutputStreamAppend() throws Exception { | |
| try (OutputStream outStream = xFile.getOutputStream()) { | |
| for (int i = 33; i < 126; i++) { | |
| outStream.write(i); | |
| } | |
| } | |
| try (OutputStream appendOut = xFile.getOutputStream(true)) { | |
| for (int i = 126; i < 155; i++) { | |
| appendOut.write(i); | |
| } | |
| } | |
| try (InputStream inStream = xFile.getInputStream()) { | |
| for (int i = 33; i < 155; i++) { | |
| int readValue = inStream.read(); | |
| assertThat(readValue).isEqualTo(i); | |
| } | |
| } | |
| } | |
| @Test | |
| public void testInputAndOutputStreamNoAppend() throws Exception { | |
| try (OutputStream outStream = xFile.getOutputStream()) { | |
| outStream.write(1); | |
| } | |
| try (OutputStream noAppendOut = xFile.getOutputStream(false)) { | |
| } | |
| try (InputStream inStream = xFile.getInputStream()) { | |
| assertThat(inStream.read()).isEqualTo(-1); | |
| } | |
| } | |
| @Test | |
| public void testGetOutputStreamCreatesFile() throws Exception { | |
| Path newFile = absolutize("does_not_exist_yet.txt"); | |
| try (OutputStream out = newFile.getOutputStream()) { | |
| out.write(42); | |
| } | |
| assertThat(newFile.isFile()).isTrue(); | |
| } | |
| @Test | |
| public void testOutputStreamThrowExceptionOnDirectory() throws Exception { | |
| try { | |
| xEmptyDirectory.getOutputStream(); | |
| fail("The Exception was not thrown!"); | |
| } catch (IOException ex) { | |
| assertThat(ex).hasMessage(xEmptyDirectory + " (Is a directory)"); | |
| } | |
| } | |
| @Test | |
| public void testInputStreamThrowExceptionOnDirectory() throws Exception { | |
| try { | |
| xEmptyDirectory.getInputStream(); | |
| fail("The Exception was not thrown!"); | |
| } catch (IOException ex) { | |
| assertThat(ex).hasMessage(xEmptyDirectory + " (Is a directory)"); | |
| } | |
| } | |
| // Test renaming | |
| @Test | |
| public void testCanRenameToUnusedName() throws Exception { | |
| xFile.renameTo(xNothing); | |
| assertThat(xFile.exists()).isFalse(); | |
| assertThat(xNothing.isFile()).isTrue(); | |
| } | |
| @Test | |
| public void testCanRenameFileToExistingFile() throws Exception { | |
| Path otherFile = absolutize("otherFile"); | |
| FileSystemUtils.createEmptyFile(otherFile); | |
| xFile.renameTo(otherFile); // succeeds | |
| assertThat(xFile.exists()).isFalse(); | |
| assertThat(otherFile.isFile()).isTrue(); | |
| } | |
| @Test | |
| public void testCanRenameDirToExistingEmptyDir() throws Exception { | |
| xNonEmptyDirectory.renameTo(xEmptyDirectory); // succeeds | |
| assertThat(xNonEmptyDirectory.exists()).isFalse(); | |
| assertThat(xEmptyDirectory.isDirectory()).isTrue(); | |
| assertThat(xEmptyDirectory.getDirectoryEntries()).isNotEmpty(); | |
| } | |
| @Test | |
| public void testCantRenameDirToExistingNonEmptyDir() throws Exception { | |
| try { | |
| xEmptyDirectory.renameTo(xNonEmptyDirectory); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessageThat().containsMatch("\\((File exists|Directory not empty)\\)$"); | |
| } | |
| } | |
| @Test | |
| public void testCantRenameDirToExistingNonEmptyDirNothingChanged() throws Exception { | |
| try { | |
| xEmptyDirectory.renameTo(xNonEmptyDirectory); | |
| fail(); | |
| } catch (IOException e) { | |
| // Expected | |
| } | |
| assertThat(xNonEmptyDirectory.isDirectory()).isTrue(); | |
| assertThat(xEmptyDirectory.isDirectory()).isTrue(); | |
| assertThat(xEmptyDirectory.getDirectoryEntries()).isEmpty(); | |
| assertThat(xNonEmptyDirectory.getDirectoryEntries()).isNotEmpty(); | |
| } | |
| @Test | |
| public void testCantRenameDirToExistingFile() { | |
| try { | |
| xEmptyDirectory.renameTo(xFile); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xEmptyDirectory + " -> " + xFile + " (Not a directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCantRenameDirToExistingFileNothingChanged() { | |
| try { | |
| xEmptyDirectory.renameTo(xFile); | |
| fail(); | |
| } catch (IOException e) { | |
| // Expected | |
| } | |
| assertThat(xEmptyDirectory.isDirectory()).isTrue(); | |
| assertThat(xFile.isFile()).isTrue(); | |
| } | |
| @Test | |
| public void testCantRenameFileToExistingDir() { | |
| try { | |
| xFile.renameTo(xEmptyDirectory); | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xFile + " -> " + xEmptyDirectory + " (Is a directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCantRenameFileToExistingDirNothingChanged() { | |
| try { | |
| xFile.renameTo(xEmptyDirectory); | |
| fail(); | |
| } catch (IOException e) { | |
| // Expected | |
| } | |
| assertThat(xEmptyDirectory.isDirectory()).isTrue(); | |
| assertThat(xFile.isFile()).isTrue(); | |
| } | |
| @Test | |
| public void testMoveOnNonExistingFileThrowsException() throws Exception { | |
| Path nonExistingPath = absolutize("non-existing"); | |
| Path targetPath = absolutize("does-not-matter"); | |
| try { | |
| nonExistingPath.renameTo(targetPath); | |
| fail(); | |
| } catch (FileNotFoundException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (No such file or directory)"); | |
| } | |
| } | |
| // Test the Paths | |
| @Test | |
| public void testGetPathOnlyAcceptsAbsolutePath() { | |
| MoreAsserts.assertThrows(IllegalArgumentException.class, () -> testFS.getPath("not-absolute")); | |
| } | |
| @Test | |
| public void testGetPathOnlyAcceptsAbsolutePathFragment() { | |
| MoreAsserts.assertThrows( | |
| IllegalArgumentException.class, () -> testFS.getPath(PathFragment.create("not-absolute"))); | |
| } | |
| // Test the access permissions | |
| @Test | |
| public void testNewFilesAreWritable() throws Exception { | |
| assertThat(xFile.isWritable()).isTrue(); | |
| } | |
| @Test | |
| public void testNewFilesAreReadable() throws Exception { | |
| assertThat(xFile.isReadable()).isTrue(); | |
| } | |
| @Test | |
| public void testNewDirsAreWritable() throws Exception { | |
| assertThat(xEmptyDirectory.isWritable()).isTrue(); | |
| } | |
| @Test | |
| public void testNewDirsAreReadable() throws Exception { | |
| assertThat(xEmptyDirectory.isReadable()).isTrue(); | |
| } | |
| @Test | |
| public void testNewDirsAreExecutable() throws Exception { | |
| assertThat(xEmptyDirectory.isExecutable()).isTrue(); | |
| } | |
| @Test | |
| public void testCannotGetExecutableOnNonexistingFile() throws Exception { | |
| try { | |
| xNothing.isExecutable(); | |
| fail("No exception thrown."); | |
| } catch (FileNotFoundException ex) { | |
| assertThat(ex).hasMessage(xNothing + " (No such file or directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotSetExecutableOnNonexistingFile() throws Exception { | |
| try { | |
| xNothing.setExecutable(true); | |
| fail("No exception thrown."); | |
| } catch (FileNotFoundException ex) { | |
| assertThat(ex).hasMessage(xNothing + " (No such file or directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotGetWritableOnNonexistingFile() throws Exception { | |
| try { | |
| xNothing.isWritable(); | |
| fail("No exception thrown."); | |
| } catch (FileNotFoundException ex) { | |
| assertThat(ex).hasMessage(xNothing + " (No such file or directory)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotSetWritableOnNonexistingFile() throws Exception { | |
| try { | |
| xNothing.setWritable(false); | |
| fail("No exception thrown."); | |
| } catch (FileNotFoundException ex) { | |
| assertThat(ex).hasMessage(xNothing + " (No such file or directory)"); | |
| } | |
| } | |
| @Test | |
| public void testSetReadableOnFile() throws Exception { | |
| xFile.setReadable(false); | |
| assertThat(xFile.isReadable()).isFalse(); | |
| xFile.setReadable(true); | |
| assertThat(xFile.isReadable()).isTrue(); | |
| } | |
| @Test | |
| public void testSetWritableOnFile() throws Exception { | |
| xFile.setWritable(false); | |
| assertThat(xFile.isWritable()).isFalse(); | |
| xFile.setWritable(true); | |
| assertThat(xFile.isWritable()).isTrue(); | |
| } | |
| @Test | |
| public void testSetExecutableOnFile() throws Exception { | |
| xFile.setExecutable(true); | |
| assertThat(xFile.isExecutable()).isTrue(); | |
| xFile.setExecutable(false); | |
| assertThat(xFile.isExecutable()).isFalse(); | |
| } | |
| @Test | |
| public void testSetExecutableOnDirectory() throws Exception { | |
| setExecutable(xNonEmptyDirectory, false); | |
| try { | |
| // We can't map names->inodes in a non-executable directory: | |
| xNonEmptyDirectoryFoo.isWritable(); // i.e. stat | |
| fail(); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testWritingToReadOnlyFileThrowsException() throws Exception { | |
| xFile.setWritable(false); | |
| try { | |
| FileSystemUtils.writeContent(xFile, "hello, world!".getBytes(UTF_8)); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xFile + " (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testReadingFromUnreadableFileThrowsException() throws Exception { | |
| FileSystemUtils.writeContent(xFile, "hello, world!".getBytes(UTF_8)); | |
| xFile.setReadable(false); | |
| try { | |
| FileSystemUtils.readContent(xFile); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xFile + " (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateFileInReadOnlyDirectory() throws Exception { | |
| Path xNonEmptyDirectoryBar = xNonEmptyDirectory.getChild("bar"); | |
| xNonEmptyDirectory.setWritable(false); | |
| try { | |
| FileSystemUtils.createEmptyFile(xNonEmptyDirectoryBar); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xNonEmptyDirectoryBar + " (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreateDirectoryInReadOnlyDirectory() throws Exception { | |
| Path xNonEmptyDirectoryBar = xNonEmptyDirectory.getChild("bar"); | |
| xNonEmptyDirectory.setWritable(false); | |
| try { | |
| xNonEmptyDirectoryBar.createDirectory(); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xNonEmptyDirectoryBar + " (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotMoveIntoReadOnlyDirectory() throws Exception { | |
| Path xNonEmptyDirectoryBar = xNonEmptyDirectory.getChild("bar"); | |
| xNonEmptyDirectory.setWritable(false); | |
| try { | |
| xFile.renameTo(xNonEmptyDirectoryBar); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotMoveFromReadOnlyDirectory() throws Exception { | |
| xNonEmptyDirectory.setWritable(false); | |
| try { | |
| xNonEmptyDirectoryFoo.renameTo(xNothing); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessageThat().endsWith(" (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotDeleteInReadOnlyDirectory() throws Exception { | |
| xNonEmptyDirectory.setWritable(false); | |
| try { | |
| xNonEmptyDirectoryFoo.delete(); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xNonEmptyDirectoryFoo + " (Permission denied)"); | |
| } | |
| } | |
| @Test | |
| public void testCannotCreatSymbolicLinkInReadOnlyDirectory() throws Exception { | |
| Path xNonEmptyDirectoryBar = xNonEmptyDirectory.getChild("bar"); | |
| xNonEmptyDirectory.setWritable(false); | |
| if (testFS.supportsSymbolicLinksNatively(xNonEmptyDirectoryBar)) { | |
| try { | |
| createSymbolicLink(xNonEmptyDirectoryBar, xNonEmptyDirectoryFoo); | |
| fail("No exception thrown."); | |
| } catch (IOException e) { | |
| assertThat(e).hasMessage(xNonEmptyDirectoryBar + " (Permission denied)"); | |
| } | |
| } | |
| } | |
| @Test | |
| public void testGetDigestForEmptyFile() throws Exception { | |
| Fingerprint fp = new Fingerprint(digestHashFunction); | |
| fp.addBytes(new byte[0]); | |
| assertThat(fp.hexDigestAndReset()) | |
| .isEqualTo(BaseEncoding.base16().lowerCase().encode(xFile.getDigest())); | |
| } | |
| @Test | |
| public void testGetDigest() throws Exception { | |
| byte[] buffer = new byte[500000]; | |
| for (int i = 0; i < buffer.length; ++i) { | |
| buffer[i] = 1; | |
| } | |
| FileSystemUtils.writeContent(xFile, buffer); | |
| Fingerprint fp = new Fingerprint(digestHashFunction); | |
| fp.addBytes(buffer); | |
| assertThat(fp.hexDigestAndReset()) | |
| .isEqualTo(BaseEncoding.base16().lowerCase().encode(xFile.getDigest())); | |
| } | |
| @Test | |
| public void testStatFailsFastOnNonExistingFiles() throws Exception { | |
| try { | |
| xNothing.stat(); | |
| fail("Expected IOException"); | |
| } catch (IOException e) { | |
| // Do nothing. | |
| } | |
| } | |
| @Test | |
| public void testStatNullableFailsFastOnNonExistingFiles() throws Exception { | |
| assertThat(xNothing.statNullable()).isNull(); | |
| } | |
| @Test | |
| public void testResolveSymlinks() throws Exception { | |
| if (testFS.supportsSymbolicLinksNatively(xLink)) { | |
| createSymbolicLink(xLink, xFile); | |
| FileSystemUtils.createEmptyFile(xFile); | |
| assertThat(testFS.resolveOneLink(xLink)).isEqualTo(xFile.asFragment()); | |
| assertThat(xLink.resolveSymbolicLinks()).isEqualTo(xFile); | |
| } | |
| } | |
| @Test | |
| public void testResolveDanglingSymlinks() throws Exception { | |
| if (testFS.supportsSymbolicLinksNatively(xLink)) { | |
| createSymbolicLink(xLink, xNothing); | |
| assertThat(testFS.resolveOneLink(xLink)).isEqualTo(xNothing.asFragment()); | |
| try { | |
| xLink.resolveSymbolicLinks(); | |
| fail(); | |
| } catch (IOException expected) { | |
| } | |
| } | |
| } | |
| @Test | |
| public void testResolveNonSymlinks() throws Exception { | |
| if (testFS.supportsSymbolicLinksNatively(xFile)) { | |
| assertThat(testFS.resolveOneLink(xFile)).isNull(); | |
| assertThat(xFile.resolveSymbolicLinks()).isEqualTo(xFile); | |
| } | |
| } | |
| @Test | |
| public void testCreateHardLink_Success() throws Exception { | |
| if (!testFS.supportsHardLinksNatively(xFile)) { | |
| return; | |
| } | |
| xFile.createHardLink(xLink); | |
| assertThat(xFile.exists()).isTrue(); | |
| assertThat(xLink.exists()).isTrue(); | |
| assertThat(xFile.isFile()).isTrue(); | |
| assertThat(xLink.isFile()).isTrue(); | |
| assertThat(isHardLinked(xFile, xLink)).isTrue(); | |
| } | |
| @Test | |
| public void testCreateHardLink_NeitherOriginalNorLinkExists() throws Exception { | |
| if (!testFS.supportsHardLinksNatively(xFile)) { | |
| return; | |
| } | |
| /* Neither original file nor link file exists */ | |
| xFile.delete(); | |
| try { | |
| xFile.createHardLink(xLink); | |
| fail("expected FileNotFoundException: File \"xFile\" linked from \"xLink\" does not exist"); | |
| } catch (FileNotFoundException expected) { | |
| assertThat(expected).hasMessage("File \"xFile\" linked from \"xLink\" does not exist"); | |
| } | |
| assertThat(xFile.exists()).isFalse(); | |
| assertThat(xLink.exists()).isFalse(); | |
| } | |
| @Test | |
| public void testCreateHardLink_OriginalDoesNotExistAndLinkExists() throws Exception { | |
| if (!testFS.supportsHardLinksNatively(xFile)) { | |
| return; | |
| } | |
| /* link file exists and original file does not exist */ | |
| xFile.delete(); | |
| FileSystemUtils.createEmptyFile(xLink); | |
| try { | |
| xFile.createHardLink(xLink); | |
| fail("expected FileNotFoundException: File \"xFile\" linked from \"xLink\" does not exist"); | |
| } catch (FileNotFoundException expected) { | |
| assertThat(expected).hasMessage("File \"xFile\" linked from \"xLink\" does not exist"); | |
| } | |
| assertThat(xFile.exists()).isFalse(); | |
| assertThat(xLink.exists()).isTrue(); | |
| } | |
| @Test | |
| public void testCreateHardLink_BothOriginalAndLinkExist() throws Exception { | |
| if (!testFS.supportsHardLinksNatively(xFile)) { | |
| return; | |
| } | |
| /* Both original file and link file exist */ | |
| FileSystemUtils.createEmptyFile(xLink); | |
| try { | |
| xFile.createHardLink(xLink); | |
| fail("expected FileAlreadyExistsException: New link file \"xLink\" already exists"); | |
| } catch (FileAlreadyExistsException expected) { | |
| assertThat(expected).hasMessage("New link file \"xLink\" already exists"); | |
| } | |
| assertThat(xFile.exists()).isTrue(); | |
| assertThat(xLink.exists()).isTrue(); | |
| assertThat(isHardLinked(xFile, xLink)).isFalse(); | |
| } | |
| protected boolean isHardLinked(Path a, Path b) throws IOException { | |
| return testFS.stat(a, false).getNodeId() == testFS.stat(b, false).getNodeId(); | |
| } | |
| } |