forked from junit-pioneer/junit-pioneer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP - initial work towards issue junit-pioneer#348
- Loading branch information
Showing
6 changed files
with
299 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* | ||
* Copyright 2016-2021 the original author or authors. | ||
* | ||
* All rights reserved. This program and the accompanying materials are | ||
* made available under the terms of the Eclipse Public License v2.0 which | ||
* accompanies this distribution and is available at | ||
* | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
*/ | ||
|
||
package org.junitpioneer.jupiter; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
// TODO: Consider adding and testing ElementType.FIELD | ||
@Target(ElementType.PARAMETER) | ||
public @interface New { | ||
|
||
Class<? extends ResourceFactory<?>> value(); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/* | ||
* Copyright 2016-2021 the original author or authors. | ||
* | ||
* All rights reserved. This program and the accompanying materials are | ||
* made available under the terms of the Eclipse Public License v2.0 which | ||
* accompanies this distribution and is available at | ||
* | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
*/ | ||
|
||
package org.junitpioneer.jupiter; | ||
|
||
public interface Resource<T> extends AutoCloseable { | ||
|
||
T get() throws Exception; | ||
|
||
@Override | ||
default void close() throws Exception { | ||
// no op by default | ||
} | ||
|
||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/org/junitpioneer/jupiter/ResourceFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/* | ||
* Copyright 2016-2021 the original author or authors. | ||
* | ||
* All rights reserved. This program and the accompanying materials are | ||
* made available under the terms of the Eclipse Public License v2.0 which | ||
* accompanies this distribution and is available at | ||
* | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
*/ | ||
|
||
package org.junitpioneer.jupiter; | ||
|
||
public interface ResourceFactory<T> extends AutoCloseable { | ||
|
||
Resource<T> create() throws Exception; | ||
|
||
@Override | ||
default void close() throws Exception { | ||
// no op by default | ||
} | ||
|
||
} |
65 changes: 65 additions & 0 deletions
65
src/main/java/org/junitpioneer/jupiter/ResourceManagerExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright 2016-2021 the original author or authors. | ||
* | ||
* All rights reserved. This program and the accompanying materials are | ||
* made available under the terms of the Eclipse Public License v2.0 which | ||
* accompanies this distribution and is available at | ||
* | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
*/ | ||
|
||
package org.junitpioneer.jupiter; | ||
|
||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.junit.jupiter.api.extension.ParameterContext; | ||
import org.junit.jupiter.api.extension.ParameterResolutionException; | ||
import org.junit.jupiter.api.extension.ParameterResolver; | ||
import org.junit.platform.commons.support.ReflectionSupport; | ||
|
||
public class ResourceManagerExtension implements ParameterResolver { | ||
|
||
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace | ||
.create(ResourceManagerExtension.class); | ||
|
||
@Override | ||
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) | ||
throws ParameterResolutionException { | ||
// TODO: Only return true if the parameter is annotated with @New or @Shared | ||
// TODO: Check that we're on a test method, rather than say a constructor or a before-each block? | ||
// return parameterContext.isAnnotated(New.class); | ||
return true; | ||
} | ||
|
||
@Override | ||
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) | ||
throws ParameterResolutionException { | ||
New newResourceAnnotation = parameterContext | ||
.findAnnotation(New.class) | ||
.orElseThrow(() -> { | ||
// TODO | ||
throw new UnsupportedOperationException("TODO"); | ||
}); | ||
ResourceFactory<?> resourceFactory = ReflectionSupport.newInstance(newResourceAnnotation.value()); | ||
// TODO: Put the resourceFactory in the store too? | ||
Resource<?> resource; | ||
try { | ||
resource = resourceFactory.create(); | ||
} | ||
catch (Exception e) { | ||
// TODO | ||
throw new UnsupportedOperationException("TODO"); | ||
} | ||
// TODO: Check that we're using a custom NAMESPACE | ||
extensionContext | ||
.getStore(ExtensionContext.Namespace.GLOBAL) | ||
.put("theResource", (ExtensionContext.Store.CloseableResource) resource::close); | ||
try { | ||
return resource.get(); | ||
} | ||
catch (Exception e) { | ||
// TODO | ||
throw new UnsupportedOperationException("TODO"); | ||
} | ||
} | ||
|
||
} |
76 changes: 76 additions & 0 deletions
76
src/main/java/org/junitpioneer/jupiter/TemporaryDirectory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright 2016-2021 the original author or authors. | ||
* | ||
* All rights reserved. This program and the accompanying materials are | ||
* made available under the terms of the Eclipse Public License v2.0 which | ||
* accompanies this distribution and is available at | ||
* | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
*/ | ||
|
||
package org.junitpioneer.jupiter; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.FileVisitResult; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.SimpleFileVisitor; | ||
import java.nio.file.attribute.BasicFileAttributes; | ||
|
||
public class TemporaryDirectory implements ResourceFactory<Path> { | ||
|
||
@Override | ||
public Resource<Path> create() throws Exception { | ||
return new Resource<Path>() { | ||
|
||
private Path tempDir; | ||
|
||
@Override | ||
public Path get() throws Exception { | ||
return (tempDir = Files.createTempDirectory("")); | ||
} | ||
|
||
@Override | ||
public void close() throws Exception { | ||
// TODO: Restore file permissions if needed. | ||
// See: https://github.com/junit-team/junit5/issues/2609 | ||
|
||
deleteRecursively(tempDir); | ||
} | ||
|
||
}; | ||
} | ||
|
||
@Override | ||
public void close() throws Exception { | ||
// TODO | ||
throw new UnsupportedOperationException("TODO in TemporaryDirectory#close"); | ||
} | ||
|
||
private void deleteRecursively(Path tempDir) throws IOException { | ||
// TODO: See how JUnit 5 recursively deletes temp directories, and if there's anything | ||
// it does that we don't, write unit tests to reproduce their behaviour. | ||
Files.walkFileTree(tempDir, new SimpleFileVisitor<Path>() { | ||
|
||
@Override | ||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { | ||
// TODO: Can we unit test that we don't throw an exception if | ||
// the dir being deleted doesn't exist anymore due to | ||
// a race condition? | ||
Files.delete(file); | ||
return FileVisitResult.CONTINUE; | ||
} | ||
|
||
@Override | ||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { | ||
// TODO: Can we unit test that we don't throw an exception if | ||
// the dir being deleted doesn't exist anymore due to | ||
// a race condition? | ||
Files.delete(dir); | ||
return FileVisitResult.CONTINUE; | ||
} | ||
|
||
}); | ||
} | ||
|
||
} |
89 changes: 89 additions & 0 deletions
89
src/test/java/org/junitpioneer/jupiter/ResourceManagerExtensionTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* Copyright 2016-2021 the original author or authors. | ||
* | ||
* All rights reserved. This program and the accompanying materials are | ||
* made available under the terms of the Eclipse Public License v2.0 which | ||
* accompanies this distribution and is available at | ||
* | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
*/ | ||
|
||
package org.junitpioneer.jupiter; | ||
|
||
import static java.nio.charset.StandardCharsets.UTF_8; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.util.List; | ||
import java.util.concurrent.CopyOnWriteArrayList; | ||
|
||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.MethodOrderer; | ||
import org.junit.jupiter.api.Order; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.TestInstance; | ||
import org.junit.jupiter.api.TestMethodOrder; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
|
||
@DisplayName("Resource manager extension") | ||
@ExtendWith(ResourceManagerExtension.class) | ||
// TODO: Do we need a test that checks a test case with LifeCycle.PER_METHOD? Ask maintainers. | ||
@TestInstance(TestInstance.Lifecycle.PER_CLASS) | ||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) | ||
class ResourceManagerExtensionTests { | ||
|
||
private Path firstRecordedTempDir; | ||
private final List<Path> recordedTempDirs = new CopyOnWriteArrayList<>(); | ||
|
||
// TODO: Consider adding a constructor with a @New(TemporaryDirectory.class) Path | ||
|
||
@DisplayName("should populate a @New(TemporaryDirectory.class)-annotated parameter with a temp dir resource") | ||
@Order(0) | ||
@Test | ||
void shouldPopulateNewAnnotatedParameterWithTempDirResource(@New(TemporaryDirectory.class) Path tempDir) { | ||
assertThat(tempDir).startsWith(Paths.get(System.getProperty("java.io.tmpdir"))); | ||
|
||
firstRecordedTempDir = tempDir; | ||
recordedTempDirs.add(tempDir); | ||
} | ||
|
||
@DisplayName("should tear down the new resource at the end") | ||
@Order(1) | ||
@Test | ||
void shouldTearDownNewResourceAtTheEnd() { | ||
assertThat(firstRecordedTempDir).doesNotExist(); | ||
} | ||
|
||
@DisplayName("should populate a second @New(TemporaryDirectory.class)-annotated parameter with a temp dir resource") | ||
@Order(2) | ||
@Test | ||
void shouldPopulateSecondNewAnnotatedParameterWithTempDirResource(@New(TemporaryDirectory.class) Path tempDir) { | ||
assertThat(tempDir).startsWith(Paths.get(System.getProperty("java.io.tmpdir"))); | ||
|
||
recordedTempDirs.add(tempDir); | ||
} | ||
|
||
@DisplayName("should populate @New(TemporaryDirectory.class)-annotated parameters with writeable temp dirs") | ||
@Order(2) | ||
@Test | ||
void shouldPopulateNewAnnotatedParametersWithWriteableTempDirs(@New(TemporaryDirectory.class) Path tempDir) | ||
throws Exception { | ||
Files.write(tempDir.resolve("file.txt"), "some random text".getBytes(UTF_8)); | ||
assertThat(tempDir.resolve("file.txt")).usingCharset(UTF_8).hasContent("some random text"); | ||
|
||
recordedTempDirs.add(tempDir); | ||
} | ||
|
||
@DisplayName("should have generated new resources each time @New was used") | ||
@Order(3) | ||
@Test | ||
void shouldHaveGeneratedNewResourcesEachTimeNewAnnotationWasUsed() { | ||
int numberOfNewTempDirsInThisClass = 3; | ||
assertThat(recordedTempDirs).hasSize(numberOfNewTempDirsInThisClass); | ||
assertThat(recordedTempDirs.stream().distinct()).hasSize(numberOfNewTempDirsInThisClass); | ||
} | ||
|
||
// TODO: Write and test with two custom ResourceFactory implementations: jimfs and OkHttp's MockWebServer | ||
} |