diff --git a/JavaLibrary.mk b/JavaLibrary.mk index 04c5fcbf7..382d9ee79 100644 --- a/JavaLibrary.mk +++ b/JavaLibrary.mk @@ -212,7 +212,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ core-tests-support \ mockwebserver \ nist-pkix-tests \ - sqlite-jdbc + sqlite-jdbc \ + junit-params LOCAL_JAVACFLAGS := $(local_javac_flags) LOCAL_ERROR_PRONE_FLAGS := -Xep:TryFailThrowable:ERROR LOCAL_JAVA_LANGUAGE_VERSION := 1.8 @@ -360,7 +361,7 @@ ifeq ($(LIBCORE_SKIP_TESTS),) LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs) LOCAL_NO_STANDARD_LIBRARIES := true LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex okhttp-hostdex bouncycastle-hostdex core-junit-hostdex junit4-target-hostdex core-tests-support-hostdex mockito-api-hostdex - LOCAL_STATIC_JAVA_LIBRARIES := sqlite-jdbc-host mockwebserver-host nist-pkix-tests-host core-test-rules-hostdex + LOCAL_STATIC_JAVA_LIBRARIES := sqlite-jdbc-host mockwebserver-host nist-pkix-tests-host core-test-rules-hostdex junit-params-hostdex LOCAL_JAVACFLAGS := $(local_javac_flags) LOCAL_MODULE_TAGS := optional LOCAL_JAVA_LANGUAGE_VERSION := 1.8 diff --git a/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java index 8ecf72d15..06286f00a 100644 --- a/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java +++ b/luni/src/test/java/libcore/java/nio/channels/FileChannelTest.java @@ -24,8 +24,20 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.spi.FileSystemProvider; +import java.util.HashSet; +import java.util.Set; import libcore.io.IoUtils; +import static java.nio.file.StandardOpenOption.READ; +import static java.nio.file.StandardOpenOption.WRITE; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class FileChannelTest extends junit.framework.TestCase { public void testReadOnlyByteArrays() throws Exception { ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer(); @@ -255,4 +267,55 @@ private static FileChannel createFileContainingBytes(byte[] bytes) throws IOExce return fc; } + + /** + * The test verifies that FileChannel#open(Path, Set, FileAttribute ...) returns the + * same object returned by #newFileChannel(Path, Set, FileAttribute ...) method + * in given Paths's FileSystemProvider. + */ + public void test_open_Path_Set_FileAttributes() throws IOException { + Path mockPath = mock(Path.class); + FileSystem mockFileSystem = mock(FileSystem.class); + FileSystemProvider mockFileSystemProvider = mock(FileSystemProvider.class); + FileChannel mockFileChannel = mock(FileChannel.class); + + FileAttribute mockFileAttribute1 = mock(FileAttribute.class); + FileAttribute mockFileAttribute2 = mock(FileAttribute.class); + + Set standardOpenOptions = new HashSet<>(); + standardOpenOptions.add(READ); + standardOpenOptions.add(WRITE); + + when(mockPath.getFileSystem()).thenReturn(mockFileSystem); + when(mockFileSystem.provider()).thenReturn(mockFileSystemProvider); + when(mockFileSystemProvider.newFileChannel(mockPath, standardOpenOptions, + mockFileAttribute1, mockFileAttribute2)).thenReturn(mockFileChannel); + + assertEquals(mockFileChannel, FileChannel.open(mockPath, standardOpenOptions, + mockFileAttribute1, mockFileAttribute2)); + } + + /** + * The test verifies that FileChannel#open(Path, OpenOption ...) returns the + * same object returned by #newFileChannel(Path, OpenOption ...) method + * in given Paths's FileSystemProvider. + */ + public void test_open_Path_OpenOptions() throws IOException { + + Path mockPath = mock(Path.class); + FileSystem mockFileSystem = mock(FileSystem.class); + FileSystemProvider mockFileSystemProvider = mock(FileSystemProvider.class); + FileChannel mockFileChannel = mock(FileChannel.class); + + Set standardOpenOptions = new HashSet<>(); + standardOpenOptions.add(READ); + standardOpenOptions.add(WRITE); + + when(mockPath.getFileSystem()).thenReturn(mockFileSystem); + when(mockFileSystem.provider()).thenReturn(mockFileSystemProvider); + when(mockFileSystemProvider.newFileChannel(mockPath, standardOpenOptions)) + .thenReturn(mockFileChannel); + + assertEquals(mockFileChannel, FileChannel.open(mockPath, READ, WRITE)); + } } diff --git a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java index 04be66225..564f7c919 100644 --- a/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java +++ b/luni/src/test/java/libcore/java/nio/file/DefaultFileSystemProvider2Test.java @@ -19,8 +19,12 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.NonReadableChannelException; import java.nio.file.CopyOption; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.DirectoryStream; @@ -29,18 +33,34 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.NotLinkException; +import java.nio.file.OpenOption; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.FileTime; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; import java.nio.file.spi.FileSystemProvider; +import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + import static java.nio.file.StandardCopyOption.ATOMIC_MOVE; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static java.nio.file.StandardOpenOption.APPEND; +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.READ; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; +import static java.nio.file.StandardOpenOption.WRITE; import static junit.framework.TestCase.assertNotNull; import static junit.framework.TestCase.assertTrue; import static libcore.java.nio.file.FilesSetup.DATA_FILE; @@ -53,6 +73,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.fail; +@RunWith(JUnitParamsRunner.class) public class DefaultFileSystemProvider2Test { @Rule @@ -362,4 +383,249 @@ public void test_setAttribute() throws IOException { fail(); } catch (NullPointerException expected) {} } + + @Test + public void test_newFileChannel() throws IOException { + Set openOptions = new HashSet<>(); + + // When file doesn't exist/ + try { + // With CREATE & WRITE in OpenOptions. + openOptions.add(CREATE); + openOptions.add(WRITE); + provider.newFileChannel(filesSetup.getTestPath(), openOptions); + assertTrue(Files.exists(filesSetup.getTestPath())); + Files.delete(filesSetup.getTestPath()); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + try { + // With CREATE & APPEND in OpenOption. + assertFalse(Files.exists(filesSetup.getTestPath())); + openOptions.add(CREATE); + openOptions.add(APPEND); + provider.newFileChannel(filesSetup.getTestPath(), openOptions); + assertTrue(Files.exists(filesSetup.getTestPath())); + Files.delete(filesSetup.getTestPath()); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + // When file exists. + try { + FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions); + assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc)); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + try { + // When file exists and READ in OpenOptions. + openOptions.add(READ); + FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions); + assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc)); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + // Reading from a file opened with WRITE. + try { + openOptions.add(WRITE); + FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions); + assertEquals(filesSetup.TEST_FILE_DATA, readFromFileChannel(fc)); + fail(); + } catch (NonReadableChannelException expected) { + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + // Writing to an exiting file. + try { + openOptions.add(WRITE); + FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions); + writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2); + fc.close(); + assertEquals(overlayString1OnString2(TEST_FILE_DATA_2, TEST_FILE_DATA), + readFromFile(filesSetup.getDataFilePath())); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + // APPEND to an existing file. + try { + openOptions.add(WRITE); + openOptions.add(TRUNCATE_EXISTING); + FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions); + writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2); + fc.close(); + assertEquals(TEST_FILE_DATA_2, readFromFile(filesSetup.getDataFilePath())); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + // TRUNCATE an existing file. + try { + openOptions.add(WRITE); + openOptions.add(APPEND); + FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions); + writeToFileChannel(fc, filesSetup.TEST_FILE_DATA_2); + fc.close(); + assertEquals(TEST_FILE_DATA + TEST_FILE_DATA_2, readFromFile(filesSetup.getDataFilePath())); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + } + + @Test + @Parameters(method = "parameters_test_newFileChannel_NoSuchFileException") + public void test_newFileChannel_NoSuchFileException(Set openOptions) + throws IOException { + try { + provider.newFileChannel(filesSetup.getTestPath(), openOptions); + fail(); + } catch (NoSuchFileException expected) {} + } + + @SuppressWarnings("unused") + private Object[] parameters_test_newFileChannel_NoSuchFileException() { + return new Object[] { + new Object[] { EnumSet.noneOf(StandardOpenOption.class) }, + new Object[] { EnumSet.of(READ) }, + new Object[] { EnumSet.of(WRITE) }, + new Object[] { EnumSet.of(TRUNCATE_EXISTING) }, + new Object[] { EnumSet.of(APPEND) }, + new Object[] { EnumSet.of(CREATE, READ) }, + new Object[] { EnumSet.of(CREATE, TRUNCATE_EXISTING) }, + new Object[] { EnumSet.of(CREATE, READ) }, + }; + } + + @Test + public void test_newFileChannel_withFileAttributes() throws IOException { + Set openOptions = new HashSet<>(); + FileTime fileTime = FileTime.fromMillis(System.currentTimeMillis()); + Files.setAttribute(filesSetup.getDataFilePath(), "basic:lastModifiedTime", fileTime); + FileAttribute unsupportedAttr = new MockFileAttribute<>( + "basic:lastModifiedTime", fileTime); + + Set perm = PosixFilePermissions.fromString("rwx------"); + FileAttribute> supportedAttr = + PosixFilePermissions.asFileAttribute(perm); + + try { + // When file doesn't exists and with OpenOption CREATE & WRITE. + openOptions.clear(); + openOptions.add(CREATE); + openOptions.add(WRITE); + provider.newFileChannel(filesSetup.getTestPath(), openOptions, unsupportedAttr); + fail(); + } catch (UnsupportedOperationException expected) { + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + try { + // With OpenOption CREATE & WRITE. + openOptions.clear(); + openOptions.add(CREATE); + openOptions.add(WRITE); + provider.newFileChannel(filesSetup.getTestPath(), openOptions, supportedAttr); + assertEquals(supportedAttr.value(), Files.getAttribute(filesSetup.getTestPath(), + supportedAttr.name())); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + // When file exists. + try { + provider.newFileChannel(filesSetup.getDataFilePath(), openOptions, + unsupportedAttr); + fail(); + } catch (UnsupportedOperationException expected) { + } finally { + filesSetup.reset(); + openOptions.clear(); + } + + // When file exists. No change in permissions. + try { + Set originalPermissions= (Set) + Files.getAttribute(filesSetup.getDataFilePath(), supportedAttr.name()); + FileChannel fc = provider.newFileChannel(filesSetup.getDataFilePath(), openOptions, + supportedAttr); + assertEquals(originalPermissions, Files.getAttribute(filesSetup.getDataFilePath(), + supportedAttr.name())); + } finally { + filesSetup.reset(); + openOptions.clear(); + } + } + + + @Test + public void test_newFileChannel_NPE() throws IOException { + try { + provider.newByteChannel(null, new HashSet<>(), new MockFileAttribute<>()); + fail(); + } catch (NullPointerException expected) {} + + try { + provider.newByteChannel(filesSetup.getTestPath(), null, new MockFileAttribute<>()); + fail(); + } catch (NullPointerException expected) {} + + try { + provider.newByteChannel(filesSetup.getTestPath(), new HashSet<>(), null); + fail(); + } catch (NullPointerException expected) {} + } + + String readFromFileChannel(FileChannel fc) throws IOException { + ByteBuffer bb = ByteBuffer.allocate(20); + fc.read(bb); + return new String(bb.array(), "UTF-8").trim(); + } + + void writeToFileChannel(FileChannel fc, String data) throws IOException { + fc.write(ByteBuffer.wrap(data.getBytes())); + } + + String overlayString1OnString2(String s1, String s2) { + return s1 + s2.substring(s1.length()); + } + + static class MockFileAttribute implements FileAttribute { + + String name; + T value; + + MockFileAttribute() { + } + + MockFileAttribute(String name, T value) { + this.name = name; + this.value = value; + } + + @Override + public String name() { + return name; + } + + @Override + public T value() { + return value; + } + } }