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// πŸ€– Sidebar snippet (previewText) must mirror the web (previewText in
5// shell.js): a non-image attachment reads as a file chip, not "πŸ“· Photo".
6final class PreviewTextTests: XCTestCase {
7 private func att(_ name: String, _ type: String?) -> Attachment {
8 Attachment(id: "b", name: name, type: type)
9 }
10
11 func testTextTakesPrecedence() {
12 var p = MessagePayload()
13 p.text = " hello world \n"
14 p.attachments = [att("photo.jpg", "image/jpeg")]
15 XCTAssertEqual(previewText(kind: "dm", payload: p), "hello world")
16 }
17
18 func testSingleImage() {
19 var p = MessagePayload()
20 p.attachments = [att("photo.jpg", "image/jpeg")]
21 XCTAssertEqual(previewText(kind: "dm", payload: p), "πŸ“· Photo")
22 }
23
24 func testMultipleImages() {
25 var p = MessagePayload()
26 p.attachments = [att("a.jpg", "image/jpeg"), att("b.png", "image/png")]
27 XCTAssertEqual(previewText(kind: "dm", payload: p), "πŸ“· 2 photos")
28 }
29
30 func testSingleFileIsNotAPhoto() {
31 var p = MessagePayload()
32 p.attachments = [att("report.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")]
33 XCTAssertEqual(previewText(kind: "dm", payload: p), "πŸ“Ž report.docx")
34 }
35
36 func testMultipleFiles() {
37 var p = MessagePayload()
38 p.attachments = [att("a.docx", "application/msword"), att("b.pdf", "application/pdf")]
39 XCTAssertEqual(previewText(kind: "dm", payload: p), "πŸ“Ž 2 files")
40 }
41
42 func testMixedImageAndFileFallsToFiles() {
43 var p = MessagePayload()
44 p.attachments = [att("a.jpg", "image/jpeg"), att("b.pdf", "application/pdf")]
45 XCTAssertEqual(previewText(kind: "dm", payload: p), "πŸ“Ž 2 files")
46 }
47
48 // A typeless attachment (legacy) isn't an image β†’ file chip with its name.
49 func testUntypedAttachment() {
50 var p = MessagePayload()
51 p.attachments = [att("mystery.bin", nil)]
52 XCTAssertEqual(previewText(kind: "dm", payload: p), "πŸ“Ž mystery.bin")
53 }
54
55 func testGroupPrefix() {
56 var p = MessagePayload()
57 p.name = "Ada"
58 p.attachments = [att("report.docx", "application/msword")]
59 XCTAssertEqual(previewText(kind: "group", payload: p), "Ada: πŸ“Ž report.docx")
60 }
61
62 // A reaction has no text of its own β€” the row used to go blank (in a group,
63 // a bare "Ada: "). It says what happened instead, quoting the snippet the
64 // reacting client stamped inside the ciphertext. Web twin: reactionLine in
65 // format.js + the reaction branch in shell.js previewText.
66 private func reaction(_ name: String, _ emoji: String, on: Bool, target: String?) -> MessagePayload {
67 var p = MessagePayload()
68 p.type = "reaction"
69 p.name = name
70 p.emoji = emoji
71 p.on = on
72 p.targetSid = 12345
73 p.targetText = target
74 return p
75 }
76
77 func testReactionQuotesItsTarget() {
78 let p = reaction("Ada", "πŸ‘", on: true, target: "buy milk")
79 XCTAssertEqual(previewText(kind: "dm", payload: p), "Ada reacted πŸ‘ to β€œbuy milk”")
80 }
81
82 // It names the actor itself, so the group prefix never doubles up.
83 func testReactionTakesNoGroupPrefix() {
84 let p = reaction("Ada", "πŸ‘", on: true, target: "buy milk")
85 XCTAssertEqual(previewText(kind: "group", payload: p), "Ada reacted πŸ‘ to β€œbuy milk”")
86 }
87
88 func testMyOwnReactionSaysYou() {
89 let p = reaction("Ada", "πŸŽ‰", on: true, target: "shipped it")
90 XCTAssertEqual(previewText(kind: "group", payload: p, mine: true), "You reacted πŸŽ‰ to β€œshipped it”")
91 }
92
93 // An un-react speaks too: on reload this event is all the sidebar has, so
94 // silence would mean a different row after a refresh than the one shown live.
95 func testUnReactSpeaks() {
96 let p = reaction("Bob", "❀️", on: false, target: "shipped it πŸŽ‰")
97 XCTAssertEqual(previewText(kind: "dm", payload: p), "Bob removed ❀️ from β€œshipped it πŸŽ‰β€")
98 }
99
100 // Reactions from clients that predate targetText (and every reaction
101 // already in a database) carry no snippet β€” the bare form still reads.
102 func testReactionWithoutASnippet() {
103 XCTAssertEqual(previewText(kind: "dm", payload: reaction("Ada", "πŸ‘", on: true, target: nil)),
104 "Ada reacted πŸ‘")
105 XCTAssertEqual(previewText(kind: "dm", payload: reaction("Ada", "πŸ‘", on: false, target: nil)),
106 "Ada removed πŸ‘")
107 }
108
109 func testReactionQuoteIsClamped() {
110 let p = reaction("Ada", "πŸ‘", on: true, target: String(repeating: "a", count: 200))
111 let line = previewText(kind: "dm", payload: p)
112 XCTAssertTrue(line.hasPrefix("Ada reacted πŸ‘ to β€œ"))
113 XCTAssertTrue(line.hasSuffix("…”"))
114 XCTAssertLessThan(line.count, 70, "the sidebar line stays one line's worth")
115 }
116
117 // The caller resolves the actor by uid (ThreadStore's displayLabels β€” my
118 // name for them, #577), and that wins over the payload's snapshot. Without
119 // it, a reaction from a device that stamped no screen name β€” common on real
120 // data β€” reads "Someone reacted πŸ‘".
121 func testActorResolvesByUidOverThePayloadName() {
122 var p = reaction("", "πŸ˜‚", on: true, target: nil)
123 p.name = ""
124 XCTAssertEqual(previewText(kind: "group", payload: p, actor: "Paul"), "Paul reacted πŸ˜‚")
125 }
126
127 func testResolvedActorBeatsAStalePayloadName() {
128 let p = reaction("Old Name", "πŸ‘", on: true, target: "buy milk")
129 XCTAssertEqual(previewText(kind: "dm", payload: p, actor: "My Name For Them"),
130 "My Name For Them reacted πŸ‘ to β€œbuy milk”")
131 }
132
133 // Nobody to resolve (they left the space, and the payload named no one).
134 func testReactionWithoutANameSaysSomeone() {
135 var p = reaction("", "πŸ‘", on: true, target: "buy milk")
136 p.name = nil
137 XCTAssertEqual(previewText(kind: "dm", payload: p), "Someone reacted πŸ‘ to β€œbuy milk”")
138 }
139
140 // The group prefix takes the same by-uid resolution as the reaction line:
141 // my name for them, so the row survives a rename and never renders a bare
142 // ": hello" for a sender whose device stamped no screen name. Web twin:
143 // previewText in shell.js resolves `who` once and uses it for both.
144 func testGroupPrefixUsesTheResolvedActor() {
145 var p = MessagePayload()
146 p.name = "Old Name"
147 p.text = "hello"
148 XCTAssertEqual(previewText(kind: "group", payload: p, actor: "My Name For Them"),
149 "My Name For Them: hello")
150 }
151
152 func testGroupPrefixFallsBackToThePayloadName() {
153 var p = MessagePayload()
154 p.name = "Ada"
155 p.text = "hello"
156 XCTAssertEqual(previewText(kind: "group", payload: p), "Ada: hello")
157 }
158
159 // Nothing to resolve and nothing stamped: no stray colon.
160 func testGroupPrefixIsSkippedWithNoNameAtAll() {
161 var p = MessagePayload()
162 p.text = "hello"
163 XCTAssertEqual(previewText(kind: "group", payload: p), "hello")
164 }
165
166 // An action line names its own actor β€” prefixing it doubles the name up.
167 func testActionLineTakesNoGroupPrefix() {
168 var p = MessagePayload()
169 p.name = "Ada"
170 p.text = "waves"
171 p.action = true
172 XCTAssertEqual(previewText(kind: "group", payload: p, actor: "Ada"), "waves")
173 }
174}
175