blob: 6e5f776321cdf6143ced14e777d9aa1e0f014e8b [file] [log] [blame]
/*
* Copyright (C) 2023 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.customization.model.picker.color.ui.viewmodel
import android.content.Context
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.customization.picker.color.data.repository.FakeColorPickerRepository
import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
import com.android.customization.picker.color.shared.model.ColorType
import com.android.customization.picker.color.ui.viewmodel.ColorOptionViewModel
import com.android.customization.picker.color.ui.viewmodel.ColorPickerViewModel
import com.android.customization.picker.color.ui.viewmodel.ColorTypeViewModel
import com.android.wallpaper.testing.collectLastValue
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class ColorPickerViewModelTest {
private lateinit var underTest: ColorPickerViewModel
private lateinit var context: Context
@Before
fun setUp() {
context = InstrumentationRegistry.getInstrumentation().targetContext
underTest =
ColorPickerViewModel.Factory(
context = context,
interactor =
ColorPickerInteractor(
repository = FakeColorPickerRepository(context = context),
),
)
.create(ColorPickerViewModel::class.java)
}
@Test
fun `Select a color section color`() = runTest {
val colorSectionOptions = collectLastValue(underTest.colorSectionOptions)
assertColorOptionUiState(colorOptions = colorSectionOptions(), selectedColorOptionIndex = 0)
colorSectionOptions()?.get(2)?.onClick?.invoke()
assertColorOptionUiState(colorOptions = colorSectionOptions(), selectedColorOptionIndex = 2)
colorSectionOptions()?.get(4)?.onClick?.invoke()
assertColorOptionUiState(colorOptions = colorSectionOptions(), selectedColorOptionIndex = 4)
}
@Test
fun `Select a preset color`() = runTest {
val colorTypes = collectLastValue(underTest.colorTypes)
val colorOptions = collectLastValue(underTest.colorOptions)
// Initially, the wallpaper color tab should be selected
assertPickerUiState(
colorTypes = colorTypes(),
colorOptions = colorOptions(),
selectedColorTypeText = "Wallpaper colors",
selectedColorOptionIndex = 0
)
// Select "Basic colors" tab
colorTypes()?.get(ColorType.BASIC_COLOR)?.onClick?.invoke()
assertPickerUiState(
colorTypes = colorTypes(),
colorOptions = colorOptions(),
selectedColorTypeText = "Basic colors",
selectedColorOptionIndex = -1
)
// Select a color option
colorOptions()?.get(2)?.onClick?.invoke()
// Check original option is no longer selected
colorTypes()?.get(ColorType.WALLPAPER_COLOR)?.onClick?.invoke()
assertPickerUiState(
colorTypes = colorTypes(),
colorOptions = colorOptions(),
selectedColorTypeText = "Wallpaper colors",
selectedColorOptionIndex = -1
)
// Check new option is selected
colorTypes()?.get(ColorType.BASIC_COLOR)?.onClick?.invoke()
assertPickerUiState(
colorTypes = colorTypes(),
colorOptions = colorOptions(),
selectedColorTypeText = "Basic colors",
selectedColorOptionIndex = 2
)
}
/**
* Asserts the entire picker UI state is what is expected. This includes the color type tabs and
* the color options list.
*
* @param colorTypes The observed color type view-models, keyed by ColorType
* @param colorOptions The observed color options
* @param selectedColorTypeText The text of the color type that's expected to be selected
* @param selectedColorOptionIndex The index of the color option that's expected to be selected,
* -1 stands for no color option should be selected
*/
private fun assertPickerUiState(
colorTypes: Map<ColorType, ColorTypeViewModel>?,
colorOptions: List<ColorOptionViewModel>?,
selectedColorTypeText: String,
selectedColorOptionIndex: Int,
) {
assertColorTypeTabUiState(
colorTypes = colorTypes,
colorTypeId = ColorType.WALLPAPER_COLOR,
isSelected = "Wallpaper colors" == selectedColorTypeText,
)
assertColorTypeTabUiState(
colorTypes = colorTypes,
colorTypeId = ColorType.BASIC_COLOR,
isSelected = "Basic colors" == selectedColorTypeText,
)
assertColorOptionUiState(colorOptions, selectedColorOptionIndex)
}
/**
* Asserts the picker section UI state is what is expected.
*
* @param colorOptions The observed color options
* @param selectedColorOptionIndex The index of the color option that's expected to be selected,
* -1 stands for no color option should be selected
*/
private fun assertColorOptionUiState(
colorOptions: List<ColorOptionViewModel>?,
selectedColorOptionIndex: Int,
) {
var foundSelectedColorOption = false
assertThat(colorOptions).isNotNull()
if (colorOptions != null) {
for (i in colorOptions.indices) {
val colorOptionHasSelectedIndex = i == selectedColorOptionIndex
assertWithMessage(
"Expected color option with index \"${i}\" to have" +
" isSelected=$colorOptionHasSelectedIndex but it was" +
" ${colorOptions[i].isSelected}, num options: ${colorOptions.size}"
)
.that(colorOptions[i].isSelected)
.isEqualTo(colorOptionHasSelectedIndex)
foundSelectedColorOption = foundSelectedColorOption || colorOptionHasSelectedIndex
}
if (selectedColorOptionIndex == -1) {
assertWithMessage(
"Expected no color options to be selected, but a color option is" +
" selected"
)
.that(foundSelectedColorOption)
.isFalse()
} else {
assertWithMessage(
"Expected a color option to be selected, but no color option is" +
" selected"
)
.that(foundSelectedColorOption)
.isTrue()
}
}
}
/**
* Asserts that a color type tab has the correct UI state.
*
* @param colorTypes The observed color type view-models, keyed by ColorType enum
* @param colorTypeId the ID of the color type to assert
* @param isSelected Whether that color type should be selected
*/
private fun assertColorTypeTabUiState(
colorTypes: Map<ColorType, ColorTypeViewModel>?,
colorTypeId: ColorType,
isSelected: Boolean,
) {
val viewModel =
colorTypes?.get(colorTypeId) ?: error("No color type with ID \"$colorTypeId\"!")
assertThat(viewModel.isSelected).isEqualTo(isSelected)
}
}