fix(chat): remove extra closing brace in ChatViewModel.kt

This commit is contained in:
Hy4ri committed 2026-06-20 12:04:42 +03:00
1 parent 890ca05d16
commit 58ee32cbd1
2 files changed
+41 -19

No files matched your search

@@ -74,7 +74,10 @@ data class ClarifyUi(
class ChatViewModel( class ChatViewModel(
application: Application, application: Application,
private val startCleanup: Boolean,
) : AndroidViewModel(application) { ) : AndroidViewModel(application) {
constructor(application: Application) : this(application, startCleanup = true)
// ── Internal state ─────────────────────────────────────────────────── // ── Internal state ───────────────────────────────────────────────────
private val _uiState = MutableStateFlow(ChatUiState()) private val _uiState = MutableStateFlow(ChatUiState())
@@ -102,13 +105,15 @@ class ChatViewModel(
state.copy(connectionStatus = connStatus) state.copy(connectionStatus = connStatus)
}.stateIn( }.stateIn(
viewModelScope, viewModelScope,
SharingStarted.WhileSubscribed(5_000), SharingStarted.Eagerly,
_uiState.value, _uiState.value,
) )
init { init {
connectWebSocket() connectWebSocket()
startPendingRequestCleanup() if (startCleanup) {
startPendingRequestCleanup()
}
} }
// ── Connection ─────────────────────────────────────────────────────── // ── Connection ───────────────────────────────────────────────────────
@@ -918,7 +923,6 @@ class ChatViewModel(
} }
} }
} }
}
} }
// ── Search ──────────────────────────────────────────────────────────── // ── Search ────────────────────────────────────────────────────────────
@@ -4,6 +4,7 @@ import android.app.Application
import com.m57.hermescontrol.data.local.AuthManager import com.m57.hermescontrol.data.local.AuthManager
import com.m57.hermescontrol.data.local.ChatMessageDao import com.m57.hermescontrol.data.local.ChatMessageDao
import com.m57.hermescontrol.data.local.HermesDatabase import com.m57.hermescontrol.data.local.HermesDatabase
import com.m57.hermescontrol.data.ws.ConnectionStatus
import com.m57.hermescontrol.data.ws.HermesWsClient import com.m57.hermescontrol.data.ws.HermesWsClient
import com.m57.hermescontrol.data.ws.JsonRpcError import com.m57.hermescontrol.data.ws.JsonRpcError
import com.m57.hermescontrol.data.ws.WsEvent import com.m57.hermescontrol.data.ws.WsEvent
@@ -18,6 +19,7 @@ import io.mockk.verify
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.advanceUntilIdle
@@ -37,6 +39,7 @@ import org.junit.Test
class ChatViewModelTest { class ChatViewModelTest {
private val testDispatcher = StandardTestDispatcher() private val testDispatcher = StandardTestDispatcher()
private val mockEventsFlow = MutableSharedFlow<WsEvent>(extraBufferCapacity = 64) private val mockEventsFlow = MutableSharedFlow<WsEvent>(extraBufferCapacity = 64)
private val mockConnectionStatus = MutableStateFlow(ConnectionStatus.DISCONNECTED)
private lateinit var app: Application private lateinit var app: Application
private val mockDao: ChatMessageDao = mockk(relaxed = true) private val mockDao: ChatMessageDao = mockk(relaxed = true)
private val mockDb: HermesDatabase = mockk(relaxed = true) private val mockDb: HermesDatabase = mockk(relaxed = true)
@@ -56,8 +59,11 @@ class ChatViewModelTest {
app = mockk(relaxed = true) app = mockk(relaxed = true)
mockConnectionStatus.value = ConnectionStatus.DISCONNECTED
every { AuthManager.getToken() } returns "test-token" every { AuthManager.getToken() } returns "test-token"
every { HermesWsClient.events } returns mockEventsFlow every { HermesWsClient.events } returns mockEventsFlow
every { HermesWsClient.connectionStatus } returns mockConnectionStatus
every { HermesWsClient.connect() } returns Unit every { HermesWsClient.connect() } returns Unit
every { HermesWsClient.disconnect() } returns Unit every { HermesWsClient.disconnect() } returns Unit
every { mockDb.chatMessageDao() } returns mockDao every { mockDb.chatMessageDao() } returns mockDao
@@ -97,7 +103,7 @@ class ChatViewModelTest {
@Test @Test
fun testInitialStateAndConnection() = fun testInitialStateAndConnection() =
runTest { runTest {
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
verify { HermesWsClient.connect() } verify { HermesWsClient.connect() }
@@ -108,9 +114,10 @@ class ChatViewModelTest {
@Test @Test
fun testGatewayReady_createsSessionIfNoneExists() = fun testGatewayReady_createsSessionIfNoneExists() =
runTest { runTest {
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
mockConnectionStatus.value = ConnectionStatus.CONNECTED
mockEventsFlow.emit(WsEvent.GatewayReady(null)) mockEventsFlow.emit(WsEvent.GatewayReady(null))
advanceUntilIdle() advanceUntilIdle()
@@ -136,7 +143,7 @@ class ChatViewModelTest {
createReqId createReqId
} }
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
// Trigger GatewayReady -> triggers createNewSession // Trigger GatewayReady -> triggers createNewSession
@@ -166,7 +173,7 @@ class ChatViewModelTest {
listReqId listReqId
} }
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
mockEventsFlow.emit(WsEvent.GatewayReady(null)) mockEventsFlow.emit(WsEvent.GatewayReady(null))
@@ -200,13 +207,23 @@ class ChatViewModelTest {
@Test @Test
fun testMessageStreamingFlow() = fun testMessageStreamingFlow() =
runTest { runTest {
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
// Set active session ID first // Trigger GatewayReady -> triggers createSession -> feed result to set active session to session-123
var createReqId = ""
every { HermesWsClient.send(WsMethods.SESSION_CREATE, any(), any()) } answers {
createReqId = "create-req-stream"
val onSent = arg<((String) -> Unit)?>(2)
onSent?.invoke(createReqId)
createReqId
}
mockEventsFlow.emit(WsEvent.GatewayReady(null)) mockEventsFlow.emit(WsEvent.GatewayReady(null))
advanceUntilIdle() advanceUntilIdle()
mockEventsFlow.emit(WsEvent.RpcResult(createReqId, mapOf("session_id" to "session-123")))
advanceUntilIdle()
// Stream Start // Stream Start
mockEventsFlow.emit(WsEvent.MessageStart("session-123")) mockEventsFlow.emit(WsEvent.MessageStart("session-123"))
advanceUntilIdle() advanceUntilIdle()
@@ -239,8 +256,8 @@ class ChatViewModelTest {
assertFalse(state.isThinking) assertFalse(state.isThinking)
assertNotNull(state.streamingMessage) assertNotNull(state.streamingMessage)
assertEquals("Hello", state.streamingMessage?.content) assertEquals("Hello", state.streamingMessage?.content)
// Streaming message is not in the main messages list yet // Streaming message is not in the main messages list yet, only "Session created" exists
assertEquals(0, state.messages.size) assertEquals(1, state.messages.size)
// Token 2 // Token 2
mockEventsFlow.emit(WsEvent.MessageToken(" world", "session-123")) mockEventsFlow.emit(WsEvent.MessageToken(" world", "session-123"))
@@ -248,7 +265,7 @@ class ChatViewModelTest {
state = viewModel.uiState.value state = viewModel.uiState.value
assertNotNull(state.streamingMessage) assertNotNull(state.streamingMessage)
assertEquals("Hello world", state.streamingMessage?.content) assertEquals("Hello world", state.streamingMessage?.content)
assertEquals(0, state.messages.size) assertEquals(1, state.messages.size)
// Complete // Complete
mockEventsFlow.emit(WsEvent.MessageComplete("Hello world!", "session-123")) mockEventsFlow.emit(WsEvent.MessageComplete("Hello world!", "session-123"))
@@ -258,9 +275,10 @@ class ChatViewModelTest {
assertNull(state.streamingMessage) assertNull(state.streamingMessage)
assertFalse(state.isThinking) assertFalse(state.isThinking)
assertEquals("", state.thinkingText) assertEquals("", state.thinkingText)
assertEquals(1, state.messages.size) assertEquals(2, state.messages.size)
assertEquals("Hello world!", state.messages[0].content) assertEquals("Session created", state.messages[0].content)
assertFalse(state.messages[0].isStreaming) assertEquals("Hello world!", state.messages[1].content)
assertFalse(state.messages[1].isStreaming)
} }
@Test @Test
@@ -274,7 +292,7 @@ class ChatViewModelTest {
createReqId createReqId
} }
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
// Set session ID // Set session ID
@@ -308,7 +326,7 @@ class ChatViewModelTest {
@Test @Test
fun testSendMessage() = fun testSendMessage() =
runTest { runTest {
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
// Trigger GatewayReady -> triggers createSession -> feed result to set active session // Trigger GatewayReady -> triggers createSession -> feed result to set active session
@@ -343,7 +361,7 @@ class ChatViewModelTest {
@Test @Test
fun testSwitchSession() = fun testSwitchSession() =
runTest { runTest {
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
viewModel.switchSession("session-456") viewModel.switchSession("session-456")
@@ -375,7 +393,7 @@ class ChatViewModelTest {
createReqId createReqId
} }
val viewModel = ChatViewModel(app) val viewModel = ChatViewModel(app, startCleanup = false)
advanceUntilIdle() advanceUntilIdle()
mockEventsFlow.emit(WsEvent.GatewayReady(null)) mockEventsFlow.emit(WsEvent.GatewayReady(null))