Loading packages/SystemUI/Android.bp +21 −1 Original line number Diff line number Diff line Loading @@ -196,13 +196,30 @@ filegroup { path: "tests/src", } filegroup { name: "kosmos-src", srcs: ["tests/utils/kosmos/src/**/*.kt"], path: "tests/utils/kosmos", } java_library { name: "kosmos", host_supported: true, srcs: [":kosmos-src"], static_libs: [ "kotlin-reflect", "kotlin-stdlib", ], } filegroup { name: "SystemUI-tests-utils", srcs: [ "tests/utils/src/**/*.java", "tests/utils/src/**/*.kt", ":kosmos-src", ], path: "tests/utils/src", path: "tests/utils", } filegroup { Loading Loading @@ -334,6 +351,7 @@ android_library { "kotlin-test", "SystemUICustomizationTestUtils", "androidx.compose.runtime_runtime", "kosmos", ], libs: [ "android.test.runner", Loading Loading @@ -416,6 +434,7 @@ android_robolectric_test { "inline-mockito-robolectric-prebuilt", "platform-parametric-runner-lib", "SystemUICustomizationTestUtils", "kosmos", ], libs: [ "android.test.runner", Loading Loading @@ -449,6 +468,7 @@ android_ravenwood_test { "androidx.test.uiautomator_uiautomator", "androidx.core_core-animation-testing", "androidx.test.ext.junit", "kosmos", ], libs: [ "android.test.runner", Loading packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/Kosmos.kt→packages/SystemUI/tests/utils/kosmos/src/com/android/systemui/kosmos/Kosmos.kt +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.kosmos import kotlin.reflect.KProperty Loading @@ -5,6 +21,7 @@ import kotlin.reflect.KProperty // (Historical note: The name Kosmos is meant to invoke "Kotlin", the "Object Mother" pattern // (https://martinfowler.com/bliki/ObjectMother.html), and of course the Greek word "kosmos" for // the "order of the world" (https://en.wiktionary.org/wiki/%CE%BA%CF%8C%CF%83%CE%BC%CE%BF%CF%82) /** * Each Kosmos is its own self-contained set of fixtures, which may reference each other. Fixtures * can be defined through extension properties in any file: Loading @@ -29,9 +46,15 @@ import kotlin.reflect.KProperty * ) * ``` */ class Kosmos { private val map: MutableMap<String, Any?> = mutableMapOf() private val gotten: MutableSet<String> = mutableSetOf() interface Kosmos { /** * Lookup a fixture in the Kosmos by [name], using [creator] to instantiate and store one if * there is none present. */ fun <T> get(name: String, creator: (Kosmos.() -> T)?): T /** Sets the [value] of a fixture with the given [name]. */ fun set(name: String, value: Any?) /** * A value in the kosmos that has a single value once it's read. It can be overridden before Loading @@ -42,28 +65,33 @@ class Kosmos { * If no [creator] parameter is provided, the fixture must be set before use. */ class Fixture<T>(private val creator: (Kosmos.() -> T)? = null) { operator fun getValue(thisRef: Kosmos, property: KProperty<*>): T { thisRef.gotten.add(property.name) @Suppress("UNCHECKED_CAST") if (!thisRef.map.contains(property.name)) { if (creator == null) { throw IllegalStateException( "Fixture ${property.name} has no default, and is read before set." ) } else { val nonNullCreator = creator // The Kotlin compiler seems to need this odd workaround thisRef.map[property.name] = thisRef.nonNullCreator() operator fun getValue(thisRef: Kosmos, property: KProperty<*>): T = thisRef.get(property.name, creator) operator fun setValue(thisRef: Kosmos, property: KProperty<*>, value: T) { thisRef.set(property.name, value) } } return thisRef.map[property.name] as T } operator fun setValue(thisRef: Kosmos, property: KProperty<*>, value: T) { check(!thisRef.gotten.contains(property.name)) { "Tried to set fixture '${property.name}' after it's already been read." /** Constructs a fresh Kosmos. */ fun Kosmos(): Kosmos = KosmosRegistry() private class KosmosRegistry : Kosmos { val map: MutableMap<String, Any?> = mutableMapOf() val gotten: MutableSet<String> = mutableSetOf() override fun <T> get(name: String, creator: (Kosmos.() -> T)?): T { gotten.add(name) if (name !in map) { checkNotNull(creator) { "Fixture $name has no default, and is read before set." } map[name] = creator() } thisRef.map[property.name] = value @Suppress("UNCHECKED_CAST") return map[name] as T } override fun set(name: String, value: Any?) { check(name !in gotten) { "Tried to set fixture '$name' after it's already been read." } map[name] = value } } Loading
packages/SystemUI/Android.bp +21 −1 Original line number Diff line number Diff line Loading @@ -196,13 +196,30 @@ filegroup { path: "tests/src", } filegroup { name: "kosmos-src", srcs: ["tests/utils/kosmos/src/**/*.kt"], path: "tests/utils/kosmos", } java_library { name: "kosmos", host_supported: true, srcs: [":kosmos-src"], static_libs: [ "kotlin-reflect", "kotlin-stdlib", ], } filegroup { name: "SystemUI-tests-utils", srcs: [ "tests/utils/src/**/*.java", "tests/utils/src/**/*.kt", ":kosmos-src", ], path: "tests/utils/src", path: "tests/utils", } filegroup { Loading Loading @@ -334,6 +351,7 @@ android_library { "kotlin-test", "SystemUICustomizationTestUtils", "androidx.compose.runtime_runtime", "kosmos", ], libs: [ "android.test.runner", Loading Loading @@ -416,6 +434,7 @@ android_robolectric_test { "inline-mockito-robolectric-prebuilt", "platform-parametric-runner-lib", "SystemUICustomizationTestUtils", "kosmos", ], libs: [ "android.test.runner", Loading Loading @@ -449,6 +468,7 @@ android_ravenwood_test { "androidx.test.uiautomator_uiautomator", "androidx.core_core-animation-testing", "androidx.test.ext.junit", "kosmos", ], libs: [ "android.test.runner", Loading
packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/Kosmos.kt→packages/SystemUI/tests/utils/kosmos/src/com/android/systemui/kosmos/Kosmos.kt +97 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.kosmos import kotlin.reflect.KProperty Loading @@ -5,6 +21,7 @@ import kotlin.reflect.KProperty // (Historical note: The name Kosmos is meant to invoke "Kotlin", the "Object Mother" pattern // (https://martinfowler.com/bliki/ObjectMother.html), and of course the Greek word "kosmos" for // the "order of the world" (https://en.wiktionary.org/wiki/%CE%BA%CF%8C%CF%83%CE%BC%CE%BF%CF%82) /** * Each Kosmos is its own self-contained set of fixtures, which may reference each other. Fixtures * can be defined through extension properties in any file: Loading @@ -29,9 +46,15 @@ import kotlin.reflect.KProperty * ) * ``` */ class Kosmos { private val map: MutableMap<String, Any?> = mutableMapOf() private val gotten: MutableSet<String> = mutableSetOf() interface Kosmos { /** * Lookup a fixture in the Kosmos by [name], using [creator] to instantiate and store one if * there is none present. */ fun <T> get(name: String, creator: (Kosmos.() -> T)?): T /** Sets the [value] of a fixture with the given [name]. */ fun set(name: String, value: Any?) /** * A value in the kosmos that has a single value once it's read. It can be overridden before Loading @@ -42,28 +65,33 @@ class Kosmos { * If no [creator] parameter is provided, the fixture must be set before use. */ class Fixture<T>(private val creator: (Kosmos.() -> T)? = null) { operator fun getValue(thisRef: Kosmos, property: KProperty<*>): T { thisRef.gotten.add(property.name) @Suppress("UNCHECKED_CAST") if (!thisRef.map.contains(property.name)) { if (creator == null) { throw IllegalStateException( "Fixture ${property.name} has no default, and is read before set." ) } else { val nonNullCreator = creator // The Kotlin compiler seems to need this odd workaround thisRef.map[property.name] = thisRef.nonNullCreator() operator fun getValue(thisRef: Kosmos, property: KProperty<*>): T = thisRef.get(property.name, creator) operator fun setValue(thisRef: Kosmos, property: KProperty<*>, value: T) { thisRef.set(property.name, value) } } return thisRef.map[property.name] as T } operator fun setValue(thisRef: Kosmos, property: KProperty<*>, value: T) { check(!thisRef.gotten.contains(property.name)) { "Tried to set fixture '${property.name}' after it's already been read." /** Constructs a fresh Kosmos. */ fun Kosmos(): Kosmos = KosmosRegistry() private class KosmosRegistry : Kosmos { val map: MutableMap<String, Any?> = mutableMapOf() val gotten: MutableSet<String> = mutableSetOf() override fun <T> get(name: String, creator: (Kosmos.() -> T)?): T { gotten.add(name) if (name !in map) { checkNotNull(creator) { "Fixture $name has no default, and is read before set." } map[name] = creator() } thisRef.map[property.name] = value @Suppress("UNCHECKED_CAST") return map[name] as T } override fun set(name: String, value: Any?) { check(name !in gotten) { "Tried to set fixture '$name' after it's already been read." } map[name] = value } }