1package com.parseable.android
3import com.parseable.android.data.model.AboutInfo
4import com.parseable.android.data.model.ApiResult
5import com.parseable.android.data.model.ServerConfig
6import com.parseable.android.data.repository.ParseableRepository
7import com.parseable.android.data.repository.SettingsRepository
8import com.parseable.android.ui.screens.settings.SettingsViewModel
10import kotlinx.coroutines.Dispatchers
11import kotlinx.coroutines.ExperimentalCoroutinesApi
12import kotlinx.coroutines.flow.flowOf
13import kotlinx.coroutines.test.*
14import kotlinx.serialization.json.JsonObject
15import kotlinx.serialization.json.JsonPrimitive
17import org.junit.Assert.*
18import org.junit.Before
21@OptIn(ExperimentalCoroutinesApi::class)
22class SettingsViewModelTest {
24 private lateinit var settingsRepository: SettingsRepository
25 private lateinit var repository: ParseableRepository
26 private val testDispatcher = UnconfinedTestDispatcher()
30 Dispatchers.setMain(testDispatcher)
31 settingsRepository = mockk(relaxed = true)
32 repository = mockk(relaxed = true)
37 Dispatchers.resetMain()
41 fun `load populates server config from settings`() = runTest {
42 val config = ServerConfig(
43 serverUrl = "https://logs.example.com",
48 coEvery { settingsRepository.serverConfig } returns flowOf(config)
49 coEvery { repository.getAbout() } returns ApiResult.Success(AboutInfo(version = "1.2.0"))
50 coEvery { repository.listUsers() } returns ApiResult.Success(emptyList())
52 val viewModel = SettingsViewModel(settingsRepository, repository)
54 val state = viewModel.state.value
55 assertEquals("https://logs.example.com", state.serverUrl)
56 assertEquals("admin", state.username)
57 assertTrue(state.useTls)
58 assertFalse(state.isLoading)
62 fun `load sets about info on success`() = runTest {
63 val about = AboutInfo(version = "1.2.0", mode = "standalone", license = "AGPL")
64 coEvery { settingsRepository.serverConfig } returns flowOf(null)
65 coEvery { repository.getAbout() } returns ApiResult.Success(about)
66 coEvery { repository.listUsers() } returns ApiResult.Success(emptyList())
68 val viewModel = SettingsViewModel(settingsRepository, repository)
70 val state = viewModel.state.value
71 assertEquals("1.2.0", state.aboutInfo?.version)
72 assertEquals("standalone", state.aboutInfo?.mode)
73 assertNull(state.error)
77 fun `load parses user list from json objects`() = runTest {
79 JsonObject(mapOf("id" to JsonPrimitive("user1"))),
80 JsonObject(mapOf("username" to JsonPrimitive("user2"))),
82 coEvery { settingsRepository.serverConfig } returns flowOf(null)
83 coEvery { repository.getAbout() } returns ApiResult.Success(AboutInfo())
84 coEvery { repository.listUsers() } returns ApiResult.Success(users)
86 val viewModel = SettingsViewModel(settingsRepository, repository)
88 val state = viewModel.state.value
89 assertEquals(listOf("user1", "user2"), state.users)
90 assertFalse(state.isLoading)
94 fun `load sets error when about fails`() = runTest {
95 coEvery { settingsRepository.serverConfig } returns flowOf(null)
96 coEvery { repository.getAbout() } returns ApiResult.Error("Server error", 500)
97 coEvery { repository.listUsers() } returns ApiResult.Success(emptyList())
99 val viewModel = SettingsViewModel(settingsRepository, repository)
101 val state = viewModel.state.value
102 assertNotNull(state.error)
103 assertNull(state.aboutInfo)
104 assertFalse(state.isLoading)
108 fun `load sets error when users fail`() = runTest {
109 coEvery { settingsRepository.serverConfig } returns flowOf(null)
110 coEvery { repository.getAbout() } returns ApiResult.Success(AboutInfo())
111 coEvery { repository.listUsers() } returns ApiResult.Error("Forbidden", 403)
113 val viewModel = SettingsViewModel(settingsRepository, repository)
115 val state = viewModel.state.value
116 assertNotNull(state.error)
117 assertTrue(state.users.isEmpty())
121 fun `load consolidates errors from both about and users`() = runTest {
122 coEvery { settingsRepository.serverConfig } returns flowOf(null)
123 coEvery { repository.getAbout() } returns ApiResult.Error("Server error", 500)
124 coEvery { repository.listUsers() } returns ApiResult.Error("Forbidden", 403)
126 val viewModel = SettingsViewModel(settingsRepository, repository)
128 val state = viewModel.state.value
129 assertNotNull(state.error)
130 // Both error messages should be present
131 assertTrue(state.error!!.contains("Server error"))
132 assertTrue(state.error!!.contains("Permission denied"))
136 fun `load resets isLoading on unexpected exception`() = runTest {
137 coEvery { settingsRepository.serverConfig } returns flowOf(null)
138 coEvery { repository.getAbout() } throws RuntimeException("unexpected")
139 coEvery { repository.listUsers() } returns ApiResult.Success(emptyList())
141 val viewModel = SettingsViewModel(settingsRepository, repository)
143 val state = viewModel.state.value
144 assertFalse(state.isLoading)
145 assertNotNull(state.error)
146 assertTrue(state.error!!.contains("unexpected"))
150 fun `load can be called again to refresh`() = runTest {
151 coEvery { settingsRepository.serverConfig } returns flowOf(null)
152 coEvery { repository.getAbout() } returns ApiResult.Error("fail", 500)
153 coEvery { repository.listUsers() } returns ApiResult.Success(emptyList())
155 val viewModel = SettingsViewModel(settingsRepository, repository)
156 assertNotNull(viewModel.state.value.error)
158 // Fix the mock and reload
159 coEvery { repository.getAbout() } returns ApiResult.Success(AboutInfo(version = "2.0"))
162 val state = viewModel.state.value
163 assertNull(state.error)
164 assertEquals("2.0", state.aboutInfo?.version)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list