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 stored-tombstone contract (#581/#582), pinned by the tombstone_delete
5// vector (canonical copy: test/event-vectors/chat.json — this fixture mirrors
6// it, like the other *-vector.json files). A history/catch-up row carrying
7// tombstone_of must evict that message exactly as the live "delete" frame
8// does; old rows without the field decode unchanged.
9final class TombstoneVectorTests: XCTestCase {
10 private struct Vector: Codable {
11 let name: String
12 let server_message: ServerMessage
13 let expected_fold_event: Fold
14 struct Fold: Codable {
15 let type: String
16 let msgId: Int64
17 }
18 }
19
20 private func loadVector() throws -> Vector {
21 let url = try XCTUnwrap(Bundle.module.url(forResource: "Fixtures/tombstone-vector", withExtension: "json"),
22 "tombstone-vector.json missing from test fixtures")
23 return try JSONDecoder().decode(Vector.self, from: Data(contentsOf: url))
24 }
25
26 func testTombstoneRowDecodes() throws {
27 let v = try loadVector()
28 XCTAssertEqual(v.expected_fold_event.type, "chat.delete")
29 let row = v.server_message
30 XCTAssertEqual(row.tombstone_of, v.expected_fold_event.msgId, "the tombstone names the id to drop")
31 XCTAssertEqual(row.blob, "", "tombstones carry no ciphertext")
32 XCTAssertGreaterThan(row.id, row.tombstone_of ?? 0,
33 "tombstone ids are fresh — above every client's forward watermark")
34 }
35
36 func testEvictionsMatchTheVector() throws {
37 let v = try loadVector()
38 // A page mixing an ordinary row with the tombstone: only the
39 // tombstone's target is evicted; plain rows are untouched.
40 let plain = ServerMessage(id: 12344, created_at: 1751899999, blob: "ciphertext", edited_at: nil, tombstone_of: nil)
41 let evict = ChatFeedModel.tombstoneEvictions([plain, v.server_message])
42 XCTAssertEqual(evict, [v.expected_fold_event.msgId])
43 }
44
45 func testLegacyRowsWithoutTheFieldDecode() throws {
46 // Pre-#581 servers (and non-tombstone rows) omit the field entirely.
47 let json = #"{"id": 7, "created_at": 1700000000, "blob": "abc"}"#
48 let row = try JSONDecoder().decode(ServerMessage.self, from: Data(json.utf8))
49 XCTAssertNil(row.tombstone_of)
50 XCTAssertTrue(ChatFeedModel.tombstoneEvictions([row]).isEmpty)
51 }
52}
53