Merge "Adds FakeFeatureFlags for testing" into tm-qpr-dev
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlags.kt
new file mode 100644
index 0000000..b2a4e33
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlags.kt
@@ -0,0 +1,93 @@
+/*
+ * 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]
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
new file mode 100644
index 0000000..7d4b4f5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
@@ -0,0 +1,106 @@
+/*
+ * 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")
+    }
+}