| package org.purl.wf4ever.robundle.fs; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.IOException; |
| import java.net.URI; |
| import java.nio.channels.FileChannel; |
| import java.nio.file.DirectoryStream; |
| import java.nio.file.FileAlreadyExistsException; |
| import java.nio.file.FileSystem; |
| import java.nio.file.FileSystems; |
| import java.nio.file.Files; |
| import java.nio.file.NoSuchFileException; |
| import java.nio.file.Path; |
| import java.nio.file.StandardOpenOption; |
| import java.nio.file.attribute.FileTime; |
| import java.util.ArrayList; |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.TimeUnit; |
| import java.util.zip.ZipOutputStream; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.purl.wf4ever.robundle.Bundles; |
| |
| public class TestZipFS { |
| |
| private static Path zip; |
| private FileSystem fs; |
| |
| @Test |
| public void fileChannelCreateNew() throws Exception { |
| Path test = fs.getPath("test.txt"); |
| EnumSet<StandardOpenOption> options = |
| EnumSet.<StandardOpenOption>of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE); |
| fs.provider().newFileChannel(test, options); |
| } |
| |
| @Test |
| public void fileChannelCreate() throws Exception { |
| try { |
| Path test = fs.getPath("test.txt"); |
| FileChannel.open(test, StandardOpenOption.WRITE, StandardOpenOption.CREATE).close(); |
| } catch (NoSuchFileException ex) { |
| System.err.println("Unexpected exception"); |
| ex.printStackTrace(); |
| // Bug in JDK |
| } |
| } |
| |
| @Test(expected=FileAlreadyExistsException.class) |
| public void fileChannelCreateFails() throws Exception { |
| Path test = fs.getPath("test.txt"); |
| Files.createFile(test); |
| FileChannel.open(test, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW).close(); |
| } |
| |
| @Test |
| public void fileChannelTruncate() throws Exception { |
| Path test = fs.getPath("test.txt"); |
| Files.write(test, new byte[1024]); |
| assertEquals(1024, Files.size(test)); |
| FileChannel.open(test, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING).close(); |
| assertEquals(0, Files.size(test)); |
| } |
| |
| |
| /** |
| * Verifies http://stackoverflow.com/questions/16588321/ as both ZIP format |
| * and Java 7 ZIPFS allows a folder and file to have the same name. |
| * |
| */ |
| @Test |
| public void directoryOrFile() throws Exception { |
| Path folder = fs.getPath("folder"); |
| assertFalse(Files.exists(folder)); |
| Files.createFile(folder); |
| assertTrue(Files.exists(folder)); |
| assertTrue(Files.isRegularFile(folder)); |
| assertFalse(Files.isDirectory(folder)); |
| |
| try { |
| Path folderCreated = Files.createDirectory(folder); |
| assertEquals(folder, folderCreated); |
| folder = folderCreated; |
| System.out.println(folder + " " + folderCreated); |
| |
| // Disable for now, just to see where this leads |
| // fail("Should have thrown FileAlreadyExistsException"); |
| } catch (FileAlreadyExistsException ex) { |
| } |
| |
| // For some reason the second createDirectory() fails correctly |
| try { |
| Files.createDirectory(folder); |
| fail("Should have thrown FileAlreadyExistsException"); |
| } catch (FileAlreadyExistsException ex) { |
| } |
| |
| Path child = folder.resolve("child"); |
| Files.createFile(child); |
| |
| // Look, it's both a file and folder! |
| // Can this be asserted? |
| assertTrue(Files.isRegularFile(folder)); |
| // Yes, if you include the final / |
| assertTrue(Files.isDirectory(fs.getPath("folder/"))); |
| // But not the parent |
| // assertTrue(Files.isDirectory(child.getParent())); |
| // Or the original Path |
| // assertTrue(Files.isDirectory(folder)); |
| |
| fs.close(); |
| // What if we open it again.. can we find both? |
| try (FileSystem fs2 = FileSystems.newFileSystem(zip, null)) { |
| assertTrue(Files.isRegularFile(fs2.getPath("folder"))); |
| assertTrue(Files.isRegularFile(fs2.getPath("folder/child"))); |
| assertTrue(Files.isDirectory(fs2.getPath("folder/"))); |
| |
| // We can even list the folder |
| try (DirectoryStream<Path> s = Files.newDirectoryStream(fs2 |
| .getPath("folder/"))) { |
| boolean found = false; |
| for (Path p : s) { |
| found = p.endsWith("child"); |
| } |
| assertTrue("Did not find 'child'", found); |
| } |
| // But if we list the root, do we find "folder" or "folder/"? |
| Path root = fs2.getRootDirectories().iterator().next(); |
| try (DirectoryStream<Path> s = Files.newDirectoryStream(root)) { |
| List<String> paths = new ArrayList<>(); |
| for (Path p : s) { |
| paths.add(p.toString()); |
| } |
| // We find both! |
| assertEquals(2, paths.size()); |
| assertTrue(paths.contains("/folder")); |
| assertTrue(paths.contains("/folder/")); |
| } |
| // SO does that mean this is a feature, and not a bug? |
| // See http://stackoverflow.com/questions/16588321/ for more |
| } |
| |
| } |
| |
| @Test |
| public void setLastModifiedTime() throws Exception { |
| Path root = fs.getRootDirectories().iterator().next(); |
| |
| Path folder = root.resolve("folder"); |
| Files.createDirectory(folder); |
| |
| Path file = root.resolve("file"); |
| Files.createFile(file); |
| |
| |
| FileTime someTimeAgo = FileTime.from(365*12, TimeUnit.DAYS); |
| Files.setLastModifiedTime(folder, someTimeAgo); |
| Files.setLastModifiedTime(file, someTimeAgo); |
| try { |
| Files.setLastModifiedTime(root, someTimeAgo); |
| } catch (NoSuchFileException ex) { |
| System.err.println("Unexpected failure of setLastModifiedTime on root"); |
| ex.printStackTrace(); |
| } |
| } |
| |
| @Before |
| public void tempZipFS() throws Exception { |
| zip = Files.createTempFile("test", ".zip"); |
| Files.delete(zip); |
| System.out.println(zip); |
| URI jar = new URI("jar", zip.toUri().toString(), null); |
| Map<String, Object> env = new HashMap<>(); |
| env.put("create", "true"); |
| fs = FileSystems.newFileSystem(jar, env); |
| } |
| |
| @After |
| public void deleteTempFS() throws IOException { |
| fs.close(); |
| Files.deleteIfExists(zip); |
| } |
| |
| /* http://stackoverflow.com/a/16584723/412540 */ |
| @Test |
| public void jarWithSpaces() throws Exception { |
| Path path = Files.createTempFile("with several spaces", ".zip"); |
| Files.delete(path); |
| path.toFile().deleteOnExit(); |
| |
| // Will fail with FileSystemNotFoundException without env: |
| //FileSystems.newFileSystem(path, null); |
| |
| // Neither does this work, as it does not double-escape: |
| // URI jar = URI.create("jar:" + path.toUri().toASCIIString()); |
| |
| URI jar = new URI("jar", path.toUri().toString(), null); |
| assertTrue(jar.toASCIIString().contains("with%2520several%2520spaces")); |
| |
| Map<String, Object> env = new HashMap<>(); |
| env.put("create", "true"); |
| |
| try (FileSystem fs = FileSystems.newFileSystem(jar, env)) { |
| URI root = fs.getPath("/").toUri(); |
| assertTrue(root.toString().contains("with%2520several%2520spaces")); |
| } |
| // Reopen from now-existing Path to check that the URI is |
| // escaped in the same way |
| try (FileSystem fs = FileSystems.newFileSystem(path, null)) { |
| URI root = fs.getPath("/").toUri(); |
| //System.out.println(root.toASCIIString()); |
| assertTrue(root.toString().contains("with%2520several%2520spaces")); |
| } |
| } |
| |
| /** |
| * See http://stackoverflow.com/a/14034572/412540 - spaces in filename seems |
| * broken in Java 8. This test passes in Java 7 and should pass in Java 8 |
| * for regression testing. |
| */ |
| @Test |
| public void jarWithSpacesJava8() throws Exception { |
| |
| Path dir = Files.createTempDirectory("test"); |
| try { |
| dir.resolve("test"); |
| |
| Path path = dir.resolve("with several spaces.zip"); |
| |
| // Make empty zip file - the old way! |
| try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream( |
| path, StandardOpenOption.CREATE, |
| StandardOpenOption.TRUNCATE_EXISTING))) { |
| out.closeEntry(); |
| } |
| |
| Map<String, Object> env = new HashMap<>(); |
| |
| URI root; |
| // Open by path |
| try (FileSystem fs = FileSystems.newFileSystem(path, null)) { |
| // Works fine |
| root = fs.getPath("/").toUri(); |
| //System.out.println(root.toASCIIString()); |
| |
| // Double-escaped, as expected and compatible with Java 7 |
| assertTrue(root.toString().contains("with%2520several%2520spaces.zip")) ; |
| } |
| |
| // Open it again from the URI |
| try (FileSystem fs = FileSystems.newFileSystem(root, env)) { |
| root = fs.getPath("/").toUri(); |
| //System.out.println(root.toASCIIString()); |
| assertTrue(root.toString().contains("with%2520several%2520spaces.zip")); |
| } |
| |
| // What if we construct the JAR URI as in Java 7? |
| URI jar = new URI("jar", path.toUri().toString(), null); |
| try (FileSystem fs = FileSystems.newFileSystem(jar, env)) { |
| root = fs.getPath("/").toUri(); |
| //System.out.println(root.toASCIIString()); |
| assertTrue(root.toString().contains("with%2520several%2520spaces.zip")); |
| } |
| |
| // OK, let's just create one and see what we get |
| env.put("create", "true"); |
| Files.delete(path); |
| |
| try (FileSystem fs = FileSystems.newFileSystem(jar, env)) { |
| root = fs.getPath("/").toUri(); |
| //System.out.println(root.toASCIIString()); |
| assertTrue(root.toString().contains("with%2520several%2520spaces.zip")); |
| } |
| |
| try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { |
| for (Path file : stream) { |
| assertEquals("with several spaces.zip", file.getFileName().toString()); |
| // not with%20several%20spaces.zip |
| } |
| } |
| |
| } finally { |
| Bundles.deleteRecursively(dir); |
| } |
| |
| } |
| |
| } |