blob: f6cf370ce8e7217e15f9ed4aea462d708c5e37b1 [file] [log] [blame]
// 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 org.junit.Assert.assertThrows;
import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.util.StringEncoding;
import com.google.devtools.build.lib.vfs.FileSystem.NotASymlinkException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
/**
* 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.
*/
public abstract class SymlinkAwareFileSystemTest extends FileSystemTest {
protected Path xLinkToFile;
protected Path xLinkToLinkToFile;
protected Path xLinkToDirectory;
protected Path xDanglingLink;
@Before
public final void createSymbolicLinks() throws Exception {
// % ls -lR
// -rw-rw-r-- xFile
// drwxrwxr-x xNonEmptyDirectory
// -rw-rw-r-- xNonEmptyDirectory/foo
// drwxrwxr-x xEmptyDirectory
// lrwxrwxr-x xLinkToFile -> xFile
// lrwxrwxr-x xLinkToDirectory -> xEmptyDirectory
// lrwxrwxr-x xLinkToLinkToFile -> xLinkToFile
// lrwxrwxr-x xDanglingLink -> xNothing
xLinkToFile = absolutize("xLinkToFile");
xLinkToLinkToFile = absolutize("xLinkToLinkToFile");
xLinkToDirectory = absolutize("xLinkToDirectory");
xDanglingLink = absolutize("xDanglingLink");
createSymbolicLink(xLinkToFile, xFile);
createSymbolicLink(xLinkToLinkToFile, xLinkToFile);
createSymbolicLink(xLinkToDirectory, xEmptyDirectory);
createSymbolicLink(xDanglingLink, xNothing);
}
@Test
public void testCreateLinkToFile() throws IOException {
Path newPath = xEmptyDirectory.getChild("new-file");
FileSystemUtils.createEmptyFile(newPath);
Path linkPath = xEmptyDirectory.getChild("some-link");
createSymbolicLink(linkPath, newPath);
assertThat(linkPath.isSymbolicLink()).isTrue();
assertThat(linkPath.isFile()).isTrue();
assertThat(linkPath.isFile(Symlinks.NOFOLLOW)).isFalse();
assertThat(linkPath.isFile(Symlinks.FOLLOW)).isTrue();
assertThat(linkPath.isDirectory()).isFalse();
assertThat(linkPath.isDirectory(Symlinks.NOFOLLOW)).isFalse();
assertThat(linkPath.isDirectory(Symlinks.FOLLOW)).isFalse();
if (testFS.supportsSymbolicLinksNatively(linkPath.asFragment())) {
assertThat(linkPath.getFileSize(Symlinks.NOFOLLOW)).isEqualTo(newPath.toString().length());
assertThat(linkPath.getFileSize()).isEqualTo(newPath.getFileSize(Symlinks.NOFOLLOW));
}
assertThat(linkPath.getParentDirectory().getDirectoryEntries()).hasSize(2);
assertThat(linkPath.getParentDirectory().getDirectoryEntries()).containsExactly(newPath,
linkPath);
}
@Test
public void testCreateLinkToDirectory() throws IOException {
Path newPath = xEmptyDirectory.getChild("new-file");
newPath.createDirectory();
Path linkPath = xEmptyDirectory.getChild("some-link");
createSymbolicLink(linkPath, newPath);
assertThat(linkPath.isSymbolicLink()).isTrue();
assertThat(linkPath.isFile()).isFalse();
assertThat(linkPath.isDirectory()).isTrue();
assertThat(linkPath.getParentDirectory().getDirectoryEntries()).hasSize(2);
assertThat(linkPath.getParentDirectory().
getDirectoryEntries()).containsExactly(newPath, linkPath);
}
@Test
public void testFileCanonicalPath() throws IOException {
Path newPath = absolutize("new-file");
FileSystemUtils.createEmptyFile(newPath);
newPath = newPath.resolveSymbolicLinks();
Path link1 = absolutize("some-link");
Path link2 = absolutize("some-link2");
createSymbolicLink(link1, newPath);
createSymbolicLink(link2, link1);
assertCanonicalPathsMatch(newPath, link1, link2);
}
@Test
public void testDirectoryCanonicalPath() throws IOException {
Path newPath = absolutize("new-folder");
newPath.createDirectory();
newPath = newPath.resolveSymbolicLinks();
Path newFile = newPath.getChild("file");
FileSystemUtils.createEmptyFile(newFile);
Path link1 = absolutize("some-link");
Path link2 = absolutize("some-link2");
createSymbolicLink(link1, newPath);
createSymbolicLink(link2, link1);
Path linkFile1 = link1.getChild("file");
Path linkFile2 = link2.getChild("file");
assertCanonicalPathsMatch(newFile, linkFile1, linkFile2);
}
private void assertCanonicalPathsMatch(Path newPath, Path link1, Path link2)
throws IOException {
assertThat(link1.resolveSymbolicLinks()).isEqualTo(newPath);
assertThat(link2.resolveSymbolicLinks()).isEqualTo(newPath);
}
//
// createDirectory
//
@Test
public void testCreateDirectoryWhereDanglingSymlinkAlreadyExists() {
IOException e = assertThrows(IOException.class, () -> xDanglingLink.createDirectory());
assertThat(e).hasMessageThat().isEqualTo(xDanglingLink + " (File exists)");
assertThat(xDanglingLink.isSymbolicLink()).isTrue(); // still a symbolic link
assertThat(xDanglingLink.isDirectory(Symlinks.FOLLOW)).isFalse(); // link still dangles
}
@Test
public void testCreateDirectoryWhereSymlinkAlreadyExists() {
IOException e = assertThrows(IOException.class, () -> xLinkToDirectory.createDirectory());
assertThat(e).hasMessageThat().isEqualTo(xLinkToDirectory + " (File exists)");
assertThat(xLinkToDirectory.isSymbolicLink()).isTrue(); // still a symbolic link
assertThat(xLinkToDirectory.isDirectory(Symlinks.FOLLOW)).isTrue(); // link still points to dir
}
// createSymbolicLink(PathFragment)
@Test
public void testCreateSymbolicLinkFromFragment() throws IOException {
String[] linkTargets = {
"foo",
"foo/bar",
".",
"..",
"../foo",
"../../foo",
"../../../../../../../../../../../../../../../../../../../../../foo",
"/foo",
"/foo/bar",
"/..",
"/foo/../bar",
};
Path linkPath = absolutize("link");
for (String linkTarget : linkTargets) {
PathFragment relative = PathFragment.create(linkTarget);
linkPath.delete();
createSymbolicLink(linkPath, relative);
if (testFS.supportsSymbolicLinksNatively(linkPath.asFragment())) {
assertThat(linkPath.getFileSize(Symlinks.NOFOLLOW))
.isEqualTo(relative.getSafePathString().length());
assertThat(linkPath.readSymbolicLink()).isEqualTo(relative);
}
}
}
@Test
public void testLinkToRootResolvesCorrectly() throws IOException {
if (OS.getCurrent() == OS.WINDOWS) {
// This test cannot be run on Windows, it mixes "/" paths with "C:/" paths
return;
}
Path rootPath = testFS.getPath("/");
try {
rootPath.getChild("testDir").createDirectory();
} catch (IOException e) {
// Do nothing. This is a real FS, and we don't have permission.
}
Path linkPath = absolutize("link");
createSymbolicLink(linkPath, rootPath);
// resolveSymbolicLinks requires an existing path:
assertThrows(
FileNotFoundException.class, () -> linkPath.getRelative("test").resolveSymbolicLinks());
// The path may not be a symlink, neither on Darwin nor on Linux.
String nonLinkEntry = null;
for (String child : testFS.getDirectoryEntries(rootPath.asFragment())) {
Path p = rootPath.getChild(child);
if (!p.isSymbolicLink() && p.isDirectory()) {
nonLinkEntry = p.getBaseName();
break;
}
}
assertThat(nonLinkEntry).isNotNull();
Path rootChild = testFS.getPath("/" + nonLinkEntry);
assertThat(linkPath.getRelative(nonLinkEntry).resolveSymbolicLinks()).isEqualTo(rootChild);
}
@Test
public void testLinkToFragmentContainingLinkResolvesCorrectly() throws IOException {
Path link1 = absolutize("link1");
PathFragment link1target = PathFragment.create("link2/foo");
Path link2 = absolutize("link2");
Path link2target = xNonEmptyDirectory;
createSymbolicLink(link1, link1target); // ln -s link2/foo link1
createSymbolicLink(link2, link2target); // ln -s xNonEmptyDirectory link2
// link1 --> xNonEmptyDirectory/foo
assertThat(link2target.getRelative("foo")).isEqualTo(link1.resolveSymbolicLinks());
}
//
// readSymbolicLink / resolveSymbolicLinks
//
@Test
public void testRecursiveSymbolicLink() throws IOException {
Path link = absolutize("recursive-link");
createSymbolicLink(link, link);
if (testFS.supportsSymbolicLinksNatively(link.asFragment())) {
IOException e = assertThrows(IOException.class, () -> link.resolveSymbolicLinks());
assertThat(e).hasMessageThat().isEqualTo(link + " (Too many levels of symbolic links)");
}
}
@Test
public void testMutuallyRecursiveSymbolicLinks() throws IOException {
Path link1 = absolutize("link1");
Path link2 = absolutize("link2");
createSymbolicLink(link2, link1);
createSymbolicLink(link1, link2);
if (testFS.supportsSymbolicLinksNatively(link1.asFragment())) {
IOException e = assertThrows(IOException.class, () -> link1.resolveSymbolicLinks());
assertThat(e).hasMessageThat().isEqualTo(link1 + " (Too many levels of symbolic links)");
}
}
@Test
public void testResolveSymbolicLinksENOENT() {
if (testFS.supportsSymbolicLinksNatively(xDanglingLink.asFragment())) {
IOException e = assertThrows(IOException.class, () -> xDanglingLink.resolveSymbolicLinks());
assertThat(e).hasMessageThat().isEqualTo(xNothing + " (No such file or directory)");
}
}
@Test
public void testResolveSymbolicLinksENOTDIR() throws IOException {
Path badLinkTarget = xFile.getChild("bad"); // parent is not a directory!
Path badLink = absolutize("badLink");
if (testFS.supportsSymbolicLinksNatively(badLink.asFragment())) {
createSymbolicLink(badLink, badLinkTarget);
assertThrows(IOException.class, badLink::resolveSymbolicLinks);
}
}
@Test
public void testResolveSymbolicLinksWithUplevelRefs() throws IOException {
if (testFS.supportsSymbolicLinksNatively(xLinkToFile.asFragment())) {
// Create a series of links that refer to xFile as ./xFile,
// ./../foo/xFile, ./../../bar/foo/xFile, etc. They should all resolve
// to xFile.
Path ancestor = xFile;
String prefix = "./";
while ((ancestor = ancestor.getParentDirectory()) != null) {
xLinkToFile.delete();
createSymbolicLink(xLinkToFile, PathFragment.create(prefix + xFile.relativeTo(ancestor)));
assertThat(xLinkToFile.resolveSymbolicLinks()).isEqualTo(xFile);
prefix += "../";
}
}
}
@Test
public void testReadSymbolicLink() throws IOException {
if (testFS.supportsSymbolicLinksNatively(xDanglingLink.asFragment())) {
assertThat(xDanglingLink.readSymbolicLink().toString()).isEqualTo(xNothing.toString());
}
assertThat(xLinkToFile.readSymbolicLink().toString()).isEqualTo(xFile.toString());
assertThat(xLinkToDirectory.readSymbolicLink().toString())
.isEqualTo(xEmptyDirectory.toString());
NotASymlinkException nase =
assertThrows(NotASymlinkException.class, () -> xFile.readSymbolicLink());
assertThat(nase).hasMessageThat().isEqualTo(xFile.toString() + " is not a symlink");
FileNotFoundException fnfe =
assertThrows(FileNotFoundException.class, () -> xNothing.readSymbolicLink());
assertThat(fnfe).hasMessageThat().isEqualTo(xNothing + " (No such file or directory)");
}
@Test
public void testCannotCreateSymbolicLinkWithReadOnlyParent()
throws IOException {
xEmptyDirectory.setWritable(false);
Path xChildOfReadonlyDir = xEmptyDirectory.getChild("x");
if (testFS.supportsSymbolicLinksNatively(xChildOfReadonlyDir.asFragment())) {
IOException e =
assertThrows(IOException.class, () -> xChildOfReadonlyDir.createSymbolicLink(xNothing));
assertThat(e).hasMessageThat().isEqualTo(xChildOfReadonlyDir + " (Permission denied)");
}
}
//
// createSymbolicLink
//
@Test
public void testCanCreateDanglingLink() throws IOException {
Path newPath = absolutize("non-existing-dir/new-file");
Path someLink = absolutize("dangling-link");
createSymbolicLink(someLink, newPath);
assertThat(someLink.isSymbolicLink()).isTrue();
assertThat(someLink.exists(Symlinks.NOFOLLOW)).isTrue(); // the link itself exists
assertThat(someLink.exists()).isFalse(); // ...but the referent doesn't
if (testFS.supportsSymbolicLinksNatively(someLink.asFragment())) {
FileNotFoundException e =
assertThrows(FileNotFoundException.class, someLink::resolveSymbolicLinks);
assertThat(e)
.hasMessageThat()
.isEqualTo(newPath.getParentDirectory() + " (No such file or directory)");
}
}
@Test
public void testCannotCreateSymbolicLinkWithoutParent() throws IOException {
Path xChildOfMissingDir = xNothing.getChild("x");
if (testFS.supportsSymbolicLinksNatively(xChildOfMissingDir.asFragment())) {
FileNotFoundException e =
assertThrows(
FileNotFoundException.class, () -> xChildOfMissingDir.createSymbolicLink(xFile));
assertThat(e).hasMessageThat().endsWith(" (No such file or directory)");
}
}
@Test
public void testCreateSymbolicLinkWhereNothingExists() throws IOException {
createSymbolicLink(xNothing, xFile);
assertThat(xNothing.isSymbolicLink()).isTrue();
}
@Test
public void testCreateSymbolicLinkWhereDirectoryAlreadyExists() {
IOException e =
assertThrows(IOException.class, () -> createSymbolicLink(xEmptyDirectory, xFile));
assertThat(e).hasMessageThat().isEqualTo(xEmptyDirectory + " (File exists)");
assertThat(xEmptyDirectory.isDirectory(Symlinks.NOFOLLOW)).isTrue();
}
@Test
public void testCreateSymbolicLinkWhereFileAlreadyExists() {
IOException e =
assertThrows(IOException.class, () -> createSymbolicLink(xFile, xEmptyDirectory));
assertThat(e).hasMessageThat().isEqualTo(xFile + " (File exists)");
assertThat(xFile.isFile(Symlinks.NOFOLLOW)).isTrue();
}
@Test
public void testCreateSymbolicLinkWhereDanglingSymlinkAlreadyExists() {
IOException e = assertThrows(IOException.class, () -> createSymbolicLink(xDanglingLink, xFile));
assertThat(e).hasMessageThat().isEqualTo(xDanglingLink + " (File exists)");
assertThat(xDanglingLink.isSymbolicLink()).isTrue(); // still a symbolic link
assertThat(xDanglingLink.isDirectory()).isFalse(); // link still dangles
}
@Test
public void testCreateSymbolicLinkWhereSymlinkAlreadyExists() {
IOException e =
assertThrows(IOException.class, () -> createSymbolicLink(xLinkToDirectory, xNothing));
assertThat(e).hasMessageThat().isEqualTo(xLinkToDirectory + " (File exists)");
assertThat(xLinkToDirectory.isSymbolicLink()).isTrue(); // still a symbolic link
assertThat(xLinkToDirectory.isDirectory()).isTrue(); // link still points to dir
}
@Test
public void testDeleteLink() throws IOException {
Path newPath = xEmptyDirectory.getChild("new-file");
Path someLink = xEmptyDirectory.getChild("a-link");
FileSystemUtils.createEmptyFile(newPath);
createSymbolicLink(someLink, newPath);
assertThat(xEmptyDirectory.getDirectoryEntries()).hasSize(2);
assertThat(someLink.delete()).isTrue();
assertThat(xEmptyDirectory.getDirectoryEntries()).hasSize(1);
assertThat(xEmptyDirectory.getDirectoryEntries()).containsExactly(newPath);
}
// Testing the links
@Test
public void testLinkFollowedToDirectory() throws IOException {
Path theDirectory = absolutize("foo/");
assertThat(theDirectory.createDirectory()).isTrue();
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);
Path linkPath = absolutize("link");
createSymbolicLink(linkPath, theDirectory);
Path resultPath1 = absolutize("link/new-file-1");
Path resultPath2 = absolutize("link/new-file-2");
Path resultPath3 = absolutize("link/new-file-3");
assertThat(linkPath.getDirectoryEntries()).containsExactly(resultPath1, resultPath2,
resultPath3);
}
@Test
public void testDanglingLinkIsNoFile() throws IOException {
Path newPath1 = absolutize("new-file-1");
Path newPath2 = absolutize("new-file-2");
FileSystemUtils.createEmptyFile(newPath1);
assertThat(newPath2.createDirectory()).isTrue();
Path linkPath1 = absolutize("link1");
Path linkPath2 = absolutize("link2");
createSymbolicLink(linkPath1, newPath1);
createSymbolicLink(linkPath2, newPath2);
newPath1.delete();
newPath2.delete();
assertThat(linkPath1.isFile()).isFalse();
assertThat(linkPath2.isDirectory()).isFalse();
}
@Test
public void testWriteOnLinkChangesFile() throws IOException {
Path testFile = absolutize("test-file");
FileSystemUtils.createEmptyFile(testFile);
String testData = "abc19";
Path testLink = absolutize("a-link");
createSymbolicLink(testLink, testFile);
FileSystemUtils.writeContentAsLatin1(testLink, testData);
String resultData =
new String(FileSystemUtils.readContentAsLatin1(testFile));
assertThat(resultData).isEqualTo(testData);
}
//
// Symlink tests:
//
@Test
public void testExistsWithSymlinks() throws IOException {
Path a = absolutize("a");
Path b = absolutize("b");
FileSystemUtils.createEmptyFile(b);
createSymbolicLink(a, b); // ln -sf "b" "a"
assertThat(a.exists()).isTrue(); // = exists(FOLLOW)
assertThat(b.exists()).isTrue(); // = exists(FOLLOW)
assertThat(a.exists(Symlinks.FOLLOW)).isTrue();
assertThat(b.exists(Symlinks.FOLLOW)).isTrue();
assertThat(a.exists(Symlinks.NOFOLLOW)).isTrue();
assertThat(b.exists(Symlinks.NOFOLLOW)).isTrue();
b.delete(); // "a" is now a dangling link
assertThat(a.exists()).isFalse(); // = exists(FOLLOW)
assertThat(b.exists()).isFalse(); // = exists(FOLLOW)
assertThat(a.exists(Symlinks.FOLLOW)).isFalse();
assertThat(b.exists(Symlinks.FOLLOW)).isFalse();
assertThat(a.exists(Symlinks.NOFOLLOW)).isTrue(); // symlink still exists
assertThat(b.exists(Symlinks.NOFOLLOW)).isFalse();
}
@Test
public void testIsDirectoryWithSymlinks() throws IOException {
Path a = absolutize("a");
Path b = absolutize("b");
b.createDirectory();
createSymbolicLink(a, b); // ln -sf "b" "a"
assertThat(a.isDirectory()).isTrue(); // = isDirectory(FOLLOW)
assertThat(b.isDirectory()).isTrue(); // = isDirectory(FOLLOW)
assertThat(a.isDirectory(Symlinks.FOLLOW)).isTrue();
assertThat(b.isDirectory(Symlinks.FOLLOW)).isTrue();
assertThat(a.isDirectory(Symlinks.NOFOLLOW)).isFalse(); // it's a link!
assertThat(b.isDirectory(Symlinks.NOFOLLOW)).isTrue();
b.delete(); // "a" is now a dangling link
assertThat(a.isDirectory()).isFalse(); // = isDirectory(FOLLOW)
assertThat(b.isDirectory()).isFalse(); // = isDirectory(FOLLOW)
assertThat(a.isDirectory(Symlinks.FOLLOW)).isFalse();
assertThat(b.isDirectory(Symlinks.FOLLOW)).isFalse();
assertThat(a.isDirectory(Symlinks.NOFOLLOW)).isFalse();
assertThat(b.isDirectory(Symlinks.NOFOLLOW)).isFalse();
}
@Test
public void testIsFileWithSymlinks() throws IOException {
Path a = absolutize("a");
Path b = absolutize("b");
FileSystemUtils.createEmptyFile(b);
createSymbolicLink(a, b); // ln -sf "b" "a"
assertThat(a.isFile()).isTrue(); // = isFile(FOLLOW)
assertThat(b.isFile()).isTrue(); // = isFile(FOLLOW)
assertThat(a.isFile(Symlinks.FOLLOW)).isTrue();
assertThat(b.isFile(Symlinks.FOLLOW)).isTrue();
assertThat(a.isFile(Symlinks.NOFOLLOW)).isFalse(); // it's a link!
assertThat(b.isFile(Symlinks.NOFOLLOW)).isTrue();
b.delete(); // "a" is now a dangling link
assertThat(a.isFile()).isFalse(); // = isFile()
assertThat(b.isFile()).isFalse(); // = isFile()
assertThat(a.isFile()).isFalse();
assertThat(b.isFile()).isFalse();
assertThat(a.isFile(Symlinks.NOFOLLOW)).isFalse();
assertThat(b.isFile(Symlinks.NOFOLLOW)).isFalse();
}
@Test
public void testGetDirectoryEntriesOnLinkToDirectory() throws Exception {
Path fooAlias = xNothing.getChild("foo");
createSymbolicLink(xNothing, xNonEmptyDirectory);
Collection<Path> dirents = xNothing.getDirectoryEntries();
assertThat(dirents).containsExactly(fooAlias);
}
@Test
public void testFilesOfLinkedDirectories() throws Exception {
Path child = xEmptyDirectory.getChild("child");
Path aliasToChild = xLinkToDirectory.getChild("child");
assertThat(aliasToChild.exists()).isFalse();
FileSystemUtils.createEmptyFile(child);
assertThat(aliasToChild.exists()).isTrue();
assertThat(aliasToChild.isFile()).isTrue();
assertThat(aliasToChild.isDirectory()).isFalse();
validateLinkedReferenceObeysReadOnly(child, aliasToChild);
validateLinkedReferenceObeysExecutable(child, aliasToChild);
}
@Test
public void testDirectoriesOfLinkedDirectories() throws Exception {
Path childDir = xEmptyDirectory.getChild("childDir");
Path linkToChildDir = xLinkToDirectory.getChild("childDir");
assertThat(linkToChildDir.exists()).isFalse();
childDir.createDirectory();
assertThat(linkToChildDir.exists()).isTrue();
assertThat(linkToChildDir.isDirectory()).isTrue();
assertThat(linkToChildDir.isFile()).isFalse();
validateLinkedReferenceObeysReadOnly(childDir, linkToChildDir);
validateLinkedReferenceObeysExecutable(childDir, linkToChildDir);
}
@Test
public void testDirectoriesOfLinkedDirectoriesOfLinkedDirectories() throws Exception {
Path childDir = xEmptyDirectory.getChild("childDir");
Path linkToLinkToDirectory = absolutize("xLinkToLinkToDirectory");
createSymbolicLink(linkToLinkToDirectory, xLinkToDirectory);
Path linkToChildDir = linkToLinkToDirectory.getChild("childDir");
assertThat(linkToChildDir.exists()).isFalse();
childDir.createDirectory();
assertThat(linkToChildDir.exists()).isTrue();
assertThat(linkToChildDir.isDirectory()).isTrue();
assertThat(linkToChildDir.isFile()).isFalse();
validateLinkedReferenceObeysReadOnly(childDir, linkToChildDir);
validateLinkedReferenceObeysExecutable(childDir, linkToChildDir);
}
private void validateLinkedReferenceObeysReadOnly(Path path, Path link) throws IOException {
path.setWritable(false);
assertThat(path.isWritable()).isFalse();
assertThat(link.isWritable()).isFalse();
path.setWritable(true);
assertThat(path.isWritable()).isTrue();
assertThat(link.isWritable()).isTrue();
path.setWritable(false);
assertThat(path.isWritable()).isFalse();
assertThat(link.isWritable()).isFalse();
}
private void validateLinkedReferenceObeysExecutable(Path path, Path link) throws IOException {
path.setExecutable(true);
assertThat(path.isExecutable()).isTrue();
assertThat(link.isExecutable()).isTrue();
path.setExecutable(false);
assertThat(path.isExecutable()).isFalse();
assertThat(link.isExecutable()).isFalse();
path.setExecutable(true);
assertThat(path.isExecutable()).isTrue();
assertThat(link.isExecutable()).isTrue();
}
@Test
public void testReadingFileFromLinkedDirectory() throws Exception {
Path linkedTo = absolutize("linkedTo");
linkedTo.createDirectory();
Path child = linkedTo.getChild("child");
FileSystemUtils.createEmptyFile(child);
byte[] outputData = "This is a test".getBytes();
FileSystemUtils.writeContent(child, outputData);
Path link = absolutize("link");
createSymbolicLink(link, linkedTo);
Path linkedChild = link.getChild("child");
byte[] inputData = FileSystemUtils.readContent(linkedChild);
assertThat(inputData).isEqualTo(outputData);
}
@Test
public void testCreatingFileInLinkedDirectory() throws Exception {
Path linkedTo = absolutize("linkedTo");
linkedTo.createDirectory();
Path child = linkedTo.getChild("child");
Path link = absolutize("link");
createSymbolicLink(link, linkedTo);
Path linkedChild = link.getChild("child");
byte[] outputData = "This is a test".getBytes();
FileSystemUtils.writeContent(linkedChild, outputData);
byte[] inputData = FileSystemUtils.readContent(child);
assertThat(inputData).isEqualTo(outputData);
}
@Test
public void testUtf8Symlink() throws Exception {
assumeUtf8CompatibleEncoding();
String target = StringEncoding.unicodeToInternal("入力_A_🌱.target");
Path link = absolutize(StringEncoding.unicodeToInternal("入力_A_🌱.txt"));
createSymbolicLink(link, PathFragment.create(target));
assertThat(link.readSymbolicLink().toString()).isEqualTo(target);
java.nio.file.Path javaPath = getJavaPathOrSkipIfUnsupported(link);
assertThat(platformToUnicode(Files.readSymbolicLink(javaPath).toString()))
.isEqualTo("入力_A_🌱.target");
}
}