diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-RC1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-RC1.adoc index de5d8d10c2a7..41467f50ac58 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-RC1.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.10.0-RC1.adoc @@ -64,6 +64,8 @@ JUnit repository on GitHub. the documentation for extension registration via `@ExtendWith` on fields. * The scope of applicability for `TestWatcher` implementations is now more extensively documented in the User Guide and Javadoc. +* `@TempDir` now successfully cleans up files and directories on Windows that are set to + read-only. [[release-notes-5.10.0-RC1-junit-vintage]] diff --git a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java index d8dbdd3776a3..0c41baa4724b 100644 --- a/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java +++ b/junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/extension/TempDirectory.java @@ -33,6 +33,7 @@ import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.DosFileAttributeView; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -390,6 +391,15 @@ private static void tryToResetPermissions(Path path) { if (Files.isDirectory(path)) { file.setExecutable(true); } + DosFileAttributeView dos = Files.getFileAttributeView(path, DosFileAttributeView.class); + if (dos != null) { + try { + dos.setReadOnly(false); + } + catch (IOException ignore) { + // nothing we can do + } + } } private IOException createIOExceptionWithAttachedFailures(SortedMap failures) { diff --git a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java index 84addd7dd905..4515d33b27fb 100644 --- a/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java +++ b/junit-jupiter-engine/src/test/java/org/junit/jupiter/engine/extension/TempDirectoryPerContextTests.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.attribute.DosFileAttributeView; import java.util.Deque; import java.util.LinkedList; import java.util.function.Supplier; @@ -47,8 +48,6 @@ import org.junit.jupiter.api.TestInfo; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.ExtensionConfigurationException; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterResolutionException; @@ -126,7 +125,6 @@ void nonMintPermissionsDoNotCauseFailure() { } @Test - @DisabledOnOs(OS.WINDOWS) @DisplayName("is capable of removing a read-only file in a read-only dir") void readOnlyFileInReadOnlyDirDoesNotCauseFailure() { executeTestsForClass(ReadOnlyFileInReadOnlyDirDoesNotCauseFailureTestCase.class).testEvents()// @@ -134,7 +132,6 @@ void readOnlyFileInReadOnlyDirDoesNotCauseFailure() { } @Test - @DisabledOnOs(OS.WINDOWS) @DisplayName("is capable of removing a read-only file in a dir in a read-only dir") void readOnlyFileInNestedReadOnlyDirDoesNotCauseFailure() { executeTestsForClass(ReadOnlyFileInDirInReadOnlyDirDoesNotCauseFailureTestCase.class).testEvents()// @@ -942,8 +939,8 @@ static class ReadOnlyFileInReadOnlyDirDoesNotCauseFailureTestCase { void createReadOnlyFileInReadOnlyDir(@TempDir File tempDir) throws IOException { File file = tempDir.toPath().resolve("file").toFile(); assumeTrue(file.createNewFile()); - assumeTrue(tempDir.setReadOnly()); - assumeTrue(file.setReadOnly()); + assumeTrue(makeReadOnly(tempDir)); + assumeTrue(makeReadOnly(file)); } } @@ -956,13 +953,22 @@ void createReadOnlyFileInReadOnlyDir(@TempDir File tempDir) throws IOException { File file = tempDir.toPath().resolve("dir").resolve("file").toFile(); assumeTrue(file.getParentFile().mkdirs()); assumeTrue(file.createNewFile()); - assumeTrue(tempDir.setReadOnly()); - assumeTrue(file.getParentFile().setReadOnly()); - assumeTrue(file.setReadOnly()); + assumeTrue(makeReadOnly(tempDir)); + assumeTrue(makeReadOnly(file.getParentFile())); + assumeTrue(makeReadOnly(file)); } } + private static boolean makeReadOnly(File file) throws IOException { + var dos = Files.getFileAttributeView(file.toPath(), DosFileAttributeView.class); + if (dos != null) { + dos.setReadOnly(true); + return true; + } + return file.setReadOnly(); + } + // https://github.com/junit-team/junit5/issues/2609 @SuppressWarnings("ResultOfMethodCallIgnored") static class NonMintPermissionContentInTempDirectoryDoesNotCauseFailureTestCase {