chore: upgrade ktlint to 1.8.0 and format codebase (#1024)
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
3f3b853758
commit
cfe3e736fd
66 files changed
+1287
-541
No files matched your search
@@ -20,7 +20,13 @@ class KanbanEventsClientTest {
|
||||
assertEquals("t-1", event.taskId)
|
||||
assertEquals("r-9", event.runId)
|
||||
assertEquals("status", event.kind)
|
||||
assertEquals("done", event.payload?.get("status")?.jsonPrimitive?.content)
|
||||
assertEquals(
|
||||
"done",
|
||||
event.payload
|
||||
?.get("status")
|
||||
?.jsonPrimitive
|
||||
?.content,
|
||||
)
|
||||
assertEquals(1710000000L, event.createdAt)
|
||||
}
|
||||
|
||||
|
||||
@@ -143,12 +143,16 @@ class BotsViewModelTest {
|
||||
|
||||
// Toggle show hidden (sorted: default (active), scout (worker active now), reviewer (canonical last_active))
|
||||
viewModel.toggleShowHidden()
|
||||
val displayedWithHidden = viewModel.uiState.value.displayProfiles.map { it.name }
|
||||
val displayedWithHidden =
|
||||
viewModel.uiState.value.displayProfiles
|
||||
.map { it.name }
|
||||
assertEquals(listOf("default", "reviewer", "scout"), displayedWithHidden)
|
||||
|
||||
// Search filter
|
||||
viewModel.setSearchQuery("arxiv")
|
||||
val searchResults = viewModel.uiState.value.displayProfiles.map { it.name }
|
||||
val searchResults =
|
||||
viewModel.uiState.value.displayProfiles
|
||||
.map { it.name }
|
||||
assertEquals(listOf("scout"), searchResults)
|
||||
}
|
||||
|
||||
@@ -230,8 +234,16 @@ class BotsViewModelTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
assertEquals(2, viewModel.uiState.value.allGroups.size)
|
||||
assertEquals("Dream Team", viewModel.uiState.value.allGroups[0].name)
|
||||
assertEquals(2, viewModel.uiState.value.allGroups[0].members.size)
|
||||
assertEquals(
|
||||
"Dream Team",
|
||||
viewModel.uiState.value.allGroups[0]
|
||||
.name,
|
||||
)
|
||||
assertEquals(
|
||||
2,
|
||||
viewModel.uiState.value.allGroups[0]
|
||||
.members.size,
|
||||
)
|
||||
|
||||
var success = false
|
||||
viewModel.disbandGroupChat("Dream Team") { success = true }
|
||||
|
||||
@@ -205,7 +205,9 @@ class GroupChatViewModelTest {
|
||||
testScheduler.runCurrent()
|
||||
|
||||
// State should contain user message
|
||||
val userMsg = viewModel.uiState.value.messages.first()
|
||||
val userMsg =
|
||||
viewModel.uiState.value.messages
|
||||
.first()
|
||||
assertTrue(userMsg.isUser)
|
||||
assertEquals("@scout what's the status?", userMsg.text)
|
||||
|
||||
@@ -213,7 +215,9 @@ class GroupChatViewModelTest {
|
||||
eventsFlow.emit(WsEvent.MessageToken(token = "Building ", sessionId = "session-scout-1"))
|
||||
testScheduler.runCurrent()
|
||||
|
||||
val streamingMsg = viewModel.uiState.value.messages.last()
|
||||
val streamingMsg =
|
||||
viewModel.uiState.value.messages
|
||||
.last()
|
||||
assertFalse(streamingMsg.isUser)
|
||||
assertEquals("scout", streamingMsg.senderName)
|
||||
assertEquals("Building ", streamingMsg.text)
|
||||
@@ -222,7 +226,9 @@ class GroupChatViewModelTest {
|
||||
eventsFlow.emit(WsEvent.MessageToken(token = "the APK...", sessionId = "session-scout-1"))
|
||||
testScheduler.runCurrent()
|
||||
|
||||
val updatedStreaming = viewModel.uiState.value.messages.last()
|
||||
val updatedStreaming =
|
||||
viewModel.uiState.value.messages
|
||||
.last()
|
||||
assertEquals("Building the APK...", updatedStreaming.text)
|
||||
|
||||
// Complete turn
|
||||
@@ -285,7 +291,11 @@ class GroupChatViewModelTest {
|
||||
testScheduler.runCurrent()
|
||||
|
||||
assertEquals(2, viewModel.uiState.value.messages.size)
|
||||
assertEquals("scout", viewModel.uiState.value.messages[1].senderName)
|
||||
assertEquals(
|
||||
"scout",
|
||||
viewModel.uiState.value.messages[1]
|
||||
.senderName,
|
||||
)
|
||||
|
||||
// Continuation pass triggers coder
|
||||
eventsFlow.emit(
|
||||
@@ -345,7 +355,11 @@ class GroupChatViewModelTest {
|
||||
|
||||
// Because lease is held by desktop_client_99, mobile only posts the user message and yields
|
||||
assertEquals(1, viewModel.uiState.value.messages.size)
|
||||
assertTrue(viewModel.uiState.value.messages.first().isUser)
|
||||
assertTrue(
|
||||
viewModel.uiState.value.messages
|
||||
.first()
|
||||
.isUser,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -452,7 +466,9 @@ class GroupChatViewModelTest {
|
||||
)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
val msgWithTool = viewModel.uiState.value.messages.last()
|
||||
val msgWithTool =
|
||||
viewModel.uiState.value.messages
|
||||
.last()
|
||||
assertEquals(1, msgWithTool.toolCalls.size)
|
||||
val toolCall = msgWithTool.toolCalls.first()
|
||||
assertEquals("terminal", toolCall.name)
|
||||
@@ -469,7 +485,9 @@ class GroupChatViewModelTest {
|
||||
)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
val msgAfterToolDone = viewModel.uiState.value.messages.last()
|
||||
val msgAfterToolDone =
|
||||
viewModel.uiState.value.messages
|
||||
.last()
|
||||
assertFalse(msgAfterToolDone.toolCalls.first().isRunning)
|
||||
|
||||
// Complete message
|
||||
@@ -481,7 +499,9 @@ class GroupChatViewModelTest {
|
||||
)
|
||||
testScheduler.runCurrent()
|
||||
|
||||
val finalMsg = viewModel.uiState.value.messages.last()
|
||||
val finalMsg =
|
||||
viewModel.uiState.value.messages
|
||||
.last()
|
||||
assertEquals("Current time is Sat Aug 29", finalMsg.text)
|
||||
assertEquals(1, finalMsg.toolCalls.size)
|
||||
assertFalse(finalMsg.toolCalls.first().isRunning)
|
||||
|
||||
@@ -158,7 +158,13 @@ class ChatInputPolicyTest {
|
||||
|
||||
@Test
|
||||
fun applyMention_insertsHandleAndAdvancesCursor() {
|
||||
val initial = TextFieldValue("ask @sc", selection = androidx.compose.ui.text.TextRange(7))
|
||||
val initial =
|
||||
TextFieldValue(
|
||||
"ask @sc",
|
||||
selection =
|
||||
androidx.compose.ui.text
|
||||
.TextRange(7),
|
||||
)
|
||||
val updated = ChatInputPolicy.applyMention(initial, "scout")
|
||||
assertEquals("ask @scout ", updated.text)
|
||||
assertEquals(11, updated.selection.end)
|
||||
|
||||
@@ -369,12 +369,13 @@ class ChatToolDedupeTest {
|
||||
var stream = StreamingState()
|
||||
stream = ChatWsEventReducer.reduce(s, stream, WsEvent.MessageStart("session-1"), "session-1").streamingState
|
||||
stream =
|
||||
ChatWsEventReducer.reduce(
|
||||
s,
|
||||
stream,
|
||||
WsEvent.ReasoningDelta("thinking about meow", "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
ChatWsEventReducer
|
||||
.reduce(
|
||||
s,
|
||||
stream,
|
||||
WsEvent.ReasoningDelta("thinking about meow", "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
var r =
|
||||
ChatWsEventReducer.reduce(
|
||||
s,
|
||||
|
||||
@@ -159,7 +159,12 @@ class ChatUpdateCommandTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
assertTrue("confirm dialog should open", vm.uiState.value.updateConfirmOpen)
|
||||
assertEquals("/update", vm.uiState.value.messages.last().content)
|
||||
assertEquals(
|
||||
"/update",
|
||||
vm.uiState.value.messages
|
||||
.last()
|
||||
.content,
|
||||
)
|
||||
|
||||
// The whole point of the fix: NOTHING goes over the wire.
|
||||
verify(exactly = 0) {
|
||||
|
||||
@@ -513,7 +513,10 @@ class ChatViewModelTest {
|
||||
|
||||
// A blocklisted command can never dispatch — it must not climb
|
||||
// the autocomplete ranking either.
|
||||
assertTrue(viewModel.uiState.value.slashUsageCounts.isEmpty())
|
||||
assertTrue(
|
||||
viewModel.uiState.value.slashUsageCounts
|
||||
.isEmpty(),
|
||||
)
|
||||
verify(exactly = 0) {
|
||||
HermesWsClient.request(WsMethods.COMMAND_DISPATCH, any(), any())
|
||||
}
|
||||
@@ -1033,7 +1036,10 @@ class ChatViewModelTest {
|
||||
viewModel.uiState.value.messages[1]
|
||||
.role,
|
||||
)
|
||||
assertFalse(viewModel.uiState.value.messages[1].isStreaming)
|
||||
assertFalse(
|
||||
viewModel.uiState.value.messages[1]
|
||||
.isStreaming,
|
||||
)
|
||||
assertEquals(
|
||||
MessageRole.TOOL,
|
||||
viewModel.uiState.value.messages[2]
|
||||
@@ -1041,7 +1047,10 @@ class ChatViewModelTest {
|
||||
)
|
||||
assertNull(viewModel.streamingState.value.streamingMessage)
|
||||
assertEquals(
|
||||
listOf(viewModel.uiState.value.messages[1].id),
|
||||
listOf(
|
||||
viewModel.uiState.value.messages[1]
|
||||
.id,
|
||||
),
|
||||
viewModel.streamingState.value.sealedOrphanIds,
|
||||
)
|
||||
|
||||
@@ -1050,7 +1059,8 @@ class ChatViewModelTest {
|
||||
mockEventsFlow.emit(WsEvent.MessageComplete("Calculating sum = 4", sessionId))
|
||||
advanceUntilIdle()
|
||||
val assistant =
|
||||
viewModel.uiState.value.messages.filter { it.role == MessageRole.ASSISTANT }
|
||||
viewModel.uiState.value.messages
|
||||
.filter { it.role == MessageRole.ASSISTANT }
|
||||
assertEquals(2, assistant.size)
|
||||
assertEquals("Calculating sum", assistant[0].content)
|
||||
assertEquals(" = 4", assistant[1].content)
|
||||
@@ -1573,7 +1583,8 @@ class ChatViewModelTest {
|
||||
every { AuthManager.getBaseUrl() } returns "http://test.local/"
|
||||
coEvery { mockApi.getSessions(any(), any(), any()) } returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
)
|
||||
coEvery {
|
||||
mockApi.getSessionMessages(
|
||||
@@ -1623,7 +1634,8 @@ class ChatViewModelTest {
|
||||
|
||||
val empty =
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
messagesA.complete(empty)
|
||||
messagesB.complete(empty)
|
||||
@@ -1641,7 +1653,8 @@ class ChatViewModelTest {
|
||||
every { AuthManager.getBaseUrl() } returns "http://test.local/"
|
||||
coEvery { mockApi.getSessions(any(), any(), any()) } returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionListResponse(sessions = emptyList(), total = 0),
|
||||
)
|
||||
coEvery {
|
||||
mockApi.getSessionMessages(
|
||||
@@ -1698,7 +1711,11 @@ class ChatViewModelTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
assertEquals("session-b", viewModel.uiState.value.currentSessionId)
|
||||
assertEquals(listOf("message-b"), viewModel.uiState.value.messages.map { it.content })
|
||||
assertEquals(
|
||||
listOf("message-b"),
|
||||
viewModel.uiState.value.messages
|
||||
.map { it.content },
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1927,7 +1944,8 @@ class ChatViewModelTest {
|
||||
sessionIds.forEach { sessionId ->
|
||||
coEvery { mockApi.getSessionMessages(sessionId, any(), any(), any(), any()) } returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1956,7 +1974,11 @@ class ChatViewModelTest {
|
||||
// Warm cache painted and survived the exhausted retry cycle — the
|
||||
// screen never went blank, and the user gets history + an error.
|
||||
assertEquals(1, viewModel.uiState.value.messages.size)
|
||||
assertEquals("Cached hello", viewModel.uiState.value.messages[0].content)
|
||||
assertEquals(
|
||||
"Cached hello",
|
||||
viewModel.uiState.value.messages[0]
|
||||
.content,
|
||||
)
|
||||
assertFalse(viewModel.uiState.value.isLoading)
|
||||
assertNotNull("resumeError must be set after retries exhaust", viewModel.uiState.value.resumeError)
|
||||
assertFalse(viewModel.uiState.value.isResumeRetrying)
|
||||
@@ -2305,7 +2327,8 @@ class ChatViewModelTest {
|
||||
assertEquals("session-new", viewModel.uiState.value.currentSessionId)
|
||||
assertTrue(
|
||||
"recovery notice must be visible",
|
||||
viewModel.uiState.value.messages.any { it.content.contains("no longer available") },
|
||||
viewModel.uiState.value.messages
|
||||
.any { it.content.contains("no longer available") },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2328,7 +2351,8 @@ class ChatViewModelTest {
|
||||
ApiClient.hermesApi.getSessionMessages(capture(fetchedSessions), any(), any(), any(), any())
|
||||
} returns
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
|
||||
// /fork sends session.branch keyed on the runtime id.
|
||||
@@ -2379,7 +2403,8 @@ class ChatViewModelTest {
|
||||
)
|
||||
} else {
|
||||
retrofit2.Response.success(
|
||||
com.m57.hermescontrol.data.model.SessionMessagesResponse(messages = emptyList()),
|
||||
com.m57.hermescontrol.data.model
|
||||
.SessionMessagesResponse(messages = emptyList()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3301,7 +3326,12 @@ class ChatViewModelTest {
|
||||
assertTrue(viewModel.uiState.value.hasOlderMessages)
|
||||
assertEquals(150, viewModel.uiState.value.messages.size)
|
||||
// Stable keys come from the server row id, not the from-end position.
|
||||
assertEquals("rest-session-456-150", viewModel.uiState.value.messages.last().id)
|
||||
assertEquals(
|
||||
"rest-session-456-150",
|
||||
viewModel.uiState.value.messages
|
||||
.last()
|
||||
.id,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3444,7 +3474,10 @@ class ChatViewModelTest {
|
||||
// 160 rows: the 10 new ones appended, the existing 150 kept —
|
||||
// no duplicates, no dropped newest copy (stable row-id keys).
|
||||
assertEquals(160, viewModel.uiState.value.messages.size)
|
||||
assertTrue(viewModel.uiState.value.messages.any { it.id == "rest-session-456-160" })
|
||||
assertTrue(
|
||||
viewModel.uiState.value.messages
|
||||
.any { it.id == "rest-session-456-160" },
|
||||
)
|
||||
}
|
||||
|
||||
// ── Attachment open (issue #724) ─────────────────────────────────────
|
||||
@@ -3506,15 +3539,17 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
val file =
|
||||
java.io.File(System.getProperty("java.io.tmpdir"), "note_${System.nanoTime()}.txt")
|
||||
java.io
|
||||
.File(System.getProperty("java.io.tmpdir"), "note_${System.nanoTime()}.txt")
|
||||
.apply { writeText("downloaded") }
|
||||
coEvery { GatewayFileClient.fetch("/tmp/note.txt", any()) } returns
|
||||
GatewayFileResult.Success(GatewayFile("note.txt", "text/plain", file))
|
||||
@@ -3552,10 +3587,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3590,10 +3626,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3606,7 +3643,8 @@ class ChatViewModelTest {
|
||||
GatewayFile(
|
||||
"report.pdf",
|
||||
"application/pdf",
|
||||
java.io.File(System.getProperty("java.io.tmpdir"), "report_${System.nanoTime()}.pdf")
|
||||
java.io
|
||||
.File(System.getProperty("java.io.tmpdir"), "report_${System.nanoTime()}.pdf")
|
||||
.apply { writeBytes(byteArrayOf(1)) },
|
||||
),
|
||||
)
|
||||
@@ -3625,7 +3663,11 @@ class ChatViewModelTest {
|
||||
|
||||
verify(exactly = 0) { resolver.delete(any(), any(), any()) }
|
||||
assertNull(viewModel.uiState.value.savingAttachmentPath)
|
||||
assertTrue(viewModel.uiState.value.openError.orEmpty().startsWith("Could not save"))
|
||||
assertTrue(
|
||||
viewModel.uiState.value.openError
|
||||
.orEmpty()
|
||||
.startsWith("Could not save"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3633,10 +3675,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_save_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3675,10 +3718,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3711,10 +3755,11 @@ class ChatViewModelTest {
|
||||
runTest {
|
||||
mockkObject(GatewayFileClient)
|
||||
val cacheDir =
|
||||
java.io.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
java.io
|
||||
.File(
|
||||
System.getProperty("java.io.tmpdir"),
|
||||
"gw_open_${System.nanoTime()}",
|
||||
).apply { mkdirs() }
|
||||
every { app.cacheDir } returns cacheDir
|
||||
every { app.applicationContext } returns app
|
||||
every { app.getApplicationContext() } returns app
|
||||
@@ -3743,7 +3788,11 @@ class ChatViewModelTest {
|
||||
|
||||
// …and cleared in all outcomes.
|
||||
assertNull(vm.uiState.value.openingAttachmentPath)
|
||||
assertTrue(vm.uiState.value.openError.orEmpty().contains("big.pdf"))
|
||||
assertTrue(
|
||||
vm.uiState.value.openError
|
||||
.orEmpty()
|
||||
.contains("big.pdf"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3763,7 +3812,10 @@ class ChatViewModelTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
// Optimistic UI state has the user message immediately
|
||||
assertTrue(vm.uiState.value.messages.any { it.content == "My super important long prompt" })
|
||||
assertTrue(
|
||||
vm.uiState.value.messages
|
||||
.any { it.content == "My super important long prompt" },
|
||||
)
|
||||
assertTrue(vm.uiState.value.isAgentTyping)
|
||||
// But wsClient.sendMessage not dispatched yet because session_id was null
|
||||
assertTrue(sentPrompts.isEmpty())
|
||||
@@ -3781,7 +3833,10 @@ class ChatViewModelTest {
|
||||
// Prompt should be dispatched automatically!
|
||||
assertEquals(listOf("My super important long prompt"), sentPrompts)
|
||||
assertEquals("session-storage-969", vm.uiState.value.currentSessionId)
|
||||
assertTrue(vm.uiState.value.messages.any { it.content == "My super important long prompt" })
|
||||
assertTrue(
|
||||
vm.uiState.value.messages
|
||||
.any { it.content == "My super important long prompt" },
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3806,7 +3861,10 @@ class ChatViewModelTest {
|
||||
advanceUntilIdle()
|
||||
|
||||
// Optimistic message in UI
|
||||
assertTrue(vm.uiState.value.messages.any { it.content == "Prompt typed during reconnect" })
|
||||
assertTrue(
|
||||
vm.uiState.value.messages
|
||||
.any { it.content == "Prompt typed during reconnect" },
|
||||
)
|
||||
|
||||
// Complete the new SESSION_CREATE RPC
|
||||
mockEventsFlow.emit(
|
||||
@@ -3842,6 +3900,9 @@ class ChatViewModelTest {
|
||||
|
||||
assertFalse(vm.uiState.value.isAgentTyping)
|
||||
assertNotNull(vm.uiState.value.errorMessage)
|
||||
assertTrue(vm.uiState.value.errorMessage!!.contains("Backend exploded"))
|
||||
assertTrue(
|
||||
vm.uiState.value.errorMessage!!
|
||||
.contains("Backend exploded"),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -421,7 +421,12 @@ class ChatWsEventReducerTest {
|
||||
)
|
||||
|
||||
assertEquals(1, result.state.messages.size)
|
||||
assertEquals("complete", result.state.messages.single().content)
|
||||
assertEquals(
|
||||
"complete",
|
||||
result.state.messages
|
||||
.single()
|
||||
.content,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -556,12 +561,13 @@ class ChatWsEventReducerTest {
|
||||
var reasoningState = start.streamingState
|
||||
for (token in reasoningTokens) {
|
||||
reasoningState =
|
||||
ChatWsEventReducer.reduce(
|
||||
state,
|
||||
reasoningState,
|
||||
WsEvent.ReasoningDelta(token, "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
ChatWsEventReducer
|
||||
.reduce(
|
||||
state,
|
||||
reasoningState,
|
||||
WsEvent.ReasoningDelta(token, "session-1"),
|
||||
"session-1",
|
||||
).streamingState
|
||||
}
|
||||
assertEquals(true, reasoningState.isReasoning)
|
||||
assertEquals("The user just said \"run echo hi\". Let me run it.", reasoningState.reasoningText)
|
||||
@@ -578,8 +584,18 @@ class ChatWsEventReducerTest {
|
||||
"session-1",
|
||||
)
|
||||
assertEquals(1, result.state.messages.size)
|
||||
assertEquals(MessageRole.TOOL, result.state.messages.first().role)
|
||||
assertEquals("terminal", result.state.messages.first().toolName)
|
||||
assertEquals(
|
||||
MessageRole.TOOL,
|
||||
result.state.messages
|
||||
.first()
|
||||
.role,
|
||||
)
|
||||
assertEquals(
|
||||
"terminal",
|
||||
result.state.messages
|
||||
.first()
|
||||
.toolName,
|
||||
)
|
||||
// Issue #771: streaming message + reasoning survive the tool call
|
||||
assertEquals(true, result.streamingState.streamingMessage?.isStreaming)
|
||||
assertEquals("The user just said \"run echo hi\". Let me run it.", result.streamingState.reasoningText)
|
||||
@@ -592,7 +608,12 @@ class ChatWsEventReducerTest {
|
||||
WsEvent.ToolComplete("terminal", mapOf("output" to "hi"), "session-1"),
|
||||
"session-1",
|
||||
)
|
||||
assertEquals(ToolStatus.COMPLETED, result.state.messages.first().toolStatus)
|
||||
assertEquals(
|
||||
ToolStatus.COMPLETED,
|
||||
result.state.messages
|
||||
.first()
|
||||
.toolStatus,
|
||||
)
|
||||
|
||||
// 5. reasoning.available — authoritative full-trace fill
|
||||
val fullReasoning = "The user just said \"run echo hi\". That's a simple terminal command. Let me just run it."
|
||||
@@ -683,7 +704,12 @@ class ChatWsEventReducerTest {
|
||||
"session-1",
|
||||
)
|
||||
|
||||
assertEquals("payload reasoning", result.state.messages.last().reasoningText)
|
||||
assertEquals(
|
||||
"payload reasoning",
|
||||
result.state.messages
|
||||
.last()
|
||||
.reasoningText,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -223,7 +223,8 @@ class SlashCommandDispatchRpcTest {
|
||||
// The optimistic bubble shows the queued TEXT (prefix stripped) so
|
||||
// the transcript sync dedupes it against the server echo.
|
||||
val userBubble =
|
||||
vm.uiState.value.messages.lastOrNull { it.role == MessageRole.USER }
|
||||
vm.uiState.value.messages
|
||||
.lastOrNull { it.role == MessageRole.USER }
|
||||
assertEquals("do the thing", userBubble?.content)
|
||||
}
|
||||
|
||||
@@ -247,7 +248,9 @@ class SlashCommandDispatchRpcTest {
|
||||
vm.sendMessage("/queue")
|
||||
advanceUntilIdle()
|
||||
|
||||
val last = vm.uiState.value.messages.lastOrNull()
|
||||
val last =
|
||||
vm.uiState.value.messages
|
||||
.lastOrNull()
|
||||
assertEquals("usage: /queue <prompt>", last?.content)
|
||||
assertEquals(0, sendCalls)
|
||||
assertTrue(
|
||||
@@ -628,7 +631,9 @@ class SlashCommandDispatchRpcTest {
|
||||
vm.sendMessage("/focus on")
|
||||
advanceUntilIdle()
|
||||
|
||||
val last = vm.uiState.value.messages.lastOrNull()
|
||||
val last =
|
||||
vm.uiState.value.messages
|
||||
.lastOrNull()
|
||||
assertEquals("Focus view: ON (tool progress pinned off)", last?.content)
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,10 @@ class ActionProgressControllerTest {
|
||||
tick()
|
||||
|
||||
assertEquals(ActionProgressPhase.SUCCEEDED, controller.state.value.phase)
|
||||
assertTrue(controller.state.value.trailingLines.isEmpty())
|
||||
assertTrue(
|
||||
controller.state.value.trailingLines
|
||||
.isEmpty(),
|
||||
)
|
||||
|
||||
controller.pushTrailingLines(listOf("Outcome: success", "Version: 0.20.4 → 0.20.5"))
|
||||
|
||||
@@ -216,7 +219,10 @@ class ActionProgressControllerTest {
|
||||
val controller = controller()
|
||||
controller.open()
|
||||
controller.pushTrailingLines(emptyList())
|
||||
assertTrue(controller.state.value.trailingLines.isEmpty())
|
||||
assertTrue(
|
||||
controller.state.value.trailingLines
|
||||
.isEmpty(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -204,7 +204,9 @@ class CronJobsViewModelTest {
|
||||
vm.saveEditor()
|
||||
settle()
|
||||
|
||||
val toast = vm.uiState.value.editorState.toastMessage.orEmpty()
|
||||
val toast =
|
||||
vm.uiState.value.editorState.toastMessage
|
||||
.orEmpty()
|
||||
assertTrue(toast, toast.contains("invalid time '25:00'"))
|
||||
assertFalse(vm.uiState.value.editorState.isSaving)
|
||||
}
|
||||
@@ -394,7 +396,11 @@ class CronJobsViewModelTest {
|
||||
|
||||
coVerify { mockApi.deleteCronJob("j5") }
|
||||
assertTrue(vm.uiState.value.editorState.isOpen)
|
||||
assertTrue(vm.uiState.value.editorState.toastMessage.orEmpty().contains("Failed to save"))
|
||||
assertTrue(
|
||||
vm.uiState.value.editorState.toastMessage
|
||||
.orEmpty()
|
||||
.contains("Failed to save"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -549,7 +555,9 @@ class CronJobsViewModelTest {
|
||||
vm.loadCronJobs()
|
||||
settle()
|
||||
|
||||
val job = vm.uiState.value.jobs.first()
|
||||
val job =
|
||||
vm.uiState.value.jobs
|
||||
.first()
|
||||
assertNotNull(job.last_fire_error)
|
||||
assertEquals("gateway unreachable", job.last_fire_error?.detail)
|
||||
assertEquals("2026-08-18T09:00:00", job.last_fire_error?.at)
|
||||
|
||||
@@ -222,7 +222,12 @@ class KanbanViewModelTest {
|
||||
coEvery { mockApi.updateKanbanTask(any(), any()) } returns Response.success(Unit)
|
||||
vm.moveTask(KanbanTask(id = "t1", title = "Task 1", status = "todo"), KanbanTaskAction.READY)
|
||||
settle()
|
||||
assertEquals("ready", vm.uiState.value.tasks.first { it.id == "t1" }.status)
|
||||
assertEquals(
|
||||
"ready",
|
||||
vm.uiState.value.tasks
|
||||
.first { it.id == "t1" }
|
||||
.status,
|
||||
)
|
||||
coVerify { mockApi.updateKanbanTask("t1", mapOf("status" to "ready")) }
|
||||
}
|
||||
|
||||
@@ -234,8 +239,16 @@ class KanbanViewModelTest {
|
||||
coEvery { mockApi.updateKanbanTask(any(), any()) } returns Response.error(409, "".toResponseBody())
|
||||
vm.moveTask(KanbanTask(id = "t1", title = "Task 1", status = "todo"), KanbanTaskAction.READY)
|
||||
settle()
|
||||
assertEquals("todo", vm.uiState.value.tasks.first { it.id == "t1" }.status)
|
||||
assertTrue(vm.uiState.value.toastMessage?.contains("Move failed") == true)
|
||||
assertEquals(
|
||||
"todo",
|
||||
vm.uiState.value.tasks
|
||||
.first { it.id == "t1" }
|
||||
.status,
|
||||
)
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage
|
||||
?.contains("Move failed") == true,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -81,7 +81,9 @@ class MemoryViewModelTest {
|
||||
|
||||
@Test
|
||||
fun `load also fetches learning graph for self-improvement section`() {
|
||||
val graph = com.m57.hermescontrol.data.model.LearningGraphResponse(nodes = emptyList())
|
||||
val graph =
|
||||
com.m57.hermescontrol.data.model
|
||||
.LearningGraphResponse(nodes = emptyList())
|
||||
coEvery { mockApi.getLearningGraph() } returns Response.success(graph)
|
||||
val vm = MemoryViewModel()
|
||||
vm.load()
|
||||
@@ -100,7 +102,11 @@ class MemoryViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertNull(vm.uiState.value.memory)
|
||||
assertTrue(vm.uiState.value.errorMessage.orEmpty().isNotBlank())
|
||||
assertTrue(
|
||||
vm.uiState.value.errorMessage
|
||||
.orEmpty()
|
||||
.isNotBlank(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -127,7 +133,11 @@ class MemoryViewModelTest {
|
||||
vm.resetMemory("memory")
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage.orEmpty().contains("Failed to reset memory"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage
|
||||
.orEmpty()
|
||||
.contains("Failed to reset memory"),
|
||||
)
|
||||
assertNull(vm.uiState.value.resetting)
|
||||
}
|
||||
}
|
||||
@@ -97,9 +97,21 @@ class PairingViewModelTest {
|
||||
assertFalse(state.isLoading)
|
||||
assertNull(state.errorMessage)
|
||||
assertEquals(1, state.pairing?.pending?.size)
|
||||
assertEquals("bob", state.pairing?.pending?.first()?.userName)
|
||||
assertEquals(
|
||||
"bob",
|
||||
state.pairing
|
||||
?.pending
|
||||
?.first()
|
||||
?.userName,
|
||||
)
|
||||
assertEquals(1, state.pairing?.approved?.size)
|
||||
assertEquals("alice", state.pairing?.approved?.first()?.userName)
|
||||
assertEquals(
|
||||
"alice",
|
||||
state.pairing
|
||||
?.approved
|
||||
?.first()
|
||||
?.userName,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -148,7 +160,10 @@ class PairingViewModelTest {
|
||||
assertEquals("discord", requestSlot.captured.platform)
|
||||
assertEquals("u2", requestSlot.captured.userId)
|
||||
coVerify(exactly = 1) { mockApi.getPairing() }
|
||||
assertTrue(vm.uiState.value.toastMessage?.contains("u2") == true)
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage
|
||||
?.contains("u2") == true,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+17
-3
@@ -229,7 +229,11 @@ class MemoryProviderDetailViewModelTest {
|
||||
vm.saveConfig()
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage.orEmpty().contains("Failed to save"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage
|
||||
.orEmpty()
|
||||
.contains("Failed to save"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -242,7 +246,13 @@ class MemoryProviderDetailViewModelTest {
|
||||
val state = vm.uiState.value
|
||||
assertEquals("Setup completed", state.toastMessage)
|
||||
assertTrue(state.setupResult?.ok == true)
|
||||
assertEquals("installed", state.setupResult?.results?.first()?.status)
|
||||
assertEquals(
|
||||
"installed",
|
||||
state.setupResult
|
||||
?.results
|
||||
?.first()
|
||||
?.status,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -253,7 +263,11 @@ class MemoryProviderDetailViewModelTest {
|
||||
vm.runSetup()
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage.orEmpty().contains("Setup failed"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage
|
||||
.orEmpty()
|
||||
.contains("Setup failed"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -136,7 +136,10 @@ class ProfilesViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
coVerify { mockApi.renameProfile("work", RenameProfileRequest("play")) }
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("renamed"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("renamed"),
|
||||
)
|
||||
// reload happened
|
||||
coVerify { mockApi.getProfiles() }
|
||||
}
|
||||
@@ -162,7 +165,10 @@ class ProfilesViewModelTest {
|
||||
vm.renameProfile("work", "play")
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Failed to rename"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Failed to rename"),
|
||||
)
|
||||
assertFalse(vm.uiState.value.isLoading)
|
||||
}
|
||||
|
||||
@@ -175,7 +181,10 @@ class ProfilesViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
coVerify { mockApi.deleteProfile("work") }
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("deleted"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("deleted"),
|
||||
)
|
||||
coVerify { mockApi.getProfiles() }
|
||||
}
|
||||
|
||||
@@ -187,7 +196,10 @@ class ProfilesViewModelTest {
|
||||
vm.deleteProfile("work")
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Failed to delete"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Failed to delete"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -200,7 +212,10 @@ class ProfilesViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
coVerify { mockApi.describeProfileAuto("work", ProfileDescribeAutoRequest(overwrite = true)) }
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Auto-described"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Auto-described"),
|
||||
)
|
||||
assertFalse(vm.uiState.value.isAutoDescribing)
|
||||
coVerify { mockApi.getProfiles() }
|
||||
}
|
||||
@@ -214,7 +229,10 @@ class ProfilesViewModelTest {
|
||||
vm.autoDescribeProfile("work")
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("no aux client configured"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("no aux client configured"),
|
||||
)
|
||||
assertFalse(vm.uiState.value.isAutoDescribing)
|
||||
}
|
||||
|
||||
@@ -241,7 +259,10 @@ class ProfilesViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertNull(vm.uiState.value.setupCommand)
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Failed to fetch setup command"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Failed to fetch setup command"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -265,7 +286,11 @@ class ProfilesViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertEquals(1, vm.uiState.value.modelProviders.size)
|
||||
assertEquals("gpt-4o", vm.uiState.value.modelProviders[0].models!![0])
|
||||
assertEquals(
|
||||
"gpt-4o",
|
||||
vm.uiState.value.modelProviders[0]
|
||||
.models!![0],
|
||||
)
|
||||
assertEquals(listOf(PinnedModel("openai", "gpt-4")), vm.uiState.value.modelPickerPinned)
|
||||
assertFalse(vm.uiState.value.isLoadingBuilderData)
|
||||
}
|
||||
@@ -278,7 +303,10 @@ class ProfilesViewModelTest {
|
||||
vm.loadModelOptions()
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Failed to load models"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Failed to load models"),
|
||||
)
|
||||
assertNull(vm.uiState.value.errorMessage)
|
||||
assertFalse(vm.uiState.value.isLoadingBuilderData)
|
||||
}
|
||||
@@ -292,7 +320,10 @@ class ProfilesViewModelTest {
|
||||
assertEquals(listOf(PinnedModel("openai", "gpt-4")), storedPinnedModels)
|
||||
|
||||
vm.togglePinModel("openai", "gpt-4")
|
||||
assertTrue(vm.uiState.value.modelPickerPinned.isEmpty())
|
||||
assertTrue(
|
||||
vm.uiState.value.modelPickerPinned
|
||||
.isEmpty(),
|
||||
)
|
||||
assertTrue(storedPinnedModels.isEmpty())
|
||||
}
|
||||
|
||||
@@ -305,7 +336,10 @@ class ProfilesViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
coVerify { ProfileSwitchCoordinator.switchProfile("work") }
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Switched to profile work"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Switched to profile work"),
|
||||
)
|
||||
coVerify { mockApi.getProfiles() }
|
||||
}
|
||||
|
||||
@@ -320,7 +354,10 @@ class ProfilesViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertNull(vm.uiState.value.activeProfileName)
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Failed to switch profile"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Failed to switch profile"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -339,7 +376,10 @@ class ProfilesViewModelTest {
|
||||
),
|
||||
)
|
||||
}
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("cloned successfully"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("cloned successfully"),
|
||||
)
|
||||
assertFalse(vm.uiState.value.isLoading)
|
||||
coVerify { mockApi.getProfiles() }
|
||||
}
|
||||
@@ -352,7 +392,10 @@ class ProfilesViewModelTest {
|
||||
vm.cloneProfile("default", "dev-copy")
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Failed to clone profile"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Failed to clone profile"),
|
||||
)
|
||||
assertFalse(vm.uiState.value.isLoading)
|
||||
}
|
||||
|
||||
@@ -378,12 +421,20 @@ class ProfilesViewModelTest {
|
||||
vm.hideProfile("secret-bot")
|
||||
assertEquals(listOf("secret-bot"), storedHiddenProfiles)
|
||||
assertTrue(vm.uiState.value.hasHiddenProfiles)
|
||||
assertEquals(listOf("default"), vm.uiState.value.displayProfiles.map { it.name })
|
||||
assertEquals(
|
||||
listOf("default"),
|
||||
vm.uiState.value.displayProfiles
|
||||
.map { it.name },
|
||||
)
|
||||
|
||||
// Toggle show hidden
|
||||
vm.toggleShowHidden()
|
||||
assertTrue(vm.uiState.value.showHidden)
|
||||
assertEquals(listOf("default", "secret-bot"), vm.uiState.value.displayProfiles.map { it.name })
|
||||
assertEquals(
|
||||
listOf("default", "secret-bot"),
|
||||
vm.uiState.value.displayProfiles
|
||||
.map { it.name },
|
||||
)
|
||||
|
||||
// Unhide
|
||||
vm.unhideProfile("secret-bot")
|
||||
|
||||
@@ -116,7 +116,11 @@ class SessionsViewModelTest {
|
||||
vm.loadSessions()
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertEquals(listOf("s-1", "s-2"), vm.uiState.value.sessions.map { it.id })
|
||||
assertEquals(
|
||||
listOf("s-1", "s-2"),
|
||||
vm.uiState.value.sessions
|
||||
.map { it.id },
|
||||
)
|
||||
assertEquals(2, vm.uiState.value.total)
|
||||
assertFalse(vm.uiState.value.hasMore)
|
||||
assertFalse(vm.uiState.value.isLoadingMore)
|
||||
@@ -206,7 +210,11 @@ class SessionsViewModelTest {
|
||||
vm.loadSessions()
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertEquals(listOf("old-pinned", "recent"), vm.uiState.value.sessions.map { it.id })
|
||||
assertEquals(
|
||||
listOf("old-pinned", "recent"),
|
||||
vm.uiState.value.sessions
|
||||
.map { it.id },
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -226,8 +234,17 @@ class SessionsViewModelTest {
|
||||
vm.togglePin("s-2")
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertEquals(listOf("s-2", "s-1"), vm.uiState.value.sessions.map { it.id })
|
||||
assertEquals(true, vm.uiState.value.sessions.first().pinned)
|
||||
assertEquals(
|
||||
listOf("s-2", "s-1"),
|
||||
vm.uiState.value.sessions
|
||||
.map { it.id },
|
||||
)
|
||||
assertEquals(
|
||||
true,
|
||||
vm.uiState.value.sessions
|
||||
.first()
|
||||
.pinned,
|
||||
)
|
||||
assertEquals("Session pinned", vm.uiState.value.toastMessage)
|
||||
}
|
||||
|
||||
@@ -249,9 +266,19 @@ class SessionsViewModelTest {
|
||||
vm.togglePin("s-2")
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertEquals(listOf("s-1", "s-2"), vm.uiState.value.sessions.map { it.id })
|
||||
assertFalse(vm.uiState.value.sessions[1].pinned ?: false)
|
||||
assertEquals(
|
||||
listOf("s-1", "s-2"),
|
||||
vm.uiState.value.sessions
|
||||
.map { it.id },
|
||||
)
|
||||
assertFalse(
|
||||
vm.uiState.value.sessions[1]
|
||||
.pinned ?: false,
|
||||
)
|
||||
assertNotNull(vm.uiState.value.toastMessage)
|
||||
assertTrue(vm.uiState.value.toastMessage!!.contains("Pin failed"))
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage!!
|
||||
.contains("Pin failed"),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,11 @@ class SkillsViewModelTest {
|
||||
vm.loadHubSources()
|
||||
settle()
|
||||
|
||||
assertEquals(true, vm.uiState.value.hubSourcesError?.contains("Failed to load hub sources"))
|
||||
assertEquals(
|
||||
true,
|
||||
vm.uiState.value.hubSourcesError
|
||||
?.contains("Failed to load hub sources"),
|
||||
)
|
||||
assertEquals(false, vm.uiState.value.isHubSourcesLoading)
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,15 @@ class ToolsetDetailViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
val state = vm.uiState.value
|
||||
assertEquals(true, state.config?.providers?.get(1)?.envVars?.first { it.key == "KEY_B" }?.isSet)
|
||||
assertEquals(
|
||||
true,
|
||||
state.config
|
||||
?.providers
|
||||
?.get(1)
|
||||
?.envVars
|
||||
?.first { it.key == "KEY_B" }
|
||||
?.isSet,
|
||||
)
|
||||
assertEquals("Saved KEY_B", state.toastMessage)
|
||||
assertNull(state.savingEnvKey)
|
||||
}
|
||||
@@ -196,7 +204,15 @@ class ToolsetDetailViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
val state = vm.uiState.value
|
||||
assertEquals(false, state.config?.providers?.get(1)?.envVars?.first { it.key == "KEY_B" }?.isSet)
|
||||
assertEquals(
|
||||
false,
|
||||
state.config
|
||||
?.providers
|
||||
?.get(1)
|
||||
?.envVars
|
||||
?.first { it.key == "KEY_B" }
|
||||
?.isSet,
|
||||
)
|
||||
assertFalse(state.revealedValues.containsKey("KEY_B"))
|
||||
assertEquals("Cleared KEY_B", state.toastMessage)
|
||||
assertNull(state.deletingEnvKey)
|
||||
@@ -213,7 +229,10 @@ class ToolsetDetailViewModelTest {
|
||||
assertEquals("sekret", vm.uiState.value.revealedValues["KEY_B"])
|
||||
|
||||
vm.hideEnvVar("KEY_B")
|
||||
assertFalse(vm.uiState.value.revealedValues.containsKey("KEY_B"))
|
||||
assertFalse(
|
||||
vm.uiState.value.revealedValues
|
||||
.containsKey("KEY_B"),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -316,7 +335,10 @@ class ToolsetDetailViewModelTest {
|
||||
testDispatcher.scheduler.advanceUntilIdle()
|
||||
|
||||
assertNull(vm.uiState.value.postSetup)
|
||||
assertTrue(vm.uiState.value.toastMessage?.contains("spawn rejected") == true)
|
||||
assertTrue(
|
||||
vm.uiState.value.toastMessage
|
||||
?.contains("spawn rejected") == true,
|
||||
)
|
||||
coVerify(exactly = 0) { mockApi.getActionStatus(any()) }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user