/*
* Copyright 2008-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package griffon.javafx.test;
import org.junit.internal.runners.statements.Fail;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import javax.annotation.Nonnull;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static java.util.Collections.unmodifiableList;
import static java.util.Comparator.comparing;
import static org.junit.runner.Description.createTestDescription;
/**
* @author Andres Almiray
* @since 2.6.0
*/
public class FunctionalJavaFXRunner extends BlockJUnit4ClassRunner {
private GriffonTestFXClassRule testFXClassRule;
public FunctionalJavaFXRunner(@Nonnull Class<?> klass) throws InitializationError {
super(klass);
}
private static class FailureListener extends RunListener {
private final GriffonTestFXClassRule testfx;
private FailureListener(GriffonTestFXClassRule testfx) {
this.testfx = testfx;
}
@Override
public void testFailure(Failure failure) throws Exception {
testfx.setFailures(true);
}
}
@Override
protected List<FrameworkMethod> computeTestMethods() {
List<FrameworkMethod> methods = new ArrayList<>(super.computeTestMethods());
Collections.sort(methods, comparing(FrameworkMethod::getName));
return unmodifiableList(methods);
}
@Override
protected void runChild(FrameworkMethod method, RunNotifier notifier) {
try {
resolveTestFXClassRule(method);
notifier.addFirstListener(new FailureListener(testFXClassRule));
} catch (Exception e) {
notifier.fireTestFailure(new Failure(createTestDescription(method.getDeclaringClass(), method.getName()), e));
}
super.runChild(method, notifier);
}
@Override
protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
try {
resolveTestFXClassRule(method);
testFXClassRule.injectMembers(target);
} catch (Exception e) {
return new Fail(e);
}
return super.withBefores(method, target, statement);
}
@Override
protected boolean isIgnored(FrameworkMethod child) {
if (super.isIgnored(child)) {
return true;
}
try {
resolveTestFXClassRule(child);
return testFXClassRule.hasFailures();
} catch (Exception e) {
return true;
}
}
private void resolveTestFXClassRule(FrameworkMethod child) throws NoSuchFieldException, IllegalAccessException {
if (testFXClassRule == null) {
for (Field field : child.getDeclaringClass().getFields()) {
if (GriffonTestFXClassRule.class.isAssignableFrom(field.getType())) {
testFXClassRule = (GriffonTestFXClassRule) field.get(null);
return;
}
}
throw new IllegalStateException("Class " + child.getDeclaringClass().getName() + " does not define a field of type " + GriffonTestFXClassRule.class.getName());
}
}
}