chromium/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureListWithProcessorUnitTest.java

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.flags;

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

import com.google.common.collect.Sets;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;

import org.chromium.base.FeatureList;
import org.chromium.base.cached_flags.CachedFlag;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/** Tests the behavior of {@link ChromeFeatureList}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class ChromeFeatureListWithProcessorUnitTest {

    /** In unit tests, all flags checked must have their value specified. */
    @Test(expected = IllegalArgumentException.class)
    public void testNoOverridesDefaultDisabled_throws() {
        ChromeFeatureList.isEnabled(ChromeFeatureList.TEST_DEFAULT_DISABLED);
    }

    /** In unit tests, all flags checked must have their value specified. */
    @Test(expected = IllegalArgumentException.class)
    public void testNoOverridesDefaultEnabled_throws() {
        ChromeFeatureList.isEnabled(ChromeFeatureList.TEST_DEFAULT_ENABLED);
    }

    /** In unit tests, flags may have their value specified by the EnableFeatures annotation. */
    @Test
    @EnableFeatures(ChromeFeatureList.TEST_DEFAULT_DISABLED)
    public void testAnnotationEnabled_returnsEnabled() {
        assertTrue(ChromeFeatureList.isEnabled(ChromeFeatureList.TEST_DEFAULT_DISABLED));
    }

    /** In unit tests, flags may have their value specified by the DisableFeatures annotation. */
    @Test
    @DisableFeatures(ChromeFeatureList.TEST_DEFAULT_ENABLED)
    public void testAnnotationDisabled_returnsDisabled() {
        assertFalse(ChromeFeatureList.isEnabled(ChromeFeatureList.TEST_DEFAULT_ENABLED));
    }

    /**
     * In unit tests, flags may have their value specified by calling {@link
     * FeatureList#setTestFeatures(java.util.Map)}.
     */
    @Test
    @EnableFeatures(ChromeFeatureList.TEST_DEFAULT_DISABLED)
    public void testSetTestFeaturesEnabled_returnsEnabled() {
        assertTrue(ChromeFeatureList.isEnabled(ChromeFeatureList.TEST_DEFAULT_DISABLED));
    }

    /**
     * In unit tests, flags may have their value specified by calling {@link
     * FeatureList#setTestFeatures(java.util.Map)}.
     */
    @Test
    @DisableFeatures(ChromeFeatureList.TEST_DEFAULT_ENABLED)
    public void testSetTestFeaturesDisabled_returnsDisabled() {
        assertFalse(ChromeFeatureList.isEnabled(ChromeFeatureList.TEST_DEFAULT_ENABLED));
    }

    @Test
    public void testAllCachedFlagsMap_matchesCachedFlagsDeclared() throws IllegalAccessException {
        HashSet<String> cachedFlagsDeclared = new HashSet<>();
        for (Field field : ChromeFeatureList.class.getDeclaredFields()) {
            int modifiers = field.getModifiers();
            if (CachedFlag.class.isAssignableFrom(field.getType())
                    && Modifier.isPublic(modifiers)
                    && Modifier.isStatic(modifiers)
                    && Modifier.isFinal(modifiers)) {
                CachedFlag flag = (CachedFlag) field.get(null);
                cachedFlagsDeclared.add(flag.getFeatureName());
            }
        }

        Set<String> cachedFlagsListed = ChromeFeatureList.sAllCachedFlags.keySet();

        Set<String> declaredButNotListed = Sets.difference(cachedFlagsDeclared, cachedFlagsListed);
        assertEquals(
                "Cached flags declared in ChromeFeatureList, but not added to |sAllCachedFlags|",
                Collections.emptySet(),
                declaredButNotListed);

        Set<String> listedButNotDeclared = Sets.difference(cachedFlagsListed, cachedFlagsDeclared);
        assertEquals(
                "Cached flags listed in |sAllCachedFlags|, but not declared as public static "
                        + "final in ChromeFeatureList",
                Collections.emptySet(),
                listedButNotDeclared);
    }
}