/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * See LICENSE.txt included in this distribution for the specific * language governing permissions and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at LICENSE.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ package org.opensolaris.opengrok.condition; import org.junit.Assume; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; import java.lang.reflect.Modifier; /** * * This rule can be added to a Junit test and will look for the annotation * {@link ConditionalRun} on either the test class or method. The test is then * skipped through Junit's {@link Assume} capabilities if the * {@link RunCondition} provided in the annotation is not satisfied. * * 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 ConditionalRunRule implements TestRule { @Override public Statement apply(Statement aStatement, Description aDescription) { if (hasConditionalIgnoreAnnotationOnMethod(aDescription)) { RunCondition condition = getIgnoreConditionOnMethod(aDescription); if (!condition.isSatisfied()) { return new IgnoreStatement(condition); } } if (hasConditionalIgnoreAnnotationOnClass(aDescription)) { RunCondition condition = getIgnoreConditionOnClass(aDescription); if (!condition.isSatisfied()) { return new IgnoreStatement(condition); } } return aStatement; } private static boolean hasConditionalIgnoreAnnotationOnClass(Description aDescription) { return aDescription.getTestClass().getAnnotation(ConditionalRun.class) != null; } private static RunCondition getIgnoreConditionOnClass(Description aDescription) { ConditionalRun annotation = aDescription.getTestClass().getAnnotation(ConditionalRun.class); return new IgnoreConditionCreator(aDescription.getTestClass(), annotation).create(); } private static boolean hasConditionalIgnoreAnnotationOnMethod(Description aDescription) { return aDescription.getAnnotation(ConditionalRun.class) != null; } private static RunCondition getIgnoreConditionOnMethod(Description aDescription) { ConditionalRun annotation = aDescription.getAnnotation(ConditionalRun.class); return new IgnoreConditionCreator(aDescription.getTestClass(), annotation).create(); } private static class IgnoreConditionCreator { private final Class<?> mTestClass; private final Class<? extends RunCondition> conditionType; IgnoreConditionCreator(Class<?> aTestClass, ConditionalRun annotation) { this.mTestClass = aTestClass; this.conditionType = annotation.condition(); } RunCondition create() { checkConditionType(); try { return createCondition(); } catch (RuntimeException re) { throw re; } catch (Exception e) { throw new RuntimeException(e); } } private RunCondition createCondition() throws Exception { RunCondition result; if (isConditionTypeStandalone()) { result = conditionType.newInstance(); } else { result = conditionType.getDeclaredConstructor(mTestClass).newInstance(mTestClass); } 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 mTestClass.getClass().isAssignableFrom(conditionType.getDeclaringClass()); } } private static class IgnoreStatement extends Statement { private final RunCondition condition; IgnoreStatement(RunCondition condition) { this.condition = condition; } @Override public void evaluate() { Assume.assumeTrue("Ignored by " + condition.getClass().getSimpleName(), false); } } }