1package soy.iko.opencode
3import soy.iko.opencode.data.model.BusEvent
4import soy.iko.opencode.data.model.FileContent
5import soy.iko.opencode.data.model.FileNode
6import soy.iko.opencode.data.model.PermissionReplied
7import soy.iko.opencode.data.model.PermissionUpdated
8import soy.iko.opencode.data.model.ProvidersResponse
9import soy.iko.opencode.data.model.defaultOption
10import soy.iko.opencode.data.model.toOptions
11import soy.iko.opencode.data.network.OpencodeJson
12import kotlinx.serialization.builtins.ListSerializer
13import kotlinx.serialization.builtins.serializer
14import org.junit.Assert.assertEquals
15import org.junit.Assert.assertNull
16import org.junit.Assert.assertTrue
21 private fun <T> decode(s: kotlinx.serialization.KSerializer<T>, json: String): T =
22 OpencodeJson.decodeFromString(s, json)
25 fun decodesPermissionUpdatedWithArrayPattern() {
27 { "type": "permission.updated", "properties": {
28 "id": "perm_1", "sessionID": "ses_1", "type": "bash",
29 "pattern": ["rm -rf *", "git push"], "title": "Run bash",
30 "metadata": { "cwd": "/tmp" }, "time": { "created": 123 } } }
32 val event = decode(BusEvent.serializer(), json) as PermissionUpdated
33 assertEquals("perm_1", event.properties.id)
34 assertEquals("bash", event.properties.type)
35 assertEquals("rm -rf *, git push", event.properties.patternText)
39 fun decodesPermissionUpdatedWithStringPattern() {
41 { "type": "permission.updated", "properties": {
42 "id": "perm_2", "sessionID": "ses_1", "type": "edit", "pattern": "src/Main.kt" } }
44 val event = decode(BusEvent.serializer(), json) as PermissionUpdated
45 assertEquals("src/Main.kt", event.properties.patternText)
49 fun decodesPermissionReplied() {
50 val json = """{"type":"permission.replied","properties":{"sessionID":"s","permissionID":"perm_1","response":"once"}}"""
51 val event = decode(BusEvent.serializer(), json) as PermissionReplied
52 assertEquals("perm_1", event.properties.permissionID)
53 assertEquals("once", event.properties.response)
57 fun decodesRichProvidersAndFlattens() {
58 // Mirrors the real (richer) /config/providers shape; unknown fields must be ignored.
62 { "id": "anthropic", "name": "Anthropic", "source": "env", "env": ["ANTHROPIC_API_KEY"],
65 "claude-sonnet": { "id": "claude-sonnet", "providerID": "anthropic", "name": "Claude Sonnet",
66 "capabilities": { "reasoning": true }, "cost": { "input": 3, "output": 15 },
67 "limit": { "context": 200000, "output": 8192 }, "status": "active" }
70 "default": { "anthropic": "claude-sonnet" }
73 val resp = decode(ProvidersResponse.serializer(), json)
74 val options = resp.toOptions()
75 assertEquals(1, options.size)
76 assertEquals("Claude Sonnet", options.single().modelLabel)
77 assertEquals("claude-sonnet", resp.defaultOption(options)?.modelID)
81 fun decodesFileContentAndDirectoryListing() {
82 val content = decode(FileContent.serializer(), """{"type":"text","content":"hello\nworld"}""")
83 assertEquals("hello\nworld", content.content)
84 assertTrue(!content.isBinary)
87 ListSerializer(FileNode.serializer()),
88 """[{"name":"src","path":"src","type":"directory"},{"name":"a.kt","path":"src/a.kt","type":"file"}]""",
90 assertEquals(2, nodes.size)
91 assertTrue(nodes[0].isDirectory)
92 assertTrue(!nodes[1].isDirectory)
96 fun decodesFindFilesAsStringArray() {
97 val paths = decode(ListSerializer(String.serializer()), """["src/a.kt","src/b.kt"]""")
98 assertEquals(listOf("src/a.kt", "src/b.kt"), paths)
102 fun binaryFileContentIsFlagged() {
103 val content = decode(FileContent.serializer(), """{"type":"binary","content":"AAAA","encoding":"base64","mimeType":"image/png"}""")
104 assertTrue(content.isBinary)
105 assertNull(content.diff)
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