diff --git a/pom.xml b/pom.xml index 75e3df0..0ec8511 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ repo - + @@ -360,7 +360,7 @@ - + true @@ -433,7 +433,7 @@ com.github.marschall.memoryfilesystem com.github.marschall.memoryfilesystem,com.github.marschall.memoryfilesystem.memory - java.annotation,jakarta.annotation + java.annotation,jakarta.annotation,java.prefs java.nio.file.spi.FileSystemProvider diff --git a/src/test/java/com/github/marschall/memoryfilesystem/AdminChecker.java b/src/test/java/com/github/marschall/memoryfilesystem/AdminChecker.java new file mode 100644 index 0000000..3d32598 --- /dev/null +++ b/src/test/java/com/github/marschall/memoryfilesystem/AdminChecker.java @@ -0,0 +1,41 @@ +package com.github.marschall.memoryfilesystem; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.prefs.Preferences; + +/** + * Checks if the current user is the local administrator + *

+ * Adapted from this Stack Overflow answer. + */ +public class AdminChecker { + public static final boolean IS_ADMIN = isRunningAsAdministrator(); + + private static boolean isRunningAsAdministrator() { + Preferences systemPrefs = Preferences.systemRoot(); + synchronized (System.err) { + PrintStream stdErrOriginal = System.err; + try (PrintStream stdErrMock = new PrintStream(new MockOutputStream())) { + System.setErr(stdErrMock); + try { + systemPrefs.put("foo", "bar"); // SecurityException on Windows + systemPrefs.remove("foo"); + systemPrefs.flush(); // BackingStoreException on Linux + return true; + } + catch (Exception exception) { + return false; + } + } + finally { + System.setErr(stdErrOriginal); + } + } + } + + private static class MockOutputStream extends OutputStream { + @Override + public void write(int b) {} + } +} diff --git a/src/test/java/com/github/marschall/memoryfilesystem/FileSystemCompatibilityTest.java b/src/test/java/com/github/marschall/memoryfilesystem/FileSystemCompatibilityTest.java index 3d0efce..9198766 100644 --- a/src/test/java/com/github/marschall/memoryfilesystem/FileSystemCompatibilityTest.java +++ b/src/test/java/com/github/marschall/memoryfilesystem/FileSystemCompatibilityTest.java @@ -40,7 +40,9 @@ import java.util.List; import java.util.stream.Stream; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -277,6 +279,10 @@ void regression93(boolean useDefault) { @CompatibilityTest void newDirectoryStreamFollowSymlinks(boolean useDefault) throws IOException { + Assumptions.assumeFalse( + useDefault && OS.current().equals(OS.WINDOWS) && !AdminChecker.IS_ADMIN, + "skip symbolic link test on Windows default file system, if not admin" + ); FileSystem fileSystem = this.getFileSystem(useDefault); Path target = fileSystem.getPath("target"); if (!useDefault) { @@ -326,6 +332,11 @@ void manyDots(boolean useDefault) throws IOException { @CompatibilityTest void relativeSymlinks(boolean useDefault) throws IOException { + Assumptions.assumeFalse( + useDefault && OS.current().equals(OS.WINDOWS) && !AdminChecker.IS_ADMIN, + "skip symbolic link test on Windows default file system, if not admin" + ); + FileSystem fileSystem = this.getFileSystem(useDefault); Path target = fileSystem.getPath("target"); if (!useDefault) { diff --git a/src/test/java/com/github/marschall/memoryfilesystem/ZipFileSystemInteroperabilityTest.java b/src/test/java/com/github/marschall/memoryfilesystem/ZipFileSystemInteroperabilityTest.java index d86ef00..75adb4f 100644 --- a/src/test/java/com/github/marschall/memoryfilesystem/ZipFileSystemInteroperabilityTest.java +++ b/src/test/java/com/github/marschall/memoryfilesystem/ZipFileSystemInteroperabilityTest.java @@ -19,14 +19,19 @@ import java.util.Map; import java.util.jar.JarOutputStream; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.extension.RegisterExtension; class ZipFileSystemInteroperabilityTest { private static final String FS_URI = "jar:"; + // Avoid casts in FileSystems.newFileSystem(Path, ClassLoader) + private static final ClassLoader NULL_CLASS_LOADER = null; + private static final Map CREATE_ENV = Collections.singletonMap("create", "false"); + @RegisterExtension final FileSystemExtension extension = new FileSystemExtension(); @@ -43,25 +48,21 @@ void createZipFileSystem() throws IOException { } @Test - @Disabled("broken") + @EnabledForJreRange(min = JRE.JAVA_12, disabledReason = "nested zips only available on JDK 12+") void createNestedZips() throws IOException { FileSystem memoryFileSystem = this.extension.getFileSystem(); - Map env = Collections.singletonMap("create", "false"); Path outerZip = memoryFileSystem.getPath("/file.zip"); try (OutputStream stream = new JarOutputStream(Files.newOutputStream(outerZip, CREATE_NEW, WRITE))) { // nothing, just create an empty jar } - URI uri = URI.create(FS_URI + outerZip.toUri()); - try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { + try (FileSystem zipfs = FileSystems.newFileSystem(outerZip, NULL_CLASS_LOADER)) { Path innerZip = zipfs.getPath("hello.zip"); try (OutputStream stream = new JarOutputStream(Files.newOutputStream(innerZip, CREATE_NEW, WRITE))) { // nothing, just create an empty jar } - Map env2 = Collections.singletonMap("create", "false"); // locate file system by using the syntax // defined in java.net.JarURLConnection - URI uri2 = URI.create(FS_URI + innerZip.toUri()); - try (FileSystem zipfs2 = FileSystems.newFileSystem(uri2, env2)) { + try (FileSystem zipfs2 = FileSystems.newFileSystem(innerZip, NULL_CLASS_LOADER)) { try (BufferedWriter writer = Files.newBufferedWriter(zipfs2.getPath("hello.txt"), US_ASCII, CREATE_NEW, WRITE)) { writer.write("world"); } @@ -70,7 +71,7 @@ void createNestedZips() throws IOException { } @Test - @Disabled("broken upstream") + @EnabledForJreRange(min = JRE.JAVA_9, disabledReason = "zip FS path to URI conversion works on JDK 9+") void jarToUriRegression() throws IOException { Path jarFolder = Files.createTempDirectory("jartest"); try { @@ -97,9 +98,8 @@ void jarToUriRegressionFixed() throws IOException { // nothing, just create an empty jar } try { - Map env = Collections.singletonMap("create", "false"); URI uri = URI.create(FS_URI + jarFile.toUri()); - try (FileSystem jarfs = FileSystems.newFileSystem(uri, env)) { + try (FileSystem jarfs = FileSystems.newFileSystem(uri, CREATE_ENV)) { Path p = jarfs.getPath("hello.txt"); assertNotNull(Paths.get(p.toUri())); } @@ -109,23 +109,19 @@ void jarToUriRegressionFixed() throws IOException { } @Test - @Disabled("broken upstream") - void nestesJarsRegression() throws IOException { + @EnabledForJreRange(min = JRE.JAVA_12, disabledReason = "nested zips only available on JDK 12+") + void nestedJarsRegression() throws IOException { Path outerJar = Files.createTempFile("outer", ".jar"); try (OutputStream stream = new JarOutputStream(Files.newOutputStream(outerJar))) { // nothing, just create an empty jar } try { - Map outerEnv = Collections.singletonMap("create", "false"); - URI outerUri = URI.create(FS_URI + outerJar.toUri()); - try (FileSystem jarfs = FileSystems.newFileSystem(outerUri, outerEnv)) { + try (FileSystem jarfs = FileSystems.newFileSystem(outerJar, NULL_CLASS_LOADER)) { Path innerJar = jarfs.getPath("inner.jar"); try (OutputStream stream = new JarOutputStream(Files.newOutputStream(innerJar, CREATE_NEW, WRITE))) { // nothing, just create an empty jar } - Map innerEnv = Collections.singletonMap("create", "false"); - URI innerUri = URI.create(FS_URI + innerJar.toUri()); - try (FileSystem zipfs2 = FileSystems.newFileSystem(innerUri, innerEnv)) { + try (FileSystem zipfs2 = FileSystems.newFileSystem(innerJar, NULL_CLASS_LOADER)) { try (BufferedWriter writer = Files.newBufferedWriter(zipfs2.getPath("hello.txt"), US_ASCII, CREATE_NEW, WRITE)) { writer.write("world"); }