eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1import XCTest
2@testable import LChatCore
3
4// πŸ€– The native half of the app-host catalogue contract (docs/native-apps.md):
5// AppManifest must decode exactly what appCatalogReport() (web/static/apps.js)
6// emits. The web side pins the report's shape in test/appcatalog.test.mjs;
7// this file pins the decode of those same shapes, so drift on either side
8// breaks a test. The literals here mirror that test's fixtures: a takeover
9// app with commands (vault-like) and a chatOnly companion.
10final class AppCatalogTests: XCTestCase {
11 func testDecodesReport() throws {
12 let report = """
13 [
14 {"name":"vault","title":"Vault","glyph":"πŸ”’","places":["chat"],
15 "listed":true,"quiet":false,"member":false,
16 "companion":false,"chatOnly":false,"chatReadOnly":false,
17 "defaultView":"split","defaultCommand":"",
18 "commands":[{"name":"vault","desc":"Save something","args":"<text>","local":false}]},
19 {"name":"habits","title":"Habit tracker","glyph":"βœ…","places":["you"],
20 "listed":false,"quiet":false,"member":true,
21 "companion":true,"chatOnly":true,"chatReadOnly":false,
22 "defaultView":"chat","defaultCommand":"habit",
23 "commands":[{"name":"habit","desc":"Log a habit","args":"","local":true}]}
24 ]
25 """.data(using: .utf8)!
26 let catalog = try XCTUnwrap(AppCatalog.decode(reportJSON: report))
27 XCTAssertEqual(catalog.count, 2)
28
29 let vault = catalog[0]
30 XCTAssertEqual(vault.name, "vault")
31 XCTAssertEqual(vault.title, "Vault")
32 XCTAssertEqual(vault.glyph, "πŸ”’")
33 XCTAssertEqual(vault.places, ["chat"])
34 XCTAssertTrue(vault.listed)
35 XCTAssertFalse(vault.member)
36 // No chatMessage β†’ takeover: render owns the whole surface.
37 XCTAssertFalse(vault.companion)
38 XCTAssertEqual(vault.commands,
39 [AppManifest.Command(name: "vault", desc: "Save something",
40 args: "<text>", local: false)])
41
42 let habits = catalog[1]
43 XCTAssertTrue(habits.member)
44 XCTAssertTrue(habits.companion)
45 XCTAssertTrue(habits.chatOnly)
46 XCTAssertEqual(habits.defaultView, "chat")
47 XCTAssertEqual(habits.defaultCommand, "habit")
48 }
49
50 // Undecodable input is "no report", never an empty app set β€” an empty
51 // catalogue would read as "this space has no apps" downstream. A malformed
52 // RECORD inside a valid report is dropped alone (per-record tolerance):
53 // one odd member-app manifest must not poison the whole catalogue.
54 func testUndecodableReportIsNil() {
55 XCTAssertNil(AppCatalog.decode(reportJSON: Data("not json".utf8)))
56 XCTAssertEqual(AppCatalog.decode(reportJSON: Data(#"[{"name":"x"}]"#.utf8)), [])
57 }
58
59 // The record round-trips through Codable losslessly β€” what the per-origin
60 // Keychain park depends on.
61 func testRoundTrip() throws {
62 let manifest = AppManifest(
63 name: "board", title: "Whiteboard", glyph: "πŸ–ŠοΈ", places: ["chat"],
64 listed: true, quiet: false, member: false,
65 companion: false, chatOnly: false, chatReadOnly: false,
66 defaultView: "split", defaultCommand: "",
67 commands: [.init(name: "board", desc: "Open the board", args: "", local: false)])
68 let data = try JSONEncoder().encode([manifest])
69 XCTAssertEqual(AppCatalog.decode(reportJSON: data), [manifest])
70 }
71}
72