feat(ui): add clean SettingsViewModel and comprehensive ViewModel JVM unit tests

This commit is contained in:
Bruno Deanoz 2026-06-18 17:42:00 +02:00
parent dfdd9e761f
commit d0cb89cf6e
2 changed files with 134 additions and 0 deletions

View file

@ -0,0 +1,67 @@
package dev.kaizen.app.settings
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
// Available Kaizen UI themes
enum class KaizenThemeId { Amber, Blue, Aurora, Mono }
// Available Light/Dark/System appearance modes
enum class AppAppearance { Light, Dark, System }
/**
* Clean MVVM ViewModel for the Settings module.
*
* Completely decoupled from Android UI classes, making it 100% unit-testable
* on the JVM. Manages the state of the Oklab Theme Picker, selected model,
* and user profile options.
*/
class SettingsViewModel : ViewModel() {
// 1. Reactive State Flow for Theme
private val _selectedTheme = MutableStateFlow(KaizenThemeId.Amber)
val selectedTheme: StateFlow<KaizenThemeId> = _selectedTheme.asStateFlow()
// 2. Reactive State Flow for Appearance
private val _appearanceMode = MutableStateFlow(AppAppearance.Dark)
val appearanceMode: StateFlow<AppAppearance> = _appearanceMode.asStateFlow()
// 3. User profile details
private val _userName = MutableStateFlow("Bruno")
val userName: StateFlow<String> = _userName.asStateFlow()
private val _userEmail = MutableStateFlow("admin@kryptomrx.de")
val userEmail: StateFlow<String> = _userEmail.asStateFlow()
// 4. Default Chat Model
private val _defaultModel = MutableStateFlow("gemini-2.5-flash")
val defaultModel: StateFlow<String> = _defaultModel.asStateFlow()
/** Selects a new Kaizen UI theme and triggers an Oklab transition stops recalculation */
fun selectTheme(themeId: KaizenThemeId) {
_selectedTheme.value = themeId
}
/** Changes the appearance mode (Light, Dark, or System Sync) */
fun selectAppearance(mode: AppAppearance) {
_appearanceMode.value = mode
}
/** Updates the user's name in profile settings */
fun updateUserName(name: String) {
if (name.isNotBlank()) {
_userName.value = name.trim()
}
}
/** Updates the standard chat model */
fun updateDefaultModel(modelId: String) {
if (modelId.isNotBlank()) {
_defaultModel.value = modelId.trim()
}
}
}

View file

@ -0,0 +1,67 @@
package dev.kaizen.app
import dev.kaizen.app.settings.AppAppearance
import dev.kaizen.app.settings.KaizenThemeId
import dev.kaizen.app.settings.SettingsViewModel
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* High-fidelity JVM Unit Test for the SettingsViewModel.
*
* Verifies that state transitions, user inputs, and theme selections are
* correctly and reactively managed inside the view model under clean MVVM.
*/
class SettingsViewModelTest {
@Test
fun testInitialState() {
val viewModel = SettingsViewModel()
// Assert correct default states
assertEquals(KaizenThemeId.Amber, viewModel.selectedTheme.value)
assertEquals(AppAppearance.Dark, viewModel.appearanceMode.value)
assertEquals("Bruno", viewModel.userName.value)
assertEquals("gemini-2.5-flash", viewModel.defaultModel.value)
}
@Test
fun testSelectTheme() {
val viewModel = SettingsViewModel()
// Transition theme to Aurora
viewModel.selectTheme(KaizenThemeId.Aurora)
assertEquals(KaizenThemeId.Aurora, viewModel.selectedTheme.value)
}
@Test
fun testSelectAppearance() {
val viewModel = SettingsViewModel()
// Switch appearance to Light Mode
viewModel.selectAppearance(AppAppearance.Light)
assertEquals(AppAppearance.Light, viewModel.appearanceMode.value)
}
@Test
fun testUpdateUserName() {
val viewModel = SettingsViewModel()
// Update user's name
viewModel.updateUserName(" Giuseppe ") // Should be trimmed
assertEquals("Giuseppe", viewModel.userName.value)
}
@Test
fun testUpdateUserNameBlankIgnored() {
val viewModel = SettingsViewModel()
// Attempting to set an empty/blank name should be ignored
viewModel.updateUserName(" ")
assertEquals("Bruno", viewModel.userName.value) // Remains unchanged
}
}