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

Commit 4ce1f9d4 authored by Dave Mankoff's avatar Dave Mankoff Committed by Automerger Merge Worker
Browse files

Merge "Adds FakeFeatureFlags for testing" into tm-qpr-dev am: 636e17ba am: ecef005b

parents 1c9ae015 ecef005b
Loading
Loading
Loading
Loading
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.flags

import android.util.SparseArray
import android.util.SparseBooleanArray
import androidx.core.util.containsKey
import java.lang.IllegalStateException

class FakeFeatureFlags : FeatureFlags {
    private val booleanFlags = SparseBooleanArray()
    private val stringFlags = SparseArray<String>()
    private val knownFlagNames = mutableMapOf<Int, String>()

    init {
        Flags.getFlagFields().forEach { field ->
            val flag: Flag<*> = field.get(null) as Flag<*>
            knownFlagNames[flag.id] = field.name
        }
    }

    fun set(flag: BooleanFlag, value: Boolean) {
        booleanFlags.put(flag.id, value)
    }

    fun set(flag: DeviceConfigBooleanFlag, value: Boolean) {
        booleanFlags.put(flag.id, value)
    }

    fun set(flag: ResourceBooleanFlag, value: Boolean) {
        booleanFlags.put(flag.id, value)
    }

    fun set(flag: SysPropBooleanFlag, value: Boolean) {
        booleanFlags.put(flag.id, value)
    }

    fun set(flag: StringFlag, value: String) {
        stringFlags.put(flag.id, value)
    }

    fun set(flag: ResourceStringFlag, value: String) {
        stringFlags.put(flag.id, value)
    }

    override fun isEnabled(flag: BooleanFlag): Boolean = requireBooleanValue(flag.id)

    override fun isEnabled(flag: ResourceBooleanFlag): Boolean = requireBooleanValue(flag.id)

    override fun isEnabled(flag: DeviceConfigBooleanFlag): Boolean = requireBooleanValue(flag.id)

    override fun isEnabled(flag: SysPropBooleanFlag): Boolean = requireBooleanValue(flag.id)

    override fun getString(flag: StringFlag): String = requireStringValue(flag.id)

    override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.id)

    override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {}

    override fun removeListener(listener: FlagListenable.Listener) {}

    private fun flagName(flagId: Int): String {
        return knownFlagNames[flagId] ?: "UNKNOWN(id=$flagId)"
    }

    private fun requireBooleanValue(flagId: Int): Boolean {
        if (!booleanFlags.containsKey(flagId)) {
            throw IllegalStateException("Flag ${flagName(flagId)} was accessed but not specified.")
        }
        return booleanFlags[flagId]
    }

    private fun requireStringValue(flagId: Int): String {
        if (!stringFlags.containsKey(flagId)) {
            throw IllegalStateException("Flag ${flagName(flagId)} was accessed but not specified.")
        }
        return stringFlags[flagId]
    }
}
+106 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.flags

import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import java.lang.IllegalStateException
import org.junit.Assert.fail
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidTestingRunner::class)
class FakeFeatureFlagsTest : SysuiTestCase() {

    private val booleanFlag = BooleanFlag(-1000)
    private val stringFlag = StringFlag(-1001)
    private val resourceBooleanFlag = ResourceBooleanFlag(-1002, resourceId = -1)
    private val resourceStringFlag = ResourceStringFlag(-1003, resourceId = -1)
    private val sysPropBooleanFlag = SysPropBooleanFlag(-1004, name = "test")

    /**
     * FakeFeatureFlags does not honor any default values. All flags which are accessed must be
     * specified. If not, an exception is thrown.
     */
    @Test
    fun throwsIfUnspecifiedFlagIsAccessed() {
        val flags: FeatureFlags = FakeFeatureFlags()
        try {
            assertThat(flags.isEnabled(Flags.TEAMFOOD)).isFalse()
            fail("Expected an exception when accessing an unspecified flag.")
        } catch (ex: IllegalStateException) {
            assertThat(ex.message).contains("TEAMFOOD")
        }
        try {
            assertThat(flags.isEnabled(booleanFlag)).isFalse()
            fail("Expected an exception when accessing an unspecified flag.")
        } catch (ex: IllegalStateException) {
            assertThat(ex.message).contains("UNKNOWN(id=-1000)")
        }
        try {
            assertThat(flags.isEnabled(resourceBooleanFlag)).isFalse()
            fail("Expected an exception when accessing an unspecified flag.")
        } catch (ex: IllegalStateException) {
            assertThat(ex.message).contains("UNKNOWN(id=-1002)")
        }
        try {
            assertThat(flags.isEnabled(sysPropBooleanFlag)).isFalse()
            fail("Expected an exception when accessing an unspecified flag.")
        } catch (ex: IllegalStateException) {
            assertThat(ex.message).contains("UNKNOWN(id=-1004)")
        }
        try {
            assertThat(flags.getString(stringFlag)).isEmpty()
            fail("Expected an exception when accessing an unspecified flag.")
        } catch (ex: IllegalStateException) {
            assertThat(ex.message).contains("UNKNOWN(id=-1001)")
        }
        try {
            assertThat(flags.getString(resourceStringFlag)).isEmpty()
            fail("Expected an exception when accessing an unspecified flag.")
        } catch (ex: IllegalStateException) {
            assertThat(ex.message).contains("UNKNOWN(id=-1003)")
        }
    }

    @Test
    fun specifiedFlagsReturnCorrectValues() {
        val flags = FakeFeatureFlags()
        flags.set(booleanFlag, false)
        flags.set(resourceBooleanFlag, false)
        flags.set(sysPropBooleanFlag, false)
        flags.set(resourceStringFlag, "")

        assertThat(flags.isEnabled(booleanFlag)).isFalse()
        assertThat(flags.isEnabled(resourceBooleanFlag)).isFalse()
        assertThat(flags.isEnabled(sysPropBooleanFlag)).isFalse()
        assertThat(flags.getString(resourceStringFlag)).isEmpty()

        flags.set(booleanFlag, true)
        flags.set(resourceBooleanFlag, true)
        flags.set(sysPropBooleanFlag, true)
        flags.set(resourceStringFlag, "Android")

        assertThat(flags.isEnabled(booleanFlag)).isTrue()
        assertThat(flags.isEnabled(resourceBooleanFlag)).isTrue()
        assertThat(flags.isEnabled(sysPropBooleanFlag)).isTrue()
        assertThat(flags.getString(resourceStringFlag)).isEqualTo("Android")
    }
}