1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.platform.test.rules; 17 18 import org.junit.Assume; 19 import org.junit.rules.MethodRule; 20 import org.junit.runners.model.FrameworkMethod; 21 import org.junit.runners.model.Statement; 22 23 import java.lang.reflect.Modifier; 24 import java.util.function.Supplier; 25 26 /** A JUnit Rule for ignoring a test based on a condition. */ 27 public class ConditionalIgnoreRule implements MethodRule { 28 @Override apply(Statement base, FrameworkMethod method, Object target)29 public Statement apply(Statement base, FrameworkMethod method, Object target) { 30 if (method.getAnnotation(ConditionalIgnore.class) != null) { 31 ConditionalIgnore annotation = method.getAnnotation(ConditionalIgnore.class); 32 Supplier<Boolean> condition; 33 Class<? extends Supplier<Boolean>> conditionType = annotation.condition(); 34 boolean conditionTypeStandalone = 35 !conditionType.isMemberClass() 36 || Modifier.isStatic(conditionType.getModifiers()); 37 if (!conditionTypeStandalone 38 && !target.getClass().isAssignableFrom(conditionType.getDeclaringClass())) { 39 String msg = 40 "Conditional class '%s' is a member class but was not declared inside the" 41 + " test case using it.\n" 42 + "Either make this class a static class, standalone class (by" 43 + " declaring it in its own file) or move it inside the test case" 44 + " using it"; 45 throw new IllegalArgumentException(String.format(msg, conditionType.getName())); 46 } 47 try { 48 condition = 49 conditionTypeStandalone 50 ? conditionType.getDeclaredConstructor().newInstance() 51 : conditionType 52 .getDeclaredConstructor(target.getClass()) 53 .newInstance(target); 54 } catch (RuntimeException re) { 55 throw re; 56 } catch (Exception e) { 57 throw new RuntimeException(e); 58 } 59 if (condition.get()) { 60 return new IgnoreStatement(condition); 61 } 62 } 63 return base; 64 } 65 66 private static class IgnoreStatement extends Statement { 67 private final Supplier<Boolean> mCondition; 68 IgnoreStatement(Supplier<Boolean> condition)69 IgnoreStatement(Supplier<Boolean> condition) { 70 this.mCondition = condition; 71 } 72 73 @Override evaluate()74 public void evaluate() { 75 Assume.assumeTrue("Ignored by " + mCondition.getClass().getSimpleName(), false); 76 } 77 } 78 } 79