-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rework Ares IOTester registration, make custom implementation possible
This fixes #105 and should now be a completely satisfactory solution. We could now also add a system property to set the default IOManager on startup, if requested.
- Loading branch information
1 parent
582371d
commit e032d0e
Showing
32 changed files
with
533 additions
and
101 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
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,71 @@ | ||
package de.tum.in.test.api; | ||
|
||
import static java.lang.annotation.ElementType.*; | ||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.Inherited; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.Target; | ||
|
||
import org.apiguardian.api.API; | ||
import org.apiguardian.api.API.Status; | ||
|
||
import de.tum.in.test.api.io.AresIOContext; | ||
import de.tum.in.test.api.io.IOManager; | ||
import de.tum.in.test.api.io.IOTester; | ||
|
||
/** | ||
* Allows to overwrite the default IO test implementation of Ares with is using | ||
* {@link IOTester}. | ||
* <p> | ||
* A custom {@link IOManager} class must have a constructor that takes no | ||
* arguments and be accessible to Ares. All classes used for that purpose should | ||
* be trusted/whitelisted. | ||
* | ||
* @author Christian Femers | ||
* @since 1.9.1 | ||
* @version 1.0.0 | ||
* @see IOManager | ||
*/ | ||
@API(status = Status.EXPERIMENTAL) | ||
@Inherited | ||
@Documented | ||
@Retention(RUNTIME) | ||
@Target({ TYPE, METHOD, ANNOTATION_TYPE }) | ||
public @interface WithIOManager { | ||
|
||
/** | ||
* The {@link IOManager} implementation to use for testing in the annotated | ||
* element. | ||
*/ | ||
Class<? extends IOManager<?>> value(); | ||
|
||
/** | ||
* Effectively no {@link IOManager}. {@link System#out}, {@link System#err} and | ||
* {@link System#in} are unchanged. Not recommended. Consider a custom but | ||
* functional {@link IOManager} implementation first. | ||
*/ | ||
public final class None implements IOManager<Void> { | ||
|
||
@Override | ||
public void beforeTestExecution(AresIOContext context) { | ||
// do nothing | ||
} | ||
|
||
@Override | ||
public void afterTestExecution(AresIOContext context) { | ||
// do nothing | ||
} | ||
|
||
@Override | ||
public Void getControllerInstance(AresIOContext context) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public Class<Void> getControllerClass() { | ||
return null; | ||
} | ||
} | ||
} |
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,26 @@ | ||
package de.tum.in.test.api.context; | ||
|
||
import java.util.Objects; | ||
|
||
import org.apiguardian.api.API; | ||
import org.apiguardian.api.API.Status; | ||
|
||
@API(status = Status.INTERNAL) | ||
public abstract class AresContext { | ||
|
||
private final TestContext testContext; | ||
|
||
protected AresContext(TestContext testContext) { | ||
this.testContext = Objects.requireNonNull(testContext); | ||
} | ||
|
||
/** | ||
* Returns the current test context. | ||
* | ||
* @return the {@link TestContext}, never null. | ||
* @author Christian Femers | ||
*/ | ||
public final TestContext testContext() { | ||
return testContext; | ||
} | ||
} |
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
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
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
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
87 changes: 87 additions & 0 deletions
87
src/main/java/de/tum/in/test/api/internal/IOExtensionUtils.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,87 @@ | ||
package de.tum.in.test.api.internal; | ||
|
||
import static java.lang.invoke.MethodType.methodType; | ||
|
||
import java.lang.annotation.AnnotationFormatError; | ||
import java.lang.invoke.LambdaMetafactory; | ||
import java.lang.invoke.MethodHandles; | ||
import java.util.HashMap; | ||
import java.util.Objects; | ||
import java.util.function.Supplier; | ||
|
||
import org.apiguardian.api.API; | ||
import org.apiguardian.api.API.Status; | ||
|
||
import de.tum.in.test.api.WithIOManager; | ||
import de.tum.in.test.api.context.TestContext; | ||
import de.tum.in.test.api.context.TestContextUtils; | ||
import de.tum.in.test.api.io.AresIOContext; | ||
import de.tum.in.test.api.io.IOManager; | ||
import de.tum.in.test.api.io.IOTesterManager; | ||
import de.tum.in.test.api.security.ArtemisSecurityManager; | ||
|
||
@API(status = Status.INTERNAL) | ||
public final class IOExtensionUtils { | ||
|
||
private static final Class<IOTesterManager> DEFAULT_IO_MANAGER = IOTesterManager.class; | ||
|
||
static { | ||
/* | ||
* Initialize SecurityManager when we are still in the main thread | ||
*/ | ||
ArtemisSecurityManager.isInstalled(); | ||
} | ||
|
||
private static final HashMap<Class<? extends IOManager<?>>, Supplier<? extends IOManager<?>>> ioManagerCache = new HashMap<>(); | ||
|
||
private final AresIOContext context; | ||
private final IOManager<?> ioManager; | ||
private final Class<?> controllerClass; | ||
|
||
public IOExtensionUtils(TestContext testContext) { | ||
context = AresIOContext.from(testContext); | ||
ioManager = createIOManagerFor(testContext); | ||
controllerClass = ioManager.getControllerClass(); | ||
} | ||
|
||
public void beforeTestExecution() { | ||
ioManager.beforeTestExecution(context); | ||
} | ||
|
||
public void afterTestExecution() { | ||
ioManager.afterTestExecution(context); | ||
} | ||
|
||
public boolean providesController() { | ||
return controllerClass != null; | ||
} | ||
|
||
public Object getControllerInstance() { | ||
return providesController() ? ioManager.getControllerInstance(context) : null; | ||
} | ||
|
||
public boolean canProvideControllerFor(Class<?> targetType) { | ||
return providesController() && Objects.class != targetType && targetType.isAssignableFrom(controllerClass); | ||
} | ||
|
||
private static IOManager<?> createIOManagerFor(TestContext testContext) { | ||
var ioManagerClass = TestContextUtils.findAnnotationIn(testContext, WithIOManager.class) | ||
.<Class<? extends IOManager<?>>>map(WithIOManager::value).orElse(DEFAULT_IO_MANAGER); | ||
return ioManagerCache.computeIfAbsent(ioManagerClass, IOExtensionUtils::generateIOManagerSupplier).get(); | ||
} | ||
|
||
private static Supplier<IOManager<?>> generateIOManagerSupplier(Class<? extends IOManager<?>> ioManagerClass) { | ||
try { | ||
var lookup = MethodHandles.lookup(); | ||
var contructor = lookup.findConstructor(ioManagerClass, methodType(void.class)); | ||
var factory = LambdaMetafactory | ||
.metafactory(lookup, "get", methodType(Supplier.class), contructor.type().generic(), contructor, //$NON-NLS-1$ | ||
contructor.type()) | ||
.getTarget(); | ||
return (Supplier<IOManager<?>>) factory.invokeExact(); | ||
} catch (Throwable e) { | ||
throw new AnnotationFormatError("Could not create IOManager Supplier for type " //$NON-NLS-1$ | ||
+ ioManagerClass.getCanonicalName() + ". Make sure a public no-args constructor is available.", e); //$NON-NLS-1$ | ||
} | ||
} | ||
} |
40 changes: 0 additions & 40 deletions
40
src/main/java/de/tum/in/test/api/internal/IOTesterManager.java
This file was deleted.
Oops, something went wrong.
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
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
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
Oops, something went wrong.