package com.oracle.truffle.api.test.polyglot;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.AccessMode;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.NotDirectoryException;
import java.nio.file.NotLinkException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileTime;
import java.util.Collections;
import java.util.EnumSet;
import java.util.stream.StreamSupport;
import org.graalvm.polyglot.io.FileSystem;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
public class NIOFileSystemTest {
private static final FileAttribute<?> ATTR_UNKNOWN = new FileAttribute<Object>() {
@Override
public String name() {
return "unknown";
}
@Override
public Object value() {
return null;
}
};
private static Path workDir;
private static Path nonExistent;
private static Path file;
private static Path fileRelative;
private static Path folder;
private static Path folderRelative;
private static FileSystem fs;
@BeforeClass
public static void setUp() throws IOException {
Path tmp = Files.createTempDirectory(NIOFileSystemTest.class.getSimpleName());
fs = FileSystem.newDefaultFileSystem();
workDir = fs.parsePath(tmp.toString());
fs.setCurrentWorkingDirectory(workDir);
nonExistent = workDir.resolve("nonexistent");
file = Files.createFile(workDir.resolve("file"));
fileRelative = workDir.relativize(file);
folder = Files.createDirectory(workDir.resolve("folder"));
folderRelative = workDir.relativize(folder);
}
@AfterClass
public static void tearDown() throws IOException {
delete(workDir);
}
@Test
public void testParsePath() {
String fileName = "test";
Path path = fs.parsePath(fileName);
Assert.assertEquals(fileName, path.getFileName().toString());
path = fs.parsePath(workDir.toAbsolutePath().toUri());
Assert.assertEquals(workDir.toAbsolutePath(), path);
expectException(() -> fs.parsePath((String) null), NullPointerException.class);
expectException(() -> fs.parsePath((URI) null), NullPointerException.class);
expectException(() -> fs.parsePath(new URI("unknownscheme:///tmp/")), UnsupportedOperationException.class);
}
@Test
public void testCheckAccess() throws IOException {
fs.checkAccess(folder, EnumSet.of(AccessMode.READ));
fs.checkAccess(folder, EnumSet.of(AccessMode.READ, AccessMode.WRITE));
fs.checkAccess(folderRelative, EnumSet.of(AccessMode.READ));
fs.checkAccess(file, EnumSet.of(AccessMode.READ));
fs.checkAccess(fileRelative, EnumSet.of(AccessMode.READ));
expectException(() -> fs.checkAccess(nonExistent, EnumSet.of(AccessMode.READ)), NoSuchFileException.class);
expectException(() -> fs.checkAccess(folder, null), NullPointerException.class);
expectException(() -> fs.checkAccess(folder, EnumSet.of(AccessMode.READ), (LinkOption[]) null), NullPointerException.class);
expectException(() -> fs.checkAccess(folder, EnumSet.of(AccessMode.READ), new LinkOption[]{null}), NullPointerException.class);
}
@Test
public void testCopy() throws IOException {
Path targetRelative = Files.createDirectory(workDir.resolve("testCopy"));
Path target = fs.toAbsolutePath(targetRelative);
expectException(() -> fs.copy(file, targetRelative), FileAlreadyExistsException.class);
expectException(() -> fs.copy(folder, targetRelative), FileAlreadyExistsException.class);
expectException(() -> fs.copy(file, targetRelative, new CopyOption() {
}), UnsupportedOperationException.class);
Path fileInTarget = Files.createFile(targetRelative.resolve("file"));
expectException(() -> fs.copy(file, targetRelative, StandardCopyOption.REPLACE_EXISTING), DirectoryNotEmptyException.class);
Files.delete(fileInTarget);
expectException(() -> fs.copy(null, targetRelative), NullPointerException.class);
expectException(() -> fs.copy(file, null), NullPointerException.class);
expectException(() -> fs.copy(file, targetRelative, (CopyOption[]) null), NullPointerException.class);
expectException(() -> fs.copy(file, targetRelative, new CopyOption[]{null}), NullPointerException.class);
fs.copy(file, target, StandardCopyOption.REPLACE_EXISTING);
fs.copy(folder, target, StandardCopyOption.REPLACE_EXISTING);
fs.copy(fileRelative, target, StandardCopyOption.REPLACE_EXISTING);
fs.copy(file, targetRelative, StandardCopyOption.REPLACE_EXISTING);
}
@Test
public void testCreateDirectory() throws IOException {
expectException(() -> fs.createDirectory(file), FileAlreadyExistsException.class);
expectException(() -> fs.createDirectory(folder, ATTR_UNKNOWN), UnsupportedOperationException.class);
expectException(() -> fs.createDirectory(null), NullPointerException.class);
Path targetRelative = workDir.resolve("testCreateDirectory");
Path target = fs.toAbsolutePath(workDir.resolve("testCreateDirectory2"));
expectException(() -> fs.createDirectory(targetRelative, (FileAttribute[]) null), NullPointerException.class);
expectException(() -> fs.createDirectory(targetRelative, new FileAttribute<?>[]{null}), NullPointerException.class);
fs.createDirectory(target);
fs.createDirectory(targetRelative);
}
@Test
public void testCreateLink() throws IOException {
Path targetRelative = workDir.resolve("testCreateLink");
Path target = fs.toAbsolutePath(workDir.resolve("testCreateLink2"));
try {
fs.createLink(targetRelative, fileRelative);
} catch (UnsupportedOperationException uoe) {
return;
}
expectException(() -> fs.createLink(targetRelative, null), NullPointerException.class);
expectException(() -> fs.createLink(null, file), NullPointerException.class);
fs.createLink(target, file);
}
@Test
public void testCreateSymLink() throws IOException {
Path targetRelative = workDir.resolve("testCreateSymLink");
Path target = fs.toAbsolutePath(workDir.resolve("testCreateSymLink2"));
try {
fs.createSymbolicLink(targetRelative, fileRelative);
} catch (UnsupportedOperationException uoe) {
return;
}
expectException(() -> fs.createSymbolicLink(targetRelative, null), NullPointerException.class);
expectException(() -> fs.createSymbolicLink(null, file), NullPointerException.class);
expectException(() -> fs.createSymbolicLink(targetRelative, file, (FileAttribute<?>[]) null), NullPointerException.class);
expectException(() -> fs.createSymbolicLink(targetRelative, file, new FileAttribute<?>[]{null}), NullPointerException.class);
expectException(() -> fs.createSymbolicLink(targetRelative, file, ATTR_UNKNOWN), UnsupportedOperationException.class);
fs.createSymbolicLink(target, file);
}
@Test
public void testDelete() throws IOException {
Path targetRelative = workDir.resolve("testDelete");
Path target = fs.toAbsolutePath(workDir.resolve("testDelete2"));
expectException(() -> fs.delete(targetRelative), NoSuchFileException.class);
expectException(() -> fs.delete(null), NullPointerException.class);
Files.createDirectory(targetRelative);
fs.delete(targetRelative);
Files.createFile(targetRelative);
fs.delete(targetRelative);
Files.createFile(target);
fs.delete(target);
}
@Test
public void testGetEncoding() {
expectException(() -> fs.getEncoding(null), NullPointerException.class);
Assert.assertNull(fs.getEncoding(file));
Assert.assertNull(fs.getEncoding(fileRelative));
}
@Test
public void testMimeType() {
expectException(() -> fs.getMimeType(null), NullPointerException.class);
Assert.assertNull(fs.getMimeType(file));
Assert.assertNull(fs.getMimeType(fileRelative));
}
@Test
public void testGetPathSeparator() {
Assert.assertEquals(File.pathSeparator, fs.getPathSeparator());
}
@Test
public void testGetSeparator() {
Assert.assertEquals(File.separator, fs.getSeparator());
}
@Test
public void testGetTempDirectory() {
Path tmp = fs.getTempDirectory();
Assert.assertNotNull(tmp);
Assert.assertTrue(Files.isDirectory(tmp));
}
@Test
public void testMove() throws IOException {
Path sourceFileRelative = Files.createFile(workDir.resolve("testMoveFile"));
Path sourceFolderRelative = Files.createDirectory(workDir.resolve("testMoveFolder"));
Path targetRelative = Files.createDirectory(workDir.resolve("testMoveTarget"));
Path target = fs.toAbsolutePath(targetRelative);
Path sourceFile = fs.toAbsolutePath(Files.createFile(workDir.resolve("testMoveFile2")));
expectException(() -> fs.move(sourceFileRelative, targetRelative), FileAlreadyExistsException.class);
expectException(() -> fs.move(sourceFolderRelative, targetRelative), FileAlreadyExistsException.class);
expectException(() -> fs.move(sourceFileRelative, targetRelative, new CopyOption() {
}), UnsupportedOperationException.class);
Path fileInTarget = Files.createFile(targetRelative.resolve("file"));
expectException(() -> fs.move(sourceFileRelative, targetRelative, StandardCopyOption.REPLACE_EXISTING), DirectoryNotEmptyException.class);
Files.delete(fileInTarget);
expectException(() -> fs.move(null, targetRelative), NullPointerException.class);
expectException(() -> fs.move(sourceFileRelative, null), NullPointerException.class);
expectException(() -> fs.move(sourceFileRelative, targetRelative, (CopyOption[]) null), NullPointerException.class);
expectException(() -> fs.move(sourceFileRelative, targetRelative, new CopyOption[]{null}), NullPointerException.class);
fs.move(sourceFileRelative, targetRelative, StandardCopyOption.REPLACE_EXISTING);
fs.move(sourceFolderRelative, targetRelative, StandardCopyOption.REPLACE_EXISTING);
fs.move(sourceFile, target, StandardCopyOption.REPLACE_EXISTING);
}
@Test
public void testNewByteChannel() throws IOException {
expectException(() -> fs.newByteChannel(null, Collections.emptySet()).close(), NullPointerException.class);
expectException(() -> fs.newByteChannel(file, null).close(), NullPointerException.class);
expectException(() -> fs.newByteChannel(file, Collections.singleton(null)).close(), NullPointerException.class);
Path targetRelative = workDir.resolve("testNewByteChannel");
expectException(() -> fs.newByteChannel(targetRelative, EnumSet.of(StandardOpenOption.CREATE), (FileAttribute<?>[]) null).close(), NullPointerException.class);
expectException(() -> fs.newByteChannel(targetRelative, EnumSet.of(StandardOpenOption.CREATE), new FileAttribute<?>[]{null}).close(), NullPointerException.class);
expectException(() -> fs.newByteChannel(targetRelative, EnumSet.of(StandardOpenOption.CREATE), ATTR_UNKNOWN).close(), UnsupportedOperationException.class);
expectException(() -> fs.newByteChannel(file, EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)).close(), FileAlreadyExistsException.class);
expectException(() -> fs.newByteChannel(targetRelative, Collections.emptySet()).close(), NoSuchFileException.class);
try (SeekableByteChannel ch = fs.newByteChannel(targetRelative, EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE))) {
Assert.assertTrue(ch instanceof FileChannel);
}
try (SeekableByteChannel ch = fs.newByteChannel(file, EnumSet.of(StandardOpenOption.READ))) {
Assert.assertTrue(ch instanceof FileChannel);
}
try (SeekableByteChannel ch = fs.newByteChannel(fileRelative, EnumSet.of(StandardOpenOption.READ))) {
Assert.assertTrue(ch instanceof FileChannel);
}
}
@Test
public void testNewDirectoryStream() throws IOException {
DirectoryStream.Filter<Path> allFilter = new DirectoryStream.Filter<Path>() {
@Override
public boolean accept(Path entry) throws IOException {
return true;
}
};
DirectoryStream.Filter<Path> errFilter = new DirectoryStream.Filter<Path>() {
@Override
public boolean accept(Path entry) throws IOException {
throw new RuntimeException();
}
};
Path targetRelative = Files.createDirectory(workDir.resolve("testNewDirectoryStream"));
Path target = fs.toAbsolutePath(targetRelative);
Path fileInTarget = Files.createFile(targetRelative.resolve("file"));
expectException(() -> fs.newDirectoryStream(null, allFilter).close(), NullPointerException.class);
expectException(() -> fs.newDirectoryStream(targetRelative, null).close(), NullPointerException.class);
expectException(() -> fs.newDirectoryStream(fileInTarget, allFilter).close(), NotDirectoryException.class);
try (DirectoryStream<Path> dir = fs.newDirectoryStream(targetRelative, allFilter)) {
Assert.assertTrue(StreamSupport.stream(dir.spliterator(), false).filter((p) -> p.getFileName().toString().equals("file")).findAny().isPresent());
}
try (DirectoryStream<Path> dir = fs.newDirectoryStream(target, allFilter)) {
Assert.assertTrue(StreamSupport.stream(dir.spliterator(), false).filter((p) -> p.getFileName().toString().equals("file")).findAny().isPresent());
}
expectException(() -> {
try (DirectoryStream<Path> dir = fs.newDirectoryStream(targetRelative, errFilter)) {
StreamSupport.stream(dir.spliterator(), false).toArray();
}
}, RuntimeException.class);
}
@Test
public void testReadAttributes() throws IOException {
expectException(() -> fs.readAttributes(null, "basic:*"), NullPointerException.class);
expectException(() -> fs.readAttributes(file, null), NullPointerException.class);
expectException(() -> fs.readAttributes(file, "basic:*", (LinkOption[]) null), NullPointerException.class);
expectException(() -> fs.readAttributes(file, "basic:*", new LinkOption[]{null}), NullPointerException.class);
expectException(() -> fs.readAttributes(file, "extended:*"), UnsupportedOperationException.class);
expectException(() -> fs.readAttributes(file, ""), IllegalArgumentException.class);
expectException(() -> fs.readAttributes(file, "basic:size+creationTime"), IllegalArgumentException.class);
expectException(() -> fs.readAttributes(file, "basic:size,creationTime,unknownAttr"), IllegalArgumentException.class);
Assert.assertEquals(1, fs.readAttributes(file, "basic:size").size());
Assert.assertEquals(2, fs.readAttributes(file, "basic:size,creationTime").size());
Assert.assertEquals(1, fs.readAttributes(file, "size").size());
Assert.assertFalse(fs.readAttributes(file, "basic:*").isEmpty());
Assert.assertFalse(fs.readAttributes(file, "*").isEmpty());
Assert.assertFalse(fs.readAttributes(fileRelative, "*").isEmpty());
}
@Test
public void testReadSymLink() throws IOException {
Path targetRelative = workDir.resolve("testReadSymLink");
Path target = fs.toAbsolutePath(workDir.resolve("testReadSymLink"));
try {
fs.createSymbolicLink(targetRelative, file);
} catch (UnsupportedOperationException uoe) {
return;
}
expectException(() -> fs.readSymbolicLink(null), NullPointerException.class);
expectException(() -> fs.readSymbolicLink(file), NotLinkException.class);
Assert.assertEquals(file, fs.readSymbolicLink(targetRelative));
Assert.assertEquals(file, fs.readSymbolicLink(target));
}
@Test
public void testSetAttribute() throws IOException {
expectException(() -> fs.setAttribute(null, "basic:lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis())), NullPointerException.class);
expectException(() -> fs.setAttribute(file, null, FileTime.fromMillis(System.currentTimeMillis())), NullPointerException.class);
expectException(() -> fs.setAttribute(file, "basic:lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis()), (LinkOption[]) null), NullPointerException.class);
expectException(() -> fs.setAttribute(file, "basic:lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis()), new LinkOption[]{null}), NullPointerException.class);
expectException(() -> fs.setAttribute(file, "basic:lastModifiedTime", System.currentTimeMillis()), ClassCastException.class);
expectException(() -> fs.setAttribute(file, "", System.currentTimeMillis()), IllegalArgumentException.class);
expectException(() -> fs.setAttribute(file, "*", System.currentTimeMillis()), IllegalArgumentException.class);
expectException(() -> fs.setAttribute(file, "basic:*", System.currentTimeMillis()), IllegalArgumentException.class);
expectException(() -> fs.setAttribute(file, "basic:size", System.currentTimeMillis()), IllegalArgumentException.class);
expectException(() -> fs.setAttribute(file, "basic:lastModifiedTime,creationTime", System.currentTimeMillis()), IllegalArgumentException.class);
expectException(() -> fs.setAttribute(file, "basic:unknownAttr", System.currentTimeMillis()), IllegalArgumentException.class);
expectException(() -> fs.setAttribute(file, "extended:lastModifiedTime", System.currentTimeMillis()), UnsupportedOperationException.class);
fs.setAttribute(file, "basic:lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis()));
fs.setAttribute(file, "lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis()));
fs.setAttribute(fileRelative, "lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis()));
}
@Test
public void testToAbsolutePath() {
expectException(() -> fs.toAbsolutePath(null), NullPointerException.class);
Assert.assertEquals(file, fs.toAbsolutePath(file));
Assert.assertEquals(file, fs.toAbsolutePath(fileRelative));
}
@Test
public void testToRealPath() throws IOException {
expectException(() -> fs.toRealPath(null), NullPointerException.class);
expectException(() -> fs.toRealPath(file, (LinkOption[]) null), NullPointerException.class);
expectException(() -> fs.toRealPath(file, new LinkOption[]{null}), NullPointerException.class);
Assert.assertEquals(file.toRealPath(), fs.toRealPath(file));
Assert.assertEquals(file.toRealPath(), fs.toRealPath(fileRelative));
}
@Test
public void testSetCurrentWorkingDirectory() {
expectException(() -> fs.setCurrentWorkingDirectory(null), NullPointerException.class);
expectException(() -> fs.setCurrentWorkingDirectory(file), IllegalArgumentException.class);
expectException(() -> fs.setCurrentWorkingDirectory(folderRelative), IllegalArgumentException.class);
}
@FunctionalInterface
private interface ExceptionOperation {
void run() throws Throwable;
}
private static void expectException(ExceptionOperation op, Class<? extends Throwable> expectedException) {
if (AssertionError.class.isAssignableFrom(expectedException)) {
throw new IllegalArgumentException("AssertionError is not supported as expectedException.");
}
try {
op.run();
Assert.fail(expectedException.getSimpleName() + " is expected.");
} catch (ThreadDeath td) {
throw td;
} catch (AssertionError ae) {
throw ae;
} catch (Throwable t) {
if (!expectedException.isInstance(t)) {
throw new AssertionError("Unexpected exception.", t);
}
}
}
private static void delete(Path toDelete) throws IOException {
if (Files.isDirectory(toDelete)) {
try (DirectoryStream<Path> dir = Files.newDirectoryStream(toDelete)) {
for (Path child : dir) {
delete(child);
}
}
}
Files.delete(toDelete);
}
}