Add tests.
Bug: 256582545 Test: unit-test & local build gallery Change-Id: Icd7ce7e2256f6f79953e48d52f436ddecb915fe2
This commit is contained in:
@@ -44,3 +44,9 @@ android_library {
|
||||
],
|
||||
min_sdk_version: "31",
|
||||
}
|
||||
|
||||
// Expose the srcs to tests, so the tests can access the internal classes.
|
||||
filegroup {
|
||||
name: "SpaLib_srcs",
|
||||
srcs: ["src/**/*.kt"],
|
||||
}
|
||||
|
||||
@@ -101,10 +101,6 @@ task coverageReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest")
|
||||
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 @@ task coverageReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest")
|
||||
// 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")
|
||||
|
||||
@@ -25,8 +25,8 @@ import androidx.compose.runtime.compositionLocalOf
|
||||
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?
|
||||
|
||||
@@ -29,6 +29,10 @@ private const val TAG = "SpaEnvironment"
|
||||
object SpaEnvironmentFactory {
|
||||
private var spaEnvironment: SpaEnvironment? = null
|
||||
|
||||
fun reset() {
|
||||
spaEnvironment = null
|
||||
}
|
||||
|
||||
fun reset(env: SpaEnvironment) {
|
||||
spaEnvironment = env
|
||||
Log.d(TAG, "reset")
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settingslib.spa.framework.theme
|
||||
|
||||
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 @@ internal fun settingsColorScheme(isDarkTheme: Boolean): SettingsColorScheme {
|
||||
*
|
||||
* @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 @@ private fun dynamicLightColorScheme(context: Context): SettingsColorScheme {
|
||||
*
|
||||
* @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 dynamicDarkColorScheme(context: Context): SettingsColorScheme {
|
||||
)
|
||||
}
|
||||
|
||||
private fun darkColorScheme(): SettingsColorScheme {
|
||||
@VisibleForTesting
|
||||
internal fun darkColorScheme(): SettingsColorScheme {
|
||||
val tonalPalette = tonalPalette()
|
||||
return SettingsColorScheme(
|
||||
background = tonalPalette.neutral10,
|
||||
@@ -124,7 +128,8 @@ private fun darkColorScheme(): SettingsColorScheme {
|
||||
)
|
||||
}
|
||||
|
||||
private fun lightColorScheme(): SettingsColorScheme {
|
||||
@VisibleForTesting
|
||||
internal fun lightColorScheme(): SettingsColorScheme {
|
||||
val tonalPalette = tonalPalette()
|
||||
return SettingsColorScheme(
|
||||
background = tonalPalette.neutral95,
|
||||
|
||||
@@ -125,7 +125,7 @@ class SpaSearchProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
@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 @@ class SpaSearchProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
@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 @@ class SpaSearchProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
@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 @@ class SpaSearchProvider : ContentProvider() {
|
||||
}
|
||||
|
||||
@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()) {
|
||||
|
||||
@@ -22,7 +22,10 @@ android_test {
|
||||
name: "SpaLibTests",
|
||||
test_suites: ["device-tests"],
|
||||
|
||||
srcs: ["src/**/*.kt"],
|
||||
srcs: [
|
||||
":SpaLib_srcs",
|
||||
"src/**/*.kt",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"SpaLib",
|
||||
|
||||
@@ -30,8 +30,8 @@ import org.junit.Rule
|
||||
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 @@ class SettingsEntryTest {
|
||||
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 @@ class SettingsEntryTest {
|
||||
val entryInject = SettingsEntryBuilder.createRoot(owner, "myRootEntry").build()
|
||||
assertThat(entryInject.id).isEqualTo(
|
||||
getUniqueEntryId(
|
||||
ROOT_ENTRY_NAME,
|
||||
ROOT_ENTRY_NAME_TEST,
|
||||
owner,
|
||||
toPage = owner
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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 @@ class ProgressBarPreferenceTest {
|
||||
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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user