ReplyTests.swift (14641B)
1 // 2 // ReplyTests.swift 3 // damusTests 4 // 5 // Created by William Casarin on 2022-05-08. 6 // 7 8 import XCTest 9 @testable import damus 10 11 class ReplyTests: XCTestCase { 12 13 override func setUpWithError() throws { 14 // Put setup code here. This method is called before the invocation of each test method in the class. 15 } 16 17 override func tearDownWithError() throws { 18 // Put teardown code here. This method is called after the invocation of each test method in the class. 19 } 20 21 func testAtAtEnd() { 22 let content = "what @" 23 let blocks = parse_post_blocks(content: content) 24 25 XCTAssertEqual(blocks.count, 1) 26 XCTAssertEqual(blocks[0].asText, "what @") 27 } 28 29 func testHashtagsInQuote() { 30 let content = "This is my \"#awesome post\"" 31 let blocks = parse_post_blocks(content: content) 32 33 XCTAssertEqual(blocks.count, 3) 34 XCTAssertEqual(blocks[0].asText, "This is my \"") 35 XCTAssertEqual(blocks[1].asHashtag, "awesome") 36 XCTAssertEqual(blocks[2].asText, " post\"") 37 } 38 39 func testHashtagAtStartWorks() { 40 let content = "#hashtag" 41 let blocks = parse_post_blocks(content: content) 42 XCTAssertEqual(blocks.count, 1) 43 XCTAssertEqual(blocks[0].asHashtag, "hashtag") 44 } 45 46 func testGroupOfHashtags() { 47 let content = "#hashtag#what#nope" 48 let blocks = parse_post_blocks(content: content) 49 XCTAssertEqual(blocks.count, 3) 50 XCTAssertEqual(blocks[0].asHashtag, "hashtag") 51 XCTAssertEqual(blocks[1].asHashtag, "what") 52 XCTAssertEqual(blocks[2].asHashtag, "nope") 53 } 54 55 func testEmptyMention() throws { 56 let content = "this is some & content" 57 let ev = NostrEvent(content: content, keypair: test_keypair, tags: [])! 58 let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks 59 let post_blocks = parse_post_blocks(content: content) 60 let post = NostrPost(content: content, kind: NostrKind.text, tags: []) 61 let post_tags = post.make_post_tags(post_blocks: post_blocks, tags: []) 62 let tr = interpret_event_refs(tags: ev.tags) 63 64 XCTAssertNil(tr) 65 XCTAssertEqual(post_tags.blocks.count, 1) 66 XCTAssertEqual(post_tags.tags.count, 0) 67 XCTAssertEqual(post_blocks.count, 1) 68 } 69 70 func testNewlineMentions() throws { 71 let bech32_pk = "npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s" 72 let pk = bech32_pubkey_decode(bech32_pk)! 73 74 let profile = Profile(name: "jb55") 75 let post = user_tag_attr_string(profile: profile, pubkey: pk) 76 post.append(.init(string: "\n")) 77 post.append(user_tag_attr_string(profile: profile, pubkey: pk)) 78 post.append(.init(string: "\n")) 79 80 let post_note = build_post(state: test_damus_state, post: post, action: .posting(.none), uploadedMedias: [], pubkeys: [pk]) 81 82 let expected_render = "nostr:\(pk.npub)\nnostr:\(pk.npub)" 83 XCTAssertEqual(post_note.content, expected_render) 84 85 let blocks = parse_note_content(content: .content(post_note.content,nil)).blocks 86 let rendered = blocks.map { $0.asString }.joined(separator: "") 87 88 XCTAssertEqual(rendered, expected_render) 89 90 XCTAssertEqual(blocks.count, 3) 91 XCTAssertEqual(blocks[0].asMention, Mention<MentionRef>.any(.pubkey(pk))) 92 XCTAssertEqual(blocks[1].asText, "\n") 93 XCTAssertEqual(blocks[2].asMention, Mention<MentionRef>.any(.pubkey(pk))) 94 } 95 96 func testThreadedReply() throws { 97 let content = "this is some content" 98 let thread_id = NoteId(hex: "da256fb52146dc565c6c6b9ef906117c665864dc02b14a7b853eca244729c2f2")! 99 let reply_id = NoteId(hex: "80093e9bdb495728f54cda2bad4aed096877189552b3d41264e73b9a9595be22")! 100 let tags = [thread_id.tag, reply_id.tag] 101 let ev = NostrEvent(content: content, keypair: test_keypair, tags: tags)! 102 let tr = interpret_event_refs(tags: ev.tags) 103 XCTAssertNotNil(tr) 104 guard let tr else { return } 105 106 XCTAssertEqual(tr.root.note_id, thread_id) 107 XCTAssertEqual(tr.reply.note_id, reply_id) 108 } 109 110 func testRootReply() throws { 111 let content = "this is a reply" 112 let thread_id = NoteId(hex: "53f60f5114c06f069ffe9da2bc033e533d09cae44d37a8462154a663771a4ce6")! 113 let tags = [thread_id.tag] 114 let ev = NostrEvent(content: content, keypair: test_keypair, tags: tags)! 115 let tr = interpret_event_refs(tags: ev.tags) 116 117 XCTAssertNotNil(tr) 118 guard let tr else { return } 119 120 XCTAssertEqual(tr.root.note_id, thread_id) 121 XCTAssertEqual(tr.reply.note_id, thread_id) 122 XCTAssertNil(tr.mention) 123 } 124 125 func testAdjacentComposedMention() throws { 126 let content = "cc@jb55" 127 128 let profile = Profile(name: "jb55") 129 let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey) 130 let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(2...6)) 131 let new_post = appended.post 132 133 try new_post.testAttributes(conditions: [ 134 { let link = $0[.link] as? String; XCTAssertNil(link) }, 135 { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") }, 136 { let link = $0[.link] as? String; XCTAssertNil(link) } 137 ]) 138 139 XCTAssertEqual(new_post.string, "cc @jb55 ") 140 } 141 142 func testAdjacentEmojiComposedMention() throws { 143 let content = "😎@jb55" 144 145 let profile = Profile(name: "jb55") 146 let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey) 147 let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(2...6)) 148 let new_post = appended.post 149 150 try new_post.testAttributes(conditions: [ 151 { let link = $0[.link] as? String; XCTAssertNil(link) }, 152 { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") }, 153 { let link = $0[.link] as? String; XCTAssertNil(link) } 154 ]) 155 156 XCTAssertEqual(new_post.string, "😎 @jb55 ") 157 } 158 159 func testComposedMentionNewline() throws { 160 let content = """ 161 162 @jb55 163 """ 164 165 let profile = Profile(name: "jb55") 166 let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey) 167 let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(1...5)) 168 let new_post = appended.post 169 170 try new_post.testAttributes(conditions: [ 171 { let link = $0[.link] as? String; XCTAssertNil(link) }, 172 { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") }, 173 { let link = $0[.link] as? String; XCTAssertNil(link) }, 174 ]) 175 176 XCTAssertEqual(new_post.string, "\n@jb55 ") 177 } 178 179 func testComposedMention() throws { 180 let content = "@jb55" 181 182 let profile = Profile(name: "jb55") 183 let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey) 184 let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(0...4)) 185 let new_post = appended.post 186 187 try new_post.testAttributes(conditions: [ 188 { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") }, 189 { let link = $0[.link] as? String; XCTAssertNil(link) }, 190 ]) 191 192 XCTAssertEqual(new_post.string, "@jb55 ") 193 } 194 195 func testAdjacentSpaceComposedMention() throws { 196 let content = "cc @jb55" 197 198 let profile = Profile(name: "jb55") 199 let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey) 200 let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(3...7)) 201 let new_post = appended.post 202 203 try new_post.testAttributes(conditions: [ 204 { let link = $0[.link] as? String; XCTAssertNil(link) }, 205 { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") }, 206 { let link = $0[.link] as? String; XCTAssertNil(link) } 207 ]) 208 209 XCTAssertEqual(new_post.string, "cc @jb55 ") 210 } 211 212 func testEmptyPostReference() throws { 213 let parsed = parse_post_blocks(content: "") 214 XCTAssertEqual(parsed.count, 0) 215 } 216 217 func testBech32MentionAtStart() throws { 218 let pk = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")! 219 let content = "@\(pk.npub) hello there" 220 let blocks = parse_post_blocks(content: content) 221 222 XCTAssertEqual(blocks.count, 2) 223 XCTAssertEqual(blocks[0].asMention, .any(.pubkey(pk))) 224 XCTAssertEqual(blocks[1].asText, " hello there") 225 226 } 227 228 func testBech32MentionAtEnd() throws { 229 let pk = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")! 230 let content = "this is a @\(pk.npub)" 231 let blocks = parse_post_blocks(content: content) 232 233 XCTAssertEqual(blocks.count, 2) 234 XCTAssertEqual(blocks[1].asMention, .any(.pubkey(pk))) 235 XCTAssertEqual(blocks[0].asText, "this is a ") 236 } 237 238 func testNpubMention() throws { 239 let evid = NoteId(hex: "71ba3e5ddaf48103be294aa370e470fb60b6c8bca3fb01706eecd00054c2f588")! 240 let pk = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")! 241 let content = "this is a @\(pk.npub) mention" 242 let blocks = parse_post_blocks(content: content) 243 let post = NostrPost(content: content, tags: [["e", evid.hex()]]) 244 let ev = post.to_event(keypair: test_keypair_full)! 245 246 XCTAssertEqual(ev.tags.count, 2) 247 XCTAssertEqual(blocks.count, 3) 248 XCTAssertEqual(blocks[1].asMention, .any(.pubkey(pk))) 249 XCTAssertEqual(ev.content, "this is a nostr:npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s mention") 250 } 251 252 func testNsecMention() throws { 253 let evid = NoteId(hex: "71ba3e5ddaf48103be294aa370e470fb60b6c8bca3fb01706eecd00054c2f588")! 254 let pk = Pubkey(hex: "ccf95d668650178defca5ac503693b6668eb77895f610178ff8ed9fe5cf9482e")! 255 let nsec = "nsec1jmzdz7d0ldqctdxwm5fzue277ttng2pk28n2u8wntc2r4a0w96ssnyukg7" 256 let content = "this is a @\(nsec) mention" 257 let blocks = parse_post_blocks(content: content) 258 let post = NostrPost(content: content, tags: [["e", evid.hex()]]) 259 let ev = post.to_event(keypair: test_keypair_full)! 260 261 XCTAssertEqual(ev.tags.count, 2) 262 XCTAssertEqual(blocks.count, 3) 263 XCTAssertEqual(blocks[1].asMention, .any(.pubkey(pk))) 264 XCTAssertEqual(ev.content, "this is a nostr:npub1enu46e5x2qtcmm72ttzsx6fmve5wkauftassz78l3mvluh8efqhqejf3v4 mention") 265 } 266 267 func testReplyMentions() throws { 268 let pubkey = Pubkey(hex: "30c6d1dc7f7c156794fa15055e651b758a61b99f50fcf759de59386050bf6ae2")! 269 let thread_id = NoteId(hex: "a250fc93570c3e87f9c9b08d6b3ef7b8e05d346df8a52c69e30ffecdb178fb9e")! 270 let reply_id = NoteId(hex: "9a180a10f16dac9566543ad1fc29616aab272b0cf123ab5d58843e16f4ef03a3")! 271 272 let tags = [ 273 ["e", thread_id.hex()], 274 ["e", reply_id.hex()], 275 ["p", pubkey.hex()] 276 ] 277 278 let post = NostrPost(content: "this is a (@\(pubkey.npub)) mention", tags: tags) 279 let ev = post.to_event(keypair: test_keypair_full)! 280 281 XCTAssertEqual(ev.content, "this is a (nostr:\(pubkey.npub)) mention") 282 XCTAssertEqual(ev.tags[2][1].string(), pubkey.description) 283 } 284 285 func testInvalidPostReference() throws { 286 let pk = "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e24" 287 let content = "this is a @\(pk) mention" 288 let parsed = parse_post_blocks(content: content) 289 XCTAssertEqual(parsed.count, 1) 290 guard case .text(let txt) = parsed[0] else { 291 XCTAssert(false) 292 return 293 } 294 XCTAssertEqual(txt, content) 295 } 296 297 func testInvalidPostReferenceEmptyAt() throws { 298 let content = "this is a @ mention" 299 let parsed = parse_post_blocks(content: content) 300 XCTAssertEqual(parsed.count, 1) 301 guard case .text(let txt) = parsed[0] else { 302 XCTAssert(false) 303 return 304 } 305 XCTAssertEqual(txt, content) 306 } 307 308 func testInvalidUriReference() throws { 309 let id = "6fec2ee6cfff779fe8560976b3d9df782b74577f0caefa7a77c0ed4c3749b5de" 310 let content = "this is a nostr:z:\(id) event mention" 311 let parsed = parse_post_blocks(content: content) 312 313 XCTAssertNotNil(parsed) 314 XCTAssertEqual(parsed.count, 1) 315 316 guard case .text(let txt) = parsed[0] else { 317 XCTAssertTrue(false) 318 return 319 } 320 321 XCTAssertEqual(txt, content) 322 } 323 324 func testParsePostUriPubkeyReference() throws { 325 let id = Pubkey(hex: "6fec2ee6cfff779fe8560976b3d9df782b74577f0caefa7a77c0ed4c3749b5de")! 326 let parsed = parse_post_blocks(content: "this is a nostr:\(id.npub) event mention") 327 328 XCTAssertNotNil(parsed) 329 XCTAssertEqual(parsed.count, 3) 330 XCTAssertEqual(parsed[0].asText, "this is a ") 331 XCTAssertEqual(parsed[1].asMention, .any(.pubkey(id))) 332 XCTAssertEqual(parsed[2].asText, " event mention") 333 334 guard case .text(let t1) = parsed[0] else { 335 XCTAssertTrue(false) 336 return 337 } 338 XCTAssertEqual(t1, "this is a ") 339 340 guard case .text(let t2) = parsed[2] else { 341 XCTAssertTrue(false) 342 return 343 } 344 XCTAssertEqual(t2, " event mention") 345 } 346 347 func testParsePostUriReference() throws { 348 let id = NoteId(hex: "6fec2ee6cfff779fe8560976b3d9df782b74577f0caefa7a77c0ed4c3749b5de")! 349 let parsed = parse_post_blocks(content: "this is a nostr:\(id.bech32) event mention") 350 351 XCTAssertNotNil(parsed) 352 XCTAssertEqual(parsed.count, 3) 353 XCTAssertEqual(parsed[0].asText, "this is a ") 354 XCTAssertEqual(parsed[1].asMention, .any(.note(id))) 355 XCTAssertEqual(parsed[2].asText, " event mention") 356 357 guard case .text(let t1) = parsed[0] else { 358 XCTAssertTrue(false) 359 return 360 } 361 XCTAssertEqual(t1, "this is a ") 362 363 guard case .text(let t2) = parsed[2] else { 364 XCTAssertTrue(false) 365 return 366 } 367 XCTAssertEqual(t2, " event mention") 368 } 369 370 }