git.iko.soy/opencode-android
on 73868e9 help sign in
opencode-android/app/src/test/java/soy/iko/opencode/ui/search/GlobalSearchViewModelTest.kt
120 lines 4.4 kB history raw
1@file:OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
3package soy.iko.opencode.ui.search
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
12import org.junit.After
13import org.junit.Assert.assertEquals
14import org.junit.Assert.assertFalse
15import org.junit.Assert.assertTrue
16import org.junit.Before
17import org.junit.Test
18import soy.iko.opencode.data.model.MessageWithParts
19import soy.iko.opencode.data.model.ServerProfile
20import soy.iko.opencode.data.model.Session
21import soy.iko.opencode.data.model.TextPart
22import soy.iko.opencode.data.model.UserMessage
23import soy.iko.opencode.ui.testing.FakeAppContainer
24import soy.iko.opencode.ui.testing.FakeEventStreamClient
25import soy.iko.opencode.ui.testing.FakeOpencodeApiClient
26import soy.iko.opencode.ui.testing.FakeOpencodeConnection
27import soy.iko.opencode.ui.testing.FakeSessionRepository
29class GlobalSearchViewModelTest {
30 private val testDispatcher = StandardTestDispatcher()
31 private val testScope = TestScope(testDispatcher)
33 @Before
34 fun setUp() { Dispatchers.setMain(testDispatcher) }
36 @After
37 fun tearDown() { Dispatchers.resetMain() }
39 private fun makeContainer(
40 sessions: List<Session>,
41 messages: List<MessageWithParts>,
42 ): FakeAppContainer {
43 val api = FakeOpencodeApiClient().apply { this.messages = messages }
44 val events = FakeEventStreamClient()
45 val repo = FakeSessionRepository(api, events).apply { this.sessions = sessions }
46 val container = FakeAppContainer()
47 container.setActiveConnection(
48 FakeOpencodeConnection(api, events, repo, ServerProfile(id = "s1", label = "T", baseUrl = "http://localhost")),
49 )
50 return container
51 }
53 private fun textMessage(id: String, text: String) = MessageWithParts(
54 info = UserMessage(id = id, sessionID = "s1"),
55 parts = listOf(TextPart(id = "p-$id", text = text)),
56 )
58 @Test
59 fun query_matchesMessageText_andReturnsSnippet() = testScope.runTest {
60 val container = makeContainer(
61 sessions = listOf(Session(id = "s1", title = "Chat 1")),
62 messages = listOf(textMessage("m1", "the quick brown fox jumps")),
63 )
64 val vm = GlobalSearchViewModel(container)
66 vm.setQuery("brown")
67 testScheduler.advanceUntilIdle()
69 val state = vm.state.value
70 assertTrue(state.hasSearched)
71 assertEquals(1, state.results.size)
72 assertEquals("s1", state.results[0].session.id)
73 assertTrue("snippet should contain the match", state.results[0].snippet.contains("brown"))
74 }
76 @Test
77 fun query_belowMinLength_doesNotSearch() = testScope.runTest {
78 val container = makeContainer(
79 sessions = listOf(Session(id = "s1", title = "Chat 1")),
80 messages = listOf(textMessage("m1", "hello world")),
81 )
82 val vm = GlobalSearchViewModel(container)
84 vm.setQuery("h")
85 testScheduler.advanceUntilIdle()
87 assertFalse(vm.state.value.hasSearched)
88 assertTrue(vm.state.value.results.isEmpty())
89 }
91 @Test
92 fun query_noMatch_setsHasSearchedWithEmptyResults() = testScope.runTest {
93 val container = makeContainer(
94 sessions = listOf(Session(id = "s1", title = "Chat 1")),
95 messages = listOf(textMessage("m1", "hello world")),
96 )
97 val vm = GlobalSearchViewModel(container)
99 vm.setQuery("zzzznomatch")
100 testScheduler.advanceUntilIdle()
102 assertTrue(vm.state.value.hasSearched)
103 assertTrue(vm.state.value.results.isEmpty())
104 }
106 @Test
107 fun query_matchesSessionTitle_evenWithoutMessageMatch() = testScope.runTest {
108 val container = makeContainer(
109 sessions = listOf(Session(id = "s1", title = "Refactor auth")),
110 messages = listOf(textMessage("m1", "unrelated content")),
111 )
112 val vm = GlobalSearchViewModel(container)
114 vm.setQuery("auth")
115 testScheduler.advanceUntilIdle()
117 assertEquals(1, vm.state.value.results.size)
118 assertEquals("s1", vm.state.value.results[0].session.id)
119 }