1 // Copyright 2022 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base.test.util; 6 7 import org.chromium.base.CommandLine; 8 9 import java.lang.annotation.Annotation; 10 import java.lang.annotation.Retention; 11 import java.lang.annotation.RetentionPolicy; 12 import java.util.List; 13 14 /** 15 * Helps with setting Feature flags during tests. Relies on registering the appropriate 16 * {@code Processor} rule on the test class. 17 ** 18 * Use {@link EnableFeatures} and {@link DisableFeatures} to specify the features to register and 19 * whether they should be enabled. 20 * 21 * Sample code: 22 * 23 * <pre> 24 * public class Test { 25 * @Rule 26 * public TestRule mProcessor = new Features.JUnitProcessor(); 27 * 28 * @EnableFeatures(BaseFeatures.Foo) 29 * public void testFoo() { ... } 30 * 31 * @EnableFeatures(ContentFeatureList.Foo) 32 * public void testFoo() { ... } 33 * } 34 * </pre> 35 * 36 * This class also offers Singleton access to enable and disable features, letting other rules 37 * affect the final configuration before the start of the test. 38 * 39 * See {@link FeaturesBase} for more details. 40 */ 41 public class Features extends FeaturesBase { 42 @Retention(RetentionPolicy.RUNTIME) 43 public @interface EnableFeatures { value()44 String[] value(); 45 } 46 47 @Retention(RetentionPolicy.RUNTIME) 48 public @interface DisableFeatures { value()49 String[] value(); 50 } 51 Features()52 private Features() {} 53 54 /** 55 * @return the instance of this class, creating a new one if necessary. 56 */ getInstance()57 public static Features getInstance() { 58 if (sInstance == null) sInstance = new Features(); 59 assert sInstance instanceof Features 60 : "Mixed use of Features annotations detected. " 61 + "Ensure the correct base/ or chrome/ version is being used."; 62 return (Features) sInstance; 63 } 64 65 /** 66 * Feature processor intended to be used in unit tests tests. The collected feature states would 67 * be applied to {@link FeatureList}'s internal test-only feature map. 68 */ 69 public static class JUnitProcessor extends BaseJUnitProcessor { JUnitProcessor()70 public JUnitProcessor() { 71 super(EnableFeatures.class, DisableFeatures.class); 72 getInstance(); 73 } 74 75 @Override before()76 protected void before() { 77 getInstance(); 78 super.before(); 79 } 80 81 @Override collectFeatures()82 protected void collectFeatures() { 83 collectFeaturesImpl(getAnnotations()); 84 } 85 } 86 87 /** 88 * Feature processor intended to be used in instrumentation tests with native library. The 89 * collected feature states would be applied to {@link CommandLine}. 90 */ 91 public static class InstrumentationProcessor extends BaseInstrumentationProcessor { InstrumentationProcessor()92 public InstrumentationProcessor() { 93 super(EnableFeatures.class, DisableFeatures.class); 94 getInstance(); 95 } 96 97 @Override collectFeatures()98 protected void collectFeatures() { 99 collectFeaturesImpl(getAnnotations()); 100 } 101 } 102 collectFeaturesImpl(List<Annotation> annotations)103 private static void collectFeaturesImpl(List<Annotation> annotations) { 104 for (Annotation annotation : annotations) { 105 if (annotation instanceof EnableFeatures) { 106 sInstance.enable(((EnableFeatures) annotation).value()); 107 } else if (annotation instanceof DisableFeatures) { 108 sInstance.disable(((DisableFeatures) annotation).value()); 109 } 110 } 111 } 112 } 113