All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.testfx.framework.junit5.ApplicationExtension Maven / Gradle / Ivy

There is a newer version: 4.0.18
Show newest version
/*
 * Copyright 2013-2014 SmartBear Software
 * Copyright 2014-2023 The TestFX Contributors
 *
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the
 * European Commission - subsequent versions of the EUPL (the "Licence"); You may
 * not use this work except in compliance with the Licence.
 *
 * You may obtain a copy of the Licence at:
 * http://ec.europa.eu/idabc/eupl.html
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the Licence for the
 * specific language governing permissions and limitations under the Licence.
 */
package org.testfx.framework.junit5;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javafx.stage.Stage;

import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
import org.testfx.api.FxRobot;
import org.testfx.api.FxToolkit;
import org.testfx.util.WaitForAsyncUtils;

public class ApplicationExtension extends FxRobot implements BeforeEachCallback, AfterEachCallback,
        TestInstancePostProcessor, ParameterResolver {

    private ApplicationFixture applicationFixture;

    @Override
    public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception {
        List init = new ArrayList<>();
        List start = new ArrayList<>();
        List stop = new ArrayList<>();
        Class testClass = testInstance.getClass();
        Method[] methods = testClass.getDeclaredMethods();
        for (Method method : methods) {
            method.setAccessible(true);
            if (method.isAnnotationPresent(Init.class)) {
                init.add(validateInitMethod(method));
            }
            if (method.isAnnotationPresent(Start.class)) {
                start.add(validateStartMethod(method));
            }
            if (method.isAnnotationPresent(Stop.class)) {
                stop.add(validateStopMethod(method));
            }
        }
        Field[] fields = testClass.getDeclaredFields();
        for (Field field : fields) {
            if (field.getType().isAssignableFrom(FxRobot.class)) {
                setField(testInstance, field, this);
            }
        }
        applicationFixture = new AnnotationBasedApplicationFixture(testInstance, init, start, stop);
    }

    @Override
    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
        return parameterContext.getParameter().getType().isAssignableFrom(FxRobot.class);
    }

    @Override
    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
        return this;
    }

    @Override
    public void beforeEach(ExtensionContext context) throws Exception {
        FxToolkit.registerPrimaryStage();
        FxToolkit.setupApplication(() -> new ApplicationAdapter(applicationFixture));
    }

    @Override
    public void afterEach(ExtensionContext context) throws Exception {
        FxToolkit.cleanupAfterTest(this, new ApplicationAdapter(applicationFixture));
        // Required to wait for the end of the UI events processing
        WaitForAsyncUtils.waitForFxEvents();
    }

    private Method validateInitMethod(Method initMethod) {
        if (initMethod.getParameterCount() != 0) {
            throw new IllegalStateException("Method annotated with @Init should have no arguments");
        }
        return initMethod;
    }

    private Method validateStartMethod(Method startMethod) {
        Class[] parameterTypes = startMethod.getParameterTypes();
        if (parameterTypes.length != 1 || !parameterTypes[0].isAssignableFrom(javafx.stage.Stage.class)) {
            throw new IllegalStateException("Method annotated with @Start should have one argument of type " +
                    "javafx.stage.Stage");
        }
        return startMethod;
    }

    private Method validateStopMethod(Method stopMethod) {
        if (stopMethod.getParameterCount() != 0) {
            throw new IllegalStateException("Method annotated with @Stop should have no arguments");
        }
        return stopMethod;
    }

    private void setField(Object instance, Field field, Object val) throws IllegalAccessException {
        boolean wasAccessible = field.isAccessible();
        try {
            field.setAccessible(true);
            field.set(instance, val);
        }
        finally {
            field.setAccessible(wasAccessible);
        }
    }

    private static class AnnotationBasedApplicationFixture implements ApplicationFixture {

        private final Object testInstance;
        private final List init;
        private final List start;
        private final List stop;

        private AnnotationBasedApplicationFixture(Object testInstance, List init,
                                                  List start, List stop) {
            this.testInstance = testInstance;
            this.init = init;
            this.start = start;
            this.stop = stop;
        }

        @Override
        public void init() throws InvocationTargetException, IllegalAccessException {
            for (Method method : init) {
                method.invoke(testInstance);
            }
        }

        @Override
        public void start(Stage stage) throws InvocationTargetException, IllegalAccessException {
            for (Method method : start) {
                method.invoke(testInstance, stage);
            }
        }

        @Override
        public void stop() throws InvocationTargetException, IllegalAccessException {
            for (Method method : stop) {
                method.invoke(testInstance);
            }
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy