Add tests.

Bug: 256582545
Test: unit-test & local build gallery
Change-Id: Icd7ce7e2256f6f79953e48d52f436ddecb915fe2
diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp
index 3ea3b5c..40613ce 100644
--- a/packages/SettingsLib/Spa/spa/Android.bp
+++ b/packages/SettingsLib/Spa/spa/Android.bp
@@ -44,3 +44,9 @@
     ],
     min_sdk_version: "31",
 }
+
+// Expose the srcs to tests, so the tests can access the internal classes.
+filegroup {
+    name: "SpaLib_srcs",
+    srcs: ["src/**/*.kt"],
+}
diff --git a/packages/SettingsLib/Spa/spa/build.gradle b/packages/SettingsLib/Spa/spa/build.gradle
index 6ddedd4..85ac8ec 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -101,10 +101,6 @@
             excludes: [
                     "com/android/settingslib/spa/debug/**",
 
-                    // Excludes inline functions, which is not covered in Jacoco reports.
-                    "com/android/settingslib/spa/framework/util/Collections*",
-                    "com/android/settingslib/spa/framework/util/Flows*",
-
                     // Excludes files forked from AndroidX.
                     "com/android/settingslib/spa/widget/scaffold/CustomizedAppBar*",
                     "com/android/settingslib/spa/widget/scaffold/TopAppBarColors*",
@@ -112,6 +108,17 @@
                     // Excludes files forked from Accompanist.
                     "com/android/settingslib/spa/framework/compose/DrawablePainter*",
                     "com/android/settingslib/spa/framework/compose/Pager*",
+
+                    // Excludes inline functions, which is not covered in Jacoco reports.
+                    "com/android/settingslib/spa/framework/util/Collections*",
+                    "com/android/settingslib/spa/framework/util/Flows*",
+
+                    // Excludes debug functions
+                    "com/android/settingslib/spa/framework/compose/TimeMeasurer*",
+
+                    // Excludes slice demo presenter & provider
+                    "com/android/settingslib/spa/slice/presenter/Demo*",
+                    "com/android/settingslib/spa/slice/provider/Demo*",
             ],
     )
     executionData.from = fileTree(dir: "$buildDir/outputs/code_coverage/debugAndroidTest/connected")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index bb968eb..0871304 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -25,8 +25,8 @@
 import androidx.compose.runtime.remember
 import com.android.settingslib.spa.framework.compose.LocalNavController
 
-const val INJECT_ENTRY_NAME = "INJECT"
-const val ROOT_ENTRY_NAME = "ROOT"
+private const val INJECT_ENTRY_NAME = "INJECT"
+private const val ROOT_ENTRY_NAME = "ROOT"
 
 interface EntryData {
     val pageId: String?
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
index 6d0b810..f672ee0 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
@@ -29,6 +29,10 @@
 object SpaEnvironmentFactory {
     private var spaEnvironment: SpaEnvironment? = null
 
+    fun reset() {
+        spaEnvironment = null
+    }
+
     fun reset(env: SpaEnvironment) {
         spaEnvironment = env
         Log.d(TAG, "reset")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
index fa17e08..d72ec26 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.os.Build
+import androidx.annotation.VisibleForTesting
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.staticCompositionLocalOf
@@ -64,7 +65,8 @@
  *
  * @param context The context required to get system resource data.
  */
-private fun dynamicLightColorScheme(context: Context): SettingsColorScheme {
+@VisibleForTesting
+internal fun dynamicLightColorScheme(context: Context): SettingsColorScheme {
     val tonalPalette = dynamicTonalPalette(context)
     return SettingsColorScheme(
         background = tonalPalette.neutral95,
@@ -90,7 +92,8 @@
  *
  * @param context The context required to get system resource data.
  */
-private fun dynamicDarkColorScheme(context: Context): SettingsColorScheme {
+@VisibleForTesting
+internal fun dynamicDarkColorScheme(context: Context): SettingsColorScheme {
     val tonalPalette = dynamicTonalPalette(context)
     return SettingsColorScheme(
         background = tonalPalette.neutral10,
@@ -107,7 +110,8 @@
     )
 }
 
-private fun darkColorScheme(): SettingsColorScheme {
+@VisibleForTesting
+internal fun darkColorScheme(): SettingsColorScheme {
     val tonalPalette = tonalPalette()
     return SettingsColorScheme(
         background = tonalPalette.neutral10,
@@ -124,7 +128,8 @@
     )
 }
 
-private fun lightColorScheme(): SettingsColorScheme {
+@VisibleForTesting
+internal fun lightColorScheme(): SettingsColorScheme {
     val tonalPalette = tonalPalette()
     return SettingsColorScheme(
         background = tonalPalette.neutral95,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
index 21bc75a..a1543d4 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
@@ -125,7 +125,7 @@
     }
 
     @VisibleForTesting
-    fun querySearchImmutableStatusData(): Cursor {
+    internal fun querySearchImmutableStatusData(): Cursor {
         val entryRepository by spaEnvironment.entryRepository
         val cursor = MatrixCursor(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.getColumns())
         for (entry in entryRepository.getAllEntries()) {
@@ -136,7 +136,7 @@
     }
 
     @VisibleForTesting
-    fun querySearchMutableStatusData(): Cursor {
+    internal fun querySearchMutableStatusData(): Cursor {
         val entryRepository by spaEnvironment.entryRepository
         val cursor = MatrixCursor(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.getColumns())
         for (entry in entryRepository.getAllEntries()) {
@@ -147,7 +147,7 @@
     }
 
     @VisibleForTesting
-    fun querySearchStaticData(): Cursor {
+    internal fun querySearchStaticData(): Cursor {
         val entryRepository by spaEnvironment.entryRepository
         val cursor = MatrixCursor(QueryEnum.SEARCH_STATIC_DATA_QUERY.getColumns())
         for (entry in entryRepository.getAllEntries()) {
@@ -158,7 +158,7 @@
     }
 
     @VisibleForTesting
-    fun querySearchDynamicData(): Cursor {
+    internal fun querySearchDynamicData(): Cursor {
         val entryRepository by spaEnvironment.entryRepository
         val cursor = MatrixCursor(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.getColumns())
         for (entry in entryRepository.getAllEntries()) {
diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp
index 69740058..f9e64ae 100644
--- a/packages/SettingsLib/Spa/tests/Android.bp
+++ b/packages/SettingsLib/Spa/tests/Android.bp
@@ -22,7 +22,10 @@
     name: "SpaLibTests",
     test_suites: ["device-tests"],
 
-    srcs: ["src/**/*.kt"],
+    srcs: [
+        ":SpaLib_srcs",
+        "src/**/*.kt",
+    ],
 
     static_libs: [
         "SpaLib",
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
index 5bf7c28..b600ac6 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
@@ -30,8 +30,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-const val INJECT_ENTRY_NAME = "INJECT"
-const val ROOT_ENTRY_NAME = "ROOT"
+const val INJECT_ENTRY_NAME_TEST = "INJECT"
+const val ROOT_ENTRY_NAME_TEST = "ROOT"
 
 class MacroForTest(private val pageId: String, private val entryId: String) : EntryMacro {
     @Composable
@@ -98,12 +98,12 @@
         val entryInject = SettingsEntryBuilder.createInject(owner).build()
         assertThat(entryInject.id).isEqualTo(
             getUniqueEntryId(
-                INJECT_ENTRY_NAME,
+                INJECT_ENTRY_NAME_TEST,
                 owner,
                 toPage = owner
             )
         )
-        assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME}_mySpp")
+        assertThat(entryInject.displayName).isEqualTo("${INJECT_ENTRY_NAME_TEST}_mySpp")
         assertThat(entryInject.fromPage).isNull()
         assertThat(entryInject.toPage).isNotNull()
     }
@@ -114,7 +114,7 @@
         val entryInject = SettingsEntryBuilder.createRoot(owner, "myRootEntry").build()
         assertThat(entryInject.id).isEqualTo(
             getUniqueEntryId(
-                ROOT_ENTRY_NAME,
+                ROOT_ENTRY_NAME_TEST,
                 owner,
                 toPage = owner
             )
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentTest.kt
new file mode 100644
index 0000000..3b0e36b
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentTest.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.settingslib.spa.framework.common
+
+import android.content.Context
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.google.common.truth.Truth
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SpaEnvironmentTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val spaEnvironment = SpaEnvironmentForTest(context)
+
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun testSpaEnvironmentFactory() {
+        SpaEnvironmentFactory.reset()
+        Truth.assertThat(SpaEnvironmentFactory.isReady()).isFalse()
+        Assert.assertThrows(UnsupportedOperationException::class.java) {
+            SpaEnvironmentFactory.instance
+        }
+
+        SpaEnvironmentFactory.reset(spaEnvironment)
+        Truth.assertThat(SpaEnvironmentFactory.isReady()).isTrue()
+        Truth.assertThat(SpaEnvironmentFactory.instance).isEqualTo(spaEnvironment)
+    }
+
+    @Test
+    fun testSpaEnvironmentFactoryForPreview() {
+        SpaEnvironmentFactory.reset()
+        composeTestRule.setContent {
+            Truth.assertThat(SpaEnvironmentFactory.isReady()).isFalse()
+            SpaEnvironmentFactory.resetForPreview()
+            Truth.assertThat(SpaEnvironmentFactory.isReady()).isTrue()
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
new file mode 100644
index 0000000..5ea92ab
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.settingslib.spa.framework.theme
+
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import androidx.compose.ui.graphics.Color
+
+@RunWith(AndroidJUnit4::class)
+class SettingsColorsTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Test
+    fun testDynamicTheme() {
+        // The dynamic color could be different in different device, just check basic restrictions:
+        // 1. text color is different with background color
+        // 2. primary / spinner color is different with its on-item color
+        val ls = dynamicLightColorScheme(context)
+        assertThat(ls.categoryTitle).isNotEqualTo(ls.background)
+        assertThat(ls.secondaryText).isNotEqualTo(ls.background)
+        assertThat(ls.primaryContainer).isNotEqualTo(ls.onPrimaryContainer)
+        assertThat(ls.spinnerHeaderContainer).isNotEqualTo(ls.onSpinnerHeaderContainer)
+        assertThat(ls.spinnerItemContainer).isNotEqualTo(ls.onSpinnerItemContainer)
+
+        val ds = dynamicDarkColorScheme(context)
+        assertThat(ds.categoryTitle).isNotEqualTo(ds.background)
+        assertThat(ds.secondaryText).isNotEqualTo(ds.background)
+        assertThat(ds.primaryContainer).isNotEqualTo(ds.onPrimaryContainer)
+        assertThat(ds.spinnerHeaderContainer).isNotEqualTo(ds.onSpinnerHeaderContainer)
+        assertThat(ds.spinnerItemContainer).isNotEqualTo(ds.onSpinnerItemContainer)
+    }
+
+    @Test
+    fun testStaticTheme() {
+        val ls = lightColorScheme()
+        assertThat(ls.background).isEqualTo(Color(red = 244, green = 239, blue = 244))
+        assertThat(ls.categoryTitle).isEqualTo(Color(red = 103, green = 80, blue = 164))
+        assertThat(ls.surface).isEqualTo(Color(red = 255, green = 251, blue = 254))
+        assertThat(ls.surfaceHeader).isEqualTo(Color(red = 230, green = 225, blue = 229))
+        assertThat(ls.secondaryText).isEqualTo(Color(red = 73, green = 69, blue = 79))
+        assertThat(ls.primaryContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
+        assertThat(ls.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+        assertThat(ls.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
+        assertThat(ls.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+        assertThat(ls.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
+        assertThat(ls.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
+
+        val ds = darkColorScheme()
+        assertThat(ds.background).isEqualTo(Color(red = 28, green = 27, blue = 31))
+        assertThat(ds.categoryTitle).isEqualTo(Color(red = 234, green = 221, blue = 255))
+        assertThat(ds.surface).isEqualTo(Color(red = 49, green = 48, blue = 51))
+        assertThat(ds.surfaceHeader).isEqualTo(Color(red = 72, green = 70, blue = 73))
+        assertThat(ds.secondaryText).isEqualTo(Color(red = 202, green = 196, blue = 208))
+        assertThat(ds.primaryContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
+        assertThat(ds.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+        assertThat(ds.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
+        assertThat(ds.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
+        assertThat(ds.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
+        assertThat(ds.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt
index 5611f8c..2140c07 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/ProgressBarPreferenceTest.kt
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.spa.widget.preference
 
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Launch
+import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.semantics.ProgressBarRangeInfo
 import androidx.compose.ui.semantics.SemanticsProperties.ProgressBarRangeInfo
 import androidx.compose.ui.test.SemanticsMatcher
@@ -49,6 +52,7 @@
             ProgressBarWithDataPreference(model = object : ProgressBarPreferenceModel {
                 override val title = "Title"
                 override val progress = 0.2f
+                override val icon: ImageVector = Icons.Outlined.Launch
             }, data = "Data")
         }
         composeTestRule.onNodeWithText("Title").assertIsDisplayed()
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/ProgressBarTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/ProgressBarTest.kt
new file mode 100644
index 0000000..072c2cc
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/ProgressBarTest.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.settingslib.spa.widget.ui
+
+import androidx.compose.ui.semantics.ProgressBarRangeInfo
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ProgressBarTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun testProgressBar() {
+        composeTestRule.setContent {
+            LinearProgressBar(progress = .5f)
+            CircularProgressBar(progress = .2f)
+        }
+
+        fun progressEqualsTo(progress: Float): SemanticsMatcher =
+            SemanticsMatcher.expectValue(
+                SemanticsProperties.ProgressBarRangeInfo,
+                ProgressBarRangeInfo(progress, 0f..1f, 0)
+            )
+        composeTestRule.onNode(progressEqualsTo(0.5f)).assertIsDisplayed()
+        composeTestRule.onNode(progressEqualsTo(0.2f)).assertIsDisplayed()
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/TextTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/TextTest.kt
new file mode 100644
index 0000000..7e5b4f8
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/TextTest.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.settingslib.spa.widget.ui
+
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.compose.toState
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TextTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun testTitle() {
+        composeTestRule.setContent {
+            SettingsTitle(title = "myTitleValue")
+            SettingsTitle(title = "myTitleState".toState())
+            PlaceholderTitle(title = "myTitlePlaceholder")
+        }
+        composeTestRule.onNodeWithText("myTitleState").assertIsDisplayed()
+        composeTestRule.onNodeWithText("myTitleValue").assertIsDisplayed()
+        composeTestRule.onNodeWithText("myTitlePlaceholder").assertIsDisplayed()
+    }
+}