Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ allprojects { project ->
}

subprojects { subproject ->
apply from: "${rootDir}/gradle/checkstyle.gradle"
apply from: "${rootDir}/gradle/license.gradle"
apply from: "${rootDir}/gradle/publish-jar.gradle"
apply from: "${rootDir}/gradle/publish-pom.gradle"

Expand Down
56 changes: 37 additions & 19 deletions subprojects/testfx-core/src/main/java/org/testfx/api/FxToolkit.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
Expand Down Expand Up @@ -94,14 +95,32 @@ public final class FxToolkit {

private static final ApplicationLauncher APP_LAUNCHER = new ApplicationLauncherImpl();
private static final ApplicationService APP_SERVICE = new ApplicationServiceImpl();
private static final FxToolkitContext CONTEXT = new FxToolkitContext();
private static final ToolkitService SERVICE = new ToolkitServiceImpl(APP_LAUNCHER, APP_SERVICE);
private static final FxToolkitContext GLOBAL_CONTEXT = new FxToolkitContext();
private static final ToolkitService GLOBAL_SERVICE = new ToolkitServiceImpl(APP_LAUNCHER, APP_SERVICE);
private static final ConcurrentHashMap<Class<?>, FxToolkitContext> ISOLATED_CONTEXTS = new ConcurrentHashMap<>();

private static FxToolkitContext currentContext = GLOBAL_CONTEXT;
private static ToolkitService currentService = GLOBAL_SERVICE;
static final String UNSUPPORTED_OPERATION_ERROR_MESSAGE = "Internal Error";
static final String UNSUPPORTED_OPERATION_CALLING_CLASS = "com.sun.glass.ui.gtk.GtkApplication";
static final String MISSING_LIBGTK_3_0_USER_MESSAGE = "Package libgtk-3-0 probably not installed";

private FxToolkit() {}

public static void useIsolatedContext(Class<?> testClass) {
ISOLATED_CONTEXTS.computeIfAbsent(testClass, clazz -> new FxToolkitContext());
switchToContext(ISOLATED_CONTEXTS.get(testClass));
}

public static void useGlobalContext() {
switchToContext(GLOBAL_CONTEXT);
}

private static void switchToContext(FxToolkitContext context) {
currentContext = context;
currentService = new ToolkitServiceImpl(APP_LAUNCHER, APP_SERVICE);
}

/**
* Sets up the {@link org.testfx.toolkit.PrimaryStageApplication} to use in tests, prevents it from shutting
* down when the last window is closed, and returns the {@link Stage} from {@link Application#start(Stage)}.
Expand All @@ -110,14 +129,13 @@ private FxToolkit() {}
*/
public static Stage registerPrimaryStage() throws TimeoutException {
try {
Stage primaryStage = waitFor(CONTEXT.getLaunchTimeoutInMillis(), MILLISECONDS,
SERVICE.setupPrimaryStage(CONTEXT.getPrimaryStageFuture(),
CONTEXT.getApplicationClass(), CONTEXT.getApplicationArgs()));
CONTEXT.setRegisteredStage(primaryStage);
Stage primaryStage = waitFor(currentContext.getLaunchTimeoutInMillis(), MILLISECONDS,
currentService.setupPrimaryStage(currentContext.getPrimaryStageFuture(),
currentContext.getApplicationClass(), currentContext.getApplicationArgs()));
currentContext.setRegisteredStage(primaryStage);
Platform.setImplicitExit(false);
return primaryStage;
}
catch (UnsupportedOperationException exception) {
} catch (UnsupportedOperationException exception) {
handleCommonRuntimeExceptions(exception);
}
return null;
Expand All @@ -131,7 +149,7 @@ public static Stage registerPrimaryStage() throws TimeoutException {
*/
public static Stage registerStage(Supplier<Stage> stageSupplier) throws TimeoutException {
Stage stage = setupFixture(stageSupplier::get);
CONTEXT.setRegisteredStage(stage);
currentContext.setRegisteredStage(stage);
return stage;
}

Expand All @@ -142,7 +160,7 @@ public static Stage registerStage(Supplier<Stage> stageSupplier) throws TimeoutE
* @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()}
*/
public static Stage setupStage(Consumer<Stage> stageConsumer) throws TimeoutException {
return waitForSetup(SERVICE.setupStage(CONTEXT.getRegisteredStage(), stageConsumer));
return waitForSetup(currentService.setupStage(currentContext.getRegisteredStage(), stageConsumer));
}

/**
Expand All @@ -152,7 +170,7 @@ public static Stage setupStage(Consumer<Stage> stageConsumer) throws TimeoutExce
*/
public static Application setupApplication(Class<? extends Application> applicationClass, String... applicationArgs)
throws TimeoutException {
return waitForSetup(SERVICE.setupApplication(CONTEXT::getRegisteredStage, applicationClass, applicationArgs));
return waitForSetup(currentService.setupApplication(currentContext::getRegisteredStage, applicationClass, applicationArgs));
}

/**
Expand All @@ -161,7 +179,7 @@ public static Application setupApplication(Class<? extends Application> applicat
* @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()}
*/
public static Application setupApplication(Supplier<Application> applicationSupplier) throws TimeoutException {
return waitForSetup(SERVICE.setupApplication(CONTEXT::getRegisteredStage, applicationSupplier));
return waitForSetup(currentService.setupApplication(currentContext::getRegisteredStage, applicationSupplier));
}

/**
Expand All @@ -175,7 +193,7 @@ public static Application setupApplication(Supplier<Application> applicationSupp
*/
public static void cleanupApplication(Application application) throws TimeoutException {
if (isFXApplicationThreadRunning()) {
waitForSetup(SERVICE.cleanupApplication(application));
waitForSetup(currentService.cleanupApplication(application));
} else {
throw new TimeoutException("FX Application Thread not running");
}
Expand All @@ -199,29 +217,29 @@ public static void cleanupAfterTest(FxRobot robot, Application application) thro
* @throws TimeoutException if execution is not finished before {@link FxToolkitContext#getSetupTimeoutInMillis()}
*/
public static Scene setupScene(Supplier<Scene> sceneSupplier) throws TimeoutException {
return waitForSetup(SERVICE.setupScene(CONTEXT.getRegisteredStage(), sceneSupplier));
return waitForSetup(currentService.setupScene(currentContext.getRegisteredStage(), sceneSupplier));
}

/**
* Runs the {@code sceneRootSupplier} on the {@code JavaFX Application Thread}, sets the registered stage's scene's
* root node to the supplied root node, and returns the supplied root node once finished.
*/
public static Parent setupSceneRoot(Supplier<Parent> sceneRootSupplier) throws TimeoutException {
return waitForSetup(SERVICE.setupSceneRoot(CONTEXT.getRegisteredStage(), sceneRootSupplier));
return waitForSetup(currentService.setupSceneRoot(currentContext.getRegisteredStage(), sceneRootSupplier));
}

/**
* Runs the given {@code runnable} on the {@code JavaFX Application Thread} and returns once finished.
*/
public static void setupFixture(Runnable runnable) throws TimeoutException {
waitForSetup(SERVICE.setupFixture(runnable));
waitForSetup(currentService.setupFixture(runnable));
}

/**
* Runs the given {@code callable} on the {@code JavaFX Application Thread} and returns once finished.
*/
public static <T> T setupFixture(Callable<T> callable) throws TimeoutException {
return waitForSetup(SERVICE.setupFixture(callable));
return waitForSetup(currentService.setupFixture(callable));
}

/**
Expand Down Expand Up @@ -266,15 +284,15 @@ public static void cleanupInput(FxRobot robot) {
* Returns the internal context.
*/
public static FxToolkitContext toolkitContext() {
return CONTEXT;
return currentContext;
}

/**
* Waits for the given future to be set before returning or times out after
* {@link FxToolkitContext#getSetupTimeoutInMillis()} is reached.
*/
private static <T> T waitForSetup(Future<T> future) throws TimeoutException {
T ret = waitFor(CONTEXT.getSetupTimeoutInMillis(), MILLISECONDS, future);
T ret = waitFor(currentContext.getSetupTimeoutInMillis(), MILLISECONDS, future);
waitForFxEvents();
return ret;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public Object resolveParameter(ParameterContext parameterContext, ExtensionConte

@Override
public void beforeEach(ExtensionContext context) throws Exception {
if (context.getTestClass().isPresent() && context.getTestClass().get().isAnnotationPresent(IsolateContext.class)) {
FxToolkit.useIsolatedContext(context.getRequiredTestClass());
} else {
FxToolkit.useGlobalContext();
}
FxToolkit.registerPrimaryStage();
FxToolkit.setupApplication(() -> new ApplicationAdapter(applicationFixture));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.testfx.framework.junit5;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// Annotation for marking isolated test classes
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) // Can be used on classes
public @interface IsolateContext {
}
Loading