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