Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b3c12f9 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow overriding flags in Robolectric tests" into ub-launcher3-master

parents 1a9cbd3c af0c0e8b
Loading
Loading
Loading
Loading
+116 −0
Original line number Diff line number Diff line
package com.android.launcher3.config;


import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.robolectric.RuntimeEnvironment;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Test rule that makes overriding flags in Robolectric tests easier. This rule clears all flags
 * before and after your test, avoiding one test method affecting subsequent methods.
 *
 * <p>Usage:
 * <pre>
 * {@literal @}Rule public final FlagOverrideRule flags = new FlagOverrideRule();
 *
 * {@literal @}FlagOverride(flag = "FOO", value=true)
 * {@literal @}Test public void myTest() {
 *     ...
 * }
 * </pre>
 */
public final class FlagOverrideRule implements TestRule {

    /**
     * Container annotation for handling multiple {@link FlagOverride} annotations.
     * <p>
     * <p>Don't use this directly, use repeated {@link FlagOverride} annotations instead.
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface FlagOverrides {
        FlagOverride[] value();
    }

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    @Repeatable(FlagOverrides.class)
    public @interface FlagOverride {
        String key();

        boolean value();
    }

    private boolean ruleInProgress;

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                FeatureFlags.initialize(RuntimeEnvironment.application.getApplicationContext());
                ruleInProgress = true;
                try {
                    clearOverrides();
                    applyAnnotationOverrides(description);
                    base.evaluate();
                } finally {
                    ruleInProgress = false;
                    clearOverrides();
                }
            }
        };
    }

    private void override(BaseFlags.TogglableFlag flag, boolean newValue) {
        if (!ruleInProgress) {
            throw new IllegalStateException(
                    "Rule isn't in progress. Did you remember to mark it with @Rule?");
        }
        flag.setForTests(newValue);
    }

    private void applyAnnotationOverrides(Description description) {
        for (Annotation annotation : description.getAnnotations()) {
            if (annotation.annotationType() == FlagOverride.class) {
                applyAnnotation((FlagOverride) annotation);
            } else if (annotation.annotationType() == FlagOverrides.class) {
                // Note: this branch is hit if the annotation is repeated
                for (FlagOverride flagOverride : ((FlagOverrides) annotation).value()) {
                    applyAnnotation(flagOverride);
                }
            }
        }
    }

    private void applyAnnotation(FlagOverride flagOverride) {
        boolean found = false;
        for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
            if (flag.getKey().equals(flagOverride.key())) {
                override(flag, flagOverride.value());
                found = true;
                break;
            }
        }
        if (!found) {
            throw new IllegalStateException("Flag " + flagOverride.key() + " not found");
        }
    }

    /**
     * Resets all flags to their default values.
     */
    private void clearOverrides() {
        for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
            flag.setForTests(flag.getDefaultValue());
        }
    }
}
+38 −0
Original line number Diff line number Diff line
package com.android.launcher3.config;

import com.android.launcher3.config.FlagOverrideRule.FlagOverride;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 * Sample Robolectric test that demonstrates flag-overriding.
 */
@RunWith(RobolectricTestRunner.class)
public class FlagOverrideSampleTest {

    // Check out https://junit.org/junit4/javadoc/4.12/org/junit/Rule.html for more information
    // on @Rules.
    @Rule
    public final FlagOverrideRule flags = new FlagOverrideRule();

    @FlagOverride(key = "EXAMPLE_FLAG", value = true)
    @FlagOverride(key = "QUICK_SWITCH", value = false)
    @Test
    public void withFlagOn() {
        assertTrue(FeatureFlags.EXAMPLE_FLAG.get());
        assertFalse(FeatureFlags.QUICK_SWITCH.get());
    }


    @FlagOverride(key = "EXAMPLE_FLAG", value = false)
    @Test
    public void withFlagOff() {
        assertFalse(FeatureFlags.EXAMPLE_FLAG.get());
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import java.util.TreeMap;

import androidx.annotation.GuardedBy;
import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting;

/**
 * Defines a set of flags used to control various launcher behaviors.
@@ -148,7 +149,14 @@ abstract class BaseFlags {
            }
        }

        String getKey() {
        /** Set the value of this flag. This should only be used in tests. */
        @VisibleForTesting
        void setForTests(boolean value) {
            currentValue = value;
        }

        @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
        public String getKey() {
            return key;
        }