1@file:OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
3package soy.iko.opencode.ui.server
5import kotlinx.coroutines.Dispatchers
6import kotlinx.coroutines.ExperimentalCoroutinesApi
7import kotlinx.coroutines.test.StandardTestDispatcher
8import kotlinx.coroutines.test.TestScope
9import kotlinx.coroutines.test.resetMain
10import kotlinx.coroutines.test.runTest
11import kotlinx.coroutines.test.setMain
13import org.junit.Assert.assertEquals
14import org.junit.Assert.assertFalse
15import org.junit.Assert.assertNotNull
16import org.junit.Assert.assertNull
17import org.junit.Assert.assertTrue
18import org.junit.Before
20import soy.iko.opencode.data.model.ServerProfile
21import soy.iko.opencode.ui.testing.FakeAppContainer
23class ServerEditViewModelTest {
24 private val testDispatcher = StandardTestDispatcher()
25 private val testScope = TestScope(testDispatcher)
29 Dispatchers.setMain(testDispatcher)
34 Dispatchers.resetMain()
37 private fun makeVm(container: FakeAppContainer, profileId: String? = null): ServerEditViewModel {
38 val vm = ServerEditViewModel(container, profileId)
39 testScope.testScheduler.advanceUntilIdle()
43 // --- new profile ---
46 fun init_newProfile_loadsEmptyForm() = testScope.runTest {
47 val container = FakeAppContainer()
48 val vm = makeVm(container, profileId = null)
49 assertTrue(vm.state.value.loaded)
50 assertTrue(vm.state.value.isNew)
51 assertEquals("", vm.state.value.baseUrl)
52 assertEquals("", vm.state.value.label)
53 assertFalse(vm.state.value.saving)
54 assertNull(vm.state.value.error)
57 // --- existing profile ---
60 fun init_existingProfile_loadsFormFields() = testScope.runTest {
61 val container = FakeAppContainer()
62 val profile = ServerProfile(
65 baseUrl = "http://localhost:3000",
69 container.fakeProfileStore.setProfiles(listOf(profile))
70 val vm = makeVm(container, profileId = "p1")
71 assertTrue(vm.state.value.loaded)
72 assertFalse(vm.state.value.isNew)
73 assertEquals("p1", vm.state.value.id)
74 assertEquals("My Server", vm.state.value.label)
75 assertEquals("http://localhost:3000", vm.state.value.baseUrl)
76 assertEquals("admin", vm.state.value.username)
77 assertEquals("secret", vm.state.value.password)
81 fun init_nonExistentProfile_showsError() = testScope.runTest {
82 val container = FakeAppContainer()
83 container.fakeProfileStore.setProfiles(emptyList())
84 val vm = makeVm(container, profileId = "nonexistent")
85 assertTrue(vm.state.value.loaded)
86 assertNotNull(vm.state.value.error)
92 fun update_modifiesState() = testScope.runTest {
93 val container = FakeAppContainer()
94 val vm = makeVm(container)
95 vm.update { it.copy(label = "New Label") }
96 assertEquals("New Label", vm.state.value.label)
99 // --- canSave validation ---
102 fun canSave_falseForBlankBaseUrl() = testScope.runTest {
103 val container = FakeAppContainer()
104 val vm = makeVm(container)
105 vm.update { it.copy(baseUrl = "") }
106 assertFalse(vm.state.value.canSave)
110 fun canSave_falseForInvalidUrl() = testScope.runTest {
111 val container = FakeAppContainer()
112 val vm = makeVm(container)
113 vm.update { it.copy(baseUrl = "not a url") }
114 assertFalse(vm.state.value.canSave)
118 fun canSave_trueForValidHttpUrl() = testScope.runTest {
119 val container = FakeAppContainer()
120 val vm = makeVm(container)
121 vm.update { it.copy(baseUrl = "http://localhost:3000") }
122 assertTrue(vm.state.value.canSave)
126 fun canSave_trueForValidHttpsUrl() = testScope.runTest {
127 val container = FakeAppContainer()
128 val vm = makeVm(container)
129 vm.update { it.copy(baseUrl = "https://example.com") }
130 assertTrue(vm.state.value.canSave)
134 fun canSave_falseForFtpUrl() = testScope.runTest {
135 val container = FakeAppContainer()
136 val vm = makeVm(container)
137 vm.update { it.copy(baseUrl = "ftp://example.com") }
138 assertFalse(vm.state.value.canSave)
144 fun save_persistsProfileAndCallsOnDone() = testScope.runTest {
145 val container = FakeAppContainer()
146 val vm = makeVm(container)
147 vm.update { it.copy(baseUrl = "http://localhost:3000", label = "Test") }
148 var doneCalled = false
149 vm.save { doneCalled = true }
150 testScheduler.advanceUntilIdle()
151 assertTrue(doneCalled)
152 assertNotNull(container.fakeProfileStore.savedProfile)
153 assertEquals("http://localhost:3000", container.fakeProfileStore.savedProfile?.baseUrl)
154 assertEquals("Test", container.fakeProfileStore.savedProfile?.label)
158 fun save_invalidUrlDoesNotSave() = testScope.runTest {
159 val container = FakeAppContainer()
160 val vm = makeVm(container)
161 vm.update { it.copy(baseUrl = "invalid") }
162 var doneCalled = false
163 vm.save { doneCalled = true }
164 testScheduler.advanceUntilIdle()
165 assertFalse(doneCalled)
166 assertNull(container.fakeProfileStore.savedProfile)
170 fun save_whileSavingDoesNotSaveAgain() = testScope.runTest {
171 val container = FakeAppContainer()
172 val vm = makeVm(container)
173 vm.update { it.copy(baseUrl = "http://localhost:3000") }
175 vm.save { doneCount++ }
176 // While saving, try to save again
177 vm.save { doneCount++ }
178 testScheduler.advanceUntilIdle()
179 assertEquals(1, doneCount)
183 fun save_generatesIdForNewProfile() = testScope.runTest {
184 val container = FakeAppContainer()
185 val vm = makeVm(container)
186 vm.update { it.copy(baseUrl = "http://localhost:3000") }
188 testScheduler.advanceUntilIdle()
189 val saved = container.fakeProfileStore.savedProfile
190 assertNotNull(saved?.id)
191 assertTrue(saved!!.id.isNotEmpty())
195 fun save_preservesIdForExistingProfile() = testScope.runTest {
196 val container = FakeAppContainer()
197 val profile = ServerProfile(id = "existing-id", label = "Old", baseUrl = "http://old")
198 container.fakeProfileStore.setProfiles(listOf(profile))
199 val vm = makeVm(container, profileId = "existing-id")
200 vm.update { it.copy(baseUrl = "http://new") }
202 testScheduler.advanceUntilIdle()
203 assertEquals("existing-id", container.fakeProfileStore.savedProfile?.id)
207 fun save_trimsFields() = testScope.runTest {
208 val container = FakeAppContainer()
209 val vm = makeVm(container)
210 vm.update { it.copy(baseUrl = " http://localhost:3000 ", label = " Test ", username = " admin ") }
212 testScheduler.advanceUntilIdle()
213 val saved = container.fakeProfileStore.savedProfile!!
214 assertEquals("http://localhost:3000", saved.baseUrl)
215 assertEquals("Test", saved.label)
216 assertEquals("admin", saved.username)
220 fun save_emptyUsernameClearsCredentials() = testScope.runTest {
221 val container = FakeAppContainer()
222 val vm = makeVm(container)
223 vm.update { it.copy(baseUrl = "http://localhost:3000", username = "", password = "") }
225 testScheduler.advanceUntilIdle()
226 val saved = container.fakeProfileStore.savedProfile!!
227 assertNull(saved.username)
228 assertNull(saved.password)
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