@@ -64,7 +64,7 @@ class LoginViewModelTest {
6464 @Test
6565 fun `onLogin succeeds with valid credentials`() = runTest {
6666 coEvery { repository.testConnection() } returns ApiResult.Success("ok")
67− coEvery { repository.getAbout() } returns ApiResult.Success(AboutInfo(version = "1.0"))
67+ coEvery { repository.verifyServer() } returns ApiResult.Success(AboutInfo(version = "1.0"))
6868
6969 viewModel.onServerUrlChange("https://test.parseable.com")
7070 viewModel.onUsernameChange("admin")
@@ -95,7 +95,7 @@ class LoginViewModelTest {
9595 @Test
9696 fun `onLogin fails when about check fails`() = runTest {
9797 coEvery { repository.testConnection() } returns ApiResult.Success("ok")
98− coEvery { repository.getAbout() } returns ApiResult.Error("not parseable", 404)
98+ coEvery { repository.verifyServer() } returns ApiResult.Error("not parseable", 404)
9999
100100 viewModel.onServerUrlChange("https://test.com")
101101 viewModel.onUsernameChange("admin")
@@ -108,6 +108,23 @@ class LoginViewModelTest {
108108 assertTrue(state.error!!.contains("doesn't appear to be Parseable"))
109109 }
110110
111+ @Test
112+ fun `onLogin shows invalid credentials on 401`() = runTest {
113+ coEvery { repository.testConnection() } returns ApiResult.Success("ok")
114+ coEvery { repository.verifyServer() } returns ApiResult.Error("Unauthorized", 401)
115+
116+ viewModel.onServerUrlChange("https://test.parseable.com")
117+ viewModel.onUsernameChange("admin")
118+ viewModel.onPasswordChange("wrongpass")
119+ viewModel.onLogin()
120+
121+ val state = viewModel.state.value
122+ assertFalse(state.loginSuccess)
123+ assertNotNull(state.error)
124+ assertTrue(state.error!!.contains("Invalid credentials"))
125+ assertFalse(state.error!!.contains("doesn't appear to be Parseable"))
126+ }
127+
111128 @Test
112129 fun `onServerUrlChange clears error`() {
113130 viewModel.onLogin() // triggers error
@@ -147,7 +164,7 @@ class LoginViewModelTest {
147164 @Test
148165 fun `onLogin prepends https when not insecure`() = runTest {
149166 coEvery { repository.testConnection() } returns ApiResult.Success("ok")
150− coEvery { repository.getAbout() } returns ApiResult.Success(AboutInfo())
167+ coEvery { repository.verifyServer() } returns ApiResult.Success(AboutInfo())
151168
152169 viewModel.onServerUrlChange("test.parseable.com")
153170 viewModel.onUsernameChange("admin")
@@ -162,7 +179,7 @@ class LoginViewModelTest {
162179 @Test
163180 fun `onLogin prepends http when insecure`() = runTest {
164181 coEvery { repository.testConnection() } returns ApiResult.Success("ok")
165− coEvery { repository.getAbout() } returns ApiResult.Success(AboutInfo())
182+ coEvery { repository.verifyServer() } returns ApiResult.Success(AboutInfo())
166183
167184 viewModel.onServerUrlChange("test.parseable.com")
168185 viewModel.onAllowInsecureChange(true)
@@ -174,4 +191,39 @@ class LoginViewModelTest {
174191 repository.configure(match { it.serverUrl == "http://test.parseable.com" })
175192 }
176193 }
194+
195+ @Test
196+ fun `onLogin handles uppercase URL scheme`() = runTest {
197+ coEvery { repository.testConnection() } returns ApiResult.Success("ok")
198+ coEvery { repository.verifyServer() } returns ApiResult.Success(AboutInfo())
199+
200+ viewModel.onServerUrlChange("HTTPS://test.parseable.com")
201+ viewModel.onUsernameChange("admin")
202+ viewModel.onPasswordChange("pass")
203+ viewModel.onLogin()
204+
205+ coVerify {
206+ repository.configure(match {
207+ it.serverUrl == "HTTPS://test.parseable.com" && it.useTls
208+ })
209+ }
210+ }
211+
212+ @Test
213+ fun `onLogin handles mixed case URL scheme`() = runTest {
214+ coEvery { repository.testConnection() } returns ApiResult.Success("ok")
215+ coEvery { repository.verifyServer() } returns ApiResult.Success(AboutInfo())
216+
217+ viewModel.onServerUrlChange("Http://test.parseable.com")
218+ viewModel.onAllowInsecureChange(true)
219+ viewModel.onUsernameChange("admin")
220+ viewModel.onPasswordChange("pass")
221+ viewModel.onLogin()
222+
223+ coVerify {
224+ repository.configure(match {
225+ it.serverUrl == "Http://test.parseable.com" && !it.useTls
226+ })
227+ }
228+ }
177229}