502516: junit4 add ConditionalIgnoreRule to Junit4TestFixtureRunner
Change-Id: I7efbbaf28f72dd71a3ece1e87dfb4baa92eb98e7
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=502516
diff --git a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/ConditionalIgnoreRule.java b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/ConditionalIgnoreRule.java
new file mode 100644
index 0000000..11d2409
--- /dev/null
+++ b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/ConditionalIgnoreRule.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Frank Becker and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Frank Becker and others - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.mylyn.commons.sdk.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Modifier;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import com.google.common.base.Throwables;
+
+/**
+ * Cobbled together from: http://www.codeaffine.com/2013/11/18/a-junit-rule-to-conditionally-ignore-tests/
+ * https://gist.github.com/yinzara/9980184 http://cwd.dhemery.com/2010/12/junit-rules/
+ * (http://stackoverflow.com/questions/28145735/androidjunit4-class-org-junit-assume-assumetrue-assumptionviolatedexception/
+ */
+
+public class ConditionalIgnoreRule implements TestRule {
+
+ private final IFixtureJUnitClass fixtureJUnitClass;
+
+ public ConditionalIgnoreRule(IFixtureJUnitClass fixtureJUnitClass) {
+ super();
+ this.fixtureJUnitClass = fixtureJUnitClass;
+ }
+
+ public interface IgnoreCondition {
+ boolean isSatisfied(AbstractTestFixture fixture);
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ ElementType.METHOD })
+ public @interface ConditionalIgnore {
+ Class<? extends IgnoreCondition> condition();
+ }
+
+ @Override
+ public Statement apply(Statement aStatement, Description aDescription) {
+ Statement result = aStatement;
+ if (hasConditionalIgnoreAnnotation(aDescription)) {
+ IgnoreCondition condition = getIgnoreCondition(aDescription);
+ if (condition.isSatisfied(fixtureJUnitClass.getActualFixture())) {
+ result = new IgnoreStatement();
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean hasConditionalIgnoreAnnotation(Description aDescription) {
+ return aDescription.getAnnotation(ConditionalIgnore.class) != null;
+ }
+
+ private static IgnoreCondition getIgnoreCondition(Description aDescription) {
+ ConditionalIgnore annotation = aDescription.getAnnotation(ConditionalIgnore.class);
+ return new IgnoreConditionCreator(aDescription.getTestClass(), annotation).create();
+ }
+
+ private static class IgnoreConditionCreator {
+ private final Class<?> testClass;
+
+ private final Class<? extends IgnoreCondition> conditionType;
+
+ IgnoreConditionCreator(Class<?> testClass, ConditionalIgnore annotation) {
+ this.testClass = testClass;
+ this.conditionType = annotation.condition();
+ }
+
+ IgnoreCondition create() {
+ checkConditionType();
+ try {
+ return createCondition();
+ } catch (Exception re) {
+ throw Throwables.propagate(re);
+ }
+ }
+
+ private IgnoreCondition createCondition() throws Exception {
+ IgnoreCondition result;
+ if (isConditionTypeStandalone()) {
+ result = conditionType.newInstance();
+ } else {
+ result = conditionType.getDeclaredConstructor(testClass).newInstance(testClass);
+ }
+ return result;
+ }
+
+ private void checkConditionType() {
+ if (!isConditionTypeStandalone() && !isConditionTypeDeclaredInTarget()) {
+ String msg = "Conditional class '%s' is a member class "
+ + "but was not declared inside the test case using it.\n"
+ + "Either make this class a static class, "
+ + "standalone class (by declaring it in it's own file) "
+ + "or move it inside the test case using it";
+ throw new IllegalArgumentException(String.format(msg, conditionType.getName()));
+ }
+ }
+
+ private boolean isConditionTypeStandalone() {
+ return !conditionType.isMemberClass() || Modifier.isStatic(conditionType.getModifiers());
+ }
+
+ private boolean isConditionTypeDeclaredInTarget() {
+ return testClass.getClass().isAssignableFrom(conditionType.getDeclaringClass());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IFixtureJUnitClass.java b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IFixtureJUnitClass.java
new file mode 100644
index 0000000..706351d
--- /dev/null
+++ b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IFixtureJUnitClass.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Frank Becker and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Frank Becker - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.sdk.util;
+
+public interface IFixtureJUnitClass {
+ public AbstractTestFixture getActualFixture();
+}
diff --git a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IgnoreRuleRuntimeException.java b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IgnoreRuleRuntimeException.java
new file mode 100644
index 0000000..ebf32e9
--- /dev/null
+++ b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IgnoreRuleRuntimeException.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Frank Becker and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Frank Becker - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.sdk.util;
+
+public class IgnoreRuleRuntimeException extends RuntimeException {
+
+}
diff --git a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IgnoreStatement.java b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IgnoreStatement.java
new file mode 100644
index 0000000..97d1b14
--- /dev/null
+++ b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/IgnoreStatement.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Frank Becker and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Frank Becker - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.sdk.util;
+
+import org.junit.runners.model.Statement;
+
+public class IgnoreStatement extends Statement {
+
+ @Override
+ public void evaluate() {
+ throw new IgnoreRuleRuntimeException();
+ }
+
+}
diff --git a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/Junit4TestFixtureRunner.java b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/Junit4TestFixtureRunner.java
index 9794414..b4acff7 100644
--- a/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/Junit4TestFixtureRunner.java
+++ b/org.eclipse.mylyn.commons.sdk.util/src/org/eclipse/mylyn/commons/sdk/util/Junit4TestFixtureRunner.java
@@ -20,6 +20,15 @@
import java.util.Collections;
import java.util.List;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.mylyn.commons.core.StatusHandler;
+import org.eclipse.osgi.util.NLS;
+import org.junit.internal.AssumptionViolatedException;
+import org.junit.internal.runners.model.EachTestNotifier;
+import org.junit.internal.runners.model.ReflectiveCallable;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
@@ -86,6 +95,64 @@
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
+
+ @Override
+ protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
+ Description description = describeChild(method);
+ if (isIgnored(method)) {
+ notifier.fireTestIgnored(description);
+ } else {
+ Object test = null;
+ try {
+ test = new ReflectiveCallable() {
+ @Override
+ protected Object runReflectiveCall() throws Throwable {
+ return createTest();
+ }
+ }.run();
+ } catch (Throwable e) {
+ StatusHandler.log(new Status(IStatus.ERROR, "org.eclipse.mylyn.commons.sdk.util", //$NON-NLS-1$
+ NLS.bind("TestClassRunnerForFixture: Testclass {0} has no public constructor", //$NON-NLS-1$
+ getTestClass().getName()),
+ e));
+ return;
+ }
+ boolean skipped = false;
+ if (test != null) {
+ List<TestRule> testRules = getTestRules(test);
+ for (TestRule testRule : testRules) {
+ if (testRule instanceof ConditionalIgnoreRule) {
+ Statement statement = testRule.apply(null, description);
+ if (statement instanceof IgnoreStatement) {
+ skipped = true;
+ break;
+ }
+ }
+ }
+ if (skipped) {
+ notifier.fireTestIgnored(description);
+ } else {
+ runTest(methodBlock(method), description, notifier);
+ }
+ }
+ }
+ }
+
+ protected final void runTest(Statement statement, Description description, RunNotifier notifier) {
+ EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
+ eachNotifier.fireTestStarted();
+ try {
+ statement.evaluate();
+ } catch (AssumptionViolatedException e) {
+ eachNotifier.addFailedAssumption(e);
+ } catch (IgnoreRuleRuntimeException e) {
+ eachNotifier.fireTestIgnored();
+ } catch (Throwable e) {
+ eachNotifier.addFailure(e);
+ } finally {
+ eachNotifier.fireTestFinished();
+ }
+ }
}
private final ArrayList<Runner> runners = new ArrayList<Runner>();
@@ -106,22 +173,21 @@
String fixtureType = null;
for (Annotation annotation : getTestClass().getAnnotations()) {
- if ("org.eclipse.mylyn.commons.sdk.util.Junit4TestFixtureRunner.OnlyRunWithProperty"
- .equals(annotation.annotationType().getCanonicalName())) {
+ if (annotation.annotationType() == RunOnlyWhenProperty.class) {
RunOnlyWhenProperty onlyWhenProperty = (RunOnlyWhenProperty) annotation;
restrictProperty = onlyWhenProperty.property();
restrictValue = onlyWhenProperty.value();
}
- if ("org.eclipse.mylyn.commons.sdk.util.Junit4TestFixtureRunner.FixtureDefinition"
- .equals(annotation.annotationType().getCanonicalName())) {
+ if (annotation.annotationType() == FixtureDefinition.class) {
FixtureDefinition fixtueDef = (FixtureDefinition) annotation;
fixtureClass = fixtueDef.fixtureClass();
fixtureType = fixtueDef.fixtureType();
}
}
if (fixtureType != null) {
- List<AbstractTestFixture> parametersList = (List<AbstractTestFixture>) TestConfiguration.getDefault()
- .discover(fixtureClass, fixtureType);
+ TestConfiguration defFixture = TestConfiguration.getDefault();
+ List<AbstractTestFixture> parametersList = (List<AbstractTestFixture>) defFixture.discover(fixtureClass,
+ fixtureType);
List<AbstractTestFixture> fixturesToExecute = new ArrayList<AbstractTestFixture>();
if (restrictProperty != null) {
for (AbstractTestFixture abstractFixture : parametersList) {