damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

ReplyTests.swift (18986B)


      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 testMentionIsntReply() throws {
     22         let evid = NoteId(hex: "4090a9017a2beac3f17795d1aafb80d9f2b9eda97e4738501082ed5c927be014")!
     23         let content = "this is #[0] a mention"
     24         let tags = [evid.tag]
     25         let ev = NostrEvent(content: content, keypair: test_keypair, tags: tags)!
     26         let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
     27         let event_refs = interpret_event_refs(blocks: blocks, tags: ev.tags)
     28 
     29         XCTAssertEqual(event_refs.count, 1)
     30         
     31         let ref = event_refs[0]
     32         
     33         XCTAssertNil(ref.is_reply)
     34         XCTAssertNil(ref.is_thread_id)
     35         XCTAssertNil(ref.is_direct_reply)
     36         XCTAssertEqual(ref.is_mention, .some(.init(note_id: evid)))
     37     }
     38     
     39     func testAtAtEnd() {
     40         let content = "what @"
     41         let blocks = parse_post_blocks(content: content)
     42         
     43         XCTAssertEqual(blocks.count, 1)
     44         XCTAssertEqual(blocks[0].asText, "what @")
     45     }
     46     
     47     func testHashtagsInQuote() {
     48         let content = "This is my \"#awesome post\""
     49         let blocks = parse_post_blocks(content: content)
     50         
     51         XCTAssertEqual(blocks.count, 3)
     52         XCTAssertEqual(blocks[0].asText, "This is my \"")
     53         XCTAssertEqual(blocks[1].asHashtag, "awesome")
     54         XCTAssertEqual(blocks[2].asText, " post\"")
     55     }
     56     
     57     func testHashtagAtStartWorks() {
     58         let content = "#hashtag"
     59         let blocks = parse_post_blocks(content: content)
     60         XCTAssertEqual(blocks.count, 1)
     61         XCTAssertEqual(blocks[0].asHashtag, "hashtag")
     62     }
     63     
     64     func testGroupOfHashtags() {
     65         let content = "#hashtag#what#nope"
     66         let blocks = parse_post_blocks(content: content)
     67         XCTAssertEqual(blocks.count, 3)
     68         XCTAssertEqual(blocks[0].asHashtag, "hashtag")
     69         XCTAssertEqual(blocks[1].asHashtag, "what")
     70         XCTAssertEqual(blocks[2].asHashtag, "nope")
     71     }
     72     
     73     func testRootReplyWithMention() throws {
     74         let content = "this is #[1] a mention"
     75         let thread_id = NoteId(hex: "c75e5cbafbefd5de2275f831c2a2386ea05ec5e5a78a5ccf60d467582db48945")!
     76         let mentioned_id = NoteId(hex: "5a534797e8cd3b9f4c1cf63e20e48bd0e8bd7f8c4d6353fbd576df000f6f54d3")!
     77         let tags = [thread_id.tag, mentioned_id.tag]
     78         let ev = NostrEvent(content: content, keypair: test_keypair, tags: tags)!
     79         let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
     80         let event_refs = interpret_event_refs(blocks: blocks, tags: ev.tags)
     81 
     82         XCTAssertEqual(event_refs.count, 2)
     83         XCTAssertNotNil(event_refs[0].is_reply)
     84         XCTAssertNotNil(event_refs[0].is_thread_id)
     85         XCTAssertNotNil(event_refs[0].is_reply)
     86         XCTAssertNotNil(event_refs[0].is_direct_reply)
     87         XCTAssertEqual(event_refs[0].is_reply, .some(NoteRef(note_id: thread_id)))
     88         XCTAssertEqual(event_refs[0].is_thread_id, .some(NoteRef(note_id: thread_id)))
     89         XCTAssertNotNil(event_refs[1].is_mention)
     90         XCTAssertEqual(event_refs[1].is_mention, .some(NoteRef(note_id: mentioned_id)))
     91     }
     92     
     93     func testEmptyMention() throws {
     94         let content = "this is some & content"
     95         let ev = NostrEvent(content: content, keypair: test_keypair, tags: [])!
     96         let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
     97         let post_blocks = parse_post_blocks(content: content)
     98         let post_tags = make_post_tags(post_blocks: post_blocks, tags: [])
     99         let event_refs = interpret_event_refs(blocks: blocks, tags: ev.tags)
    100 
    101         XCTAssertEqual(event_refs.count, 0)
    102         XCTAssertEqual(post_tags.blocks.count, 1)
    103         XCTAssertEqual(post_tags.tags.count, 0)
    104         XCTAssertEqual(post_blocks.count, 1)
    105     }
    106 
    107     func testManyMentions() throws {
    108         let content = "#[10]"
    109         let tags: [[String]] = [[],[],[],[],[],[],[],[],[],[],["p", "3e999f94e2cb34ef44a64b351141ac4e51b5121b2d31aed4a6c84602a1144692"]]
    110         let ev = NostrEvent(content: content, keypair: test_keypair, tags: tags)!
    111         let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
    112         let mentions = blocks.filter { $0.asMention != nil }
    113         XCTAssertEqual(mentions.count, 1)
    114     }
    115 
    116     func testNewlineMentions() throws {
    117         let bech32_pk = "npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s"
    118         let pk = bech32_pubkey_decode(bech32_pk)!
    119 
    120         let profile = Profile(name: "jb55")
    121         let post = user_tag_attr_string(profile: profile, pubkey: pk)
    122         post.append(.init(string: "\n"))
    123         post.append(user_tag_attr_string(profile: profile, pubkey: pk))
    124         post.append(.init(string: "\n"))
    125 
    126         let post_note = build_post(state: test_damus_state, post: post, action: .posting(.none), uploadedMedias: [], references: [.pubkey(pk)])
    127 
    128         let expected_render = "nostr:\(pk.npub)\nnostr:\(pk.npub)"
    129         XCTAssertEqual(post_note.content, expected_render)
    130 
    131         let blocks = parse_note_content(content: .content(post_note.content,nil)).blocks
    132         let rendered = blocks.map { $0.asString }.joined(separator: "")
    133 
    134         XCTAssertEqual(rendered, expected_render)
    135 
    136         XCTAssertEqual(blocks.count, 3)
    137         XCTAssertEqual(blocks[0].asMention, Mention<MentionRef>.any(.pubkey(pk)))
    138         XCTAssertEqual(blocks[1].asText, "\n")
    139         XCTAssertEqual(blocks[2].asMention, Mention<MentionRef>.any(.pubkey(pk)))
    140     }
    141     
    142     func testThreadedReply() throws {
    143         let content = "this is some content"
    144         let thread_id = NoteId(hex: "da256fb52146dc565c6c6b9ef906117c665864dc02b14a7b853eca244729c2f2")!
    145         let reply_id = NoteId(hex: "80093e9bdb495728f54cda2bad4aed096877189552b3d41264e73b9a9595be22")!
    146         let tags = [thread_id.tag, reply_id.tag]
    147         let ev = NostrEvent(content: content, keypair: test_keypair, tags: tags)!
    148         let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
    149         let event_refs = interpret_event_refs(blocks: blocks, tags: ev.tags)
    150 
    151         XCTAssertEqual(event_refs.count, 2)
    152         let r1 = event_refs[0]
    153         let r2 = event_refs[1]
    154         
    155         XCTAssertEqual(r1.is_thread_id, .some(.note_id(thread_id)))
    156         XCTAssertEqual(r2.is_reply, .some(.note_id(reply_id)))
    157         XCTAssertEqual(r2.is_direct_reply, .some(.note_id(reply_id)))
    158         XCTAssertNil(r1.is_direct_reply)
    159     }
    160     
    161     func testRootReply() throws {
    162         let content = "this is a reply"
    163         let thread_id = NoteId(hex: "53f60f5114c06f069ffe9da2bc033e533d09cae44d37a8462154a663771a4ce6")!
    164         let tags = [thread_id.tag]
    165         let ev = NostrEvent(content: content, keypair: test_keypair, tags: tags)!
    166         let blocks = parse_note_content(content: .content(ev.content,nil)).blocks
    167         let event_refs = interpret_event_refs(blocks: blocks, tags: ev.tags)
    168 
    169         XCTAssertEqual(event_refs.count, 1)
    170         let r = event_refs[0]
    171         
    172         XCTAssertEqual(r.is_direct_reply, .some(.note_id(thread_id)))
    173         XCTAssertEqual(r.is_reply, .some(.note_id(thread_id)))
    174         XCTAssertEqual(r.is_thread_id, .some(.note_id(thread_id)))
    175         XCTAssertNil(r.is_mention)
    176     }
    177 
    178     func testAdjacentComposedMention() throws {
    179         let content = "cc@jb55"
    180 
    181         let profile = Profile(name: "jb55")
    182         let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey)
    183         let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(2...6))
    184         let new_post = appended.post
    185 
    186         try new_post.testAttributes(conditions: [
    187             { let link = $0[.link] as? String; XCTAssertNil(link) },
    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, "cc @jb55 ")
    193     }
    194 
    195     func testAdjacentEmojiComposedMention() throws {
    196         let content = "😎@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(2...6))
    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, "😎 @jb55 ")
    210     }
    211 
    212     func testComposedMentionNewline() throws {
    213         let content = """
    214         
    215         @jb55
    216         """
    217 
    218         let profile = Profile(name: "jb55")
    219         let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey)
    220         let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(1...5))
    221         let new_post = appended.post
    222 
    223         try new_post.testAttributes(conditions: [
    224             { let link = $0[.link] as? String; XCTAssertNil(link) },
    225             { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") },
    226             { let link = $0[.link] as? String; XCTAssertNil(link) },
    227         ])
    228 
    229         XCTAssertEqual(new_post.string, "\n@jb55 ")
    230     }
    231 
    232     func testComposedMention() throws {
    233         let content = "@jb55"
    234 
    235         let profile = Profile(name: "jb55")
    236         let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey)
    237         let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(0...4))
    238         let new_post = appended.post
    239 
    240         try new_post.testAttributes(conditions: [
    241             { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") },
    242             { let link = $0[.link] as? String; XCTAssertNil(link) },
    243         ])
    244 
    245         XCTAssertEqual(new_post.string, "@jb55 ")
    246     }
    247 
    248     func testAdjacentSpaceComposedMention() throws {
    249         let content = "cc @jb55"
    250 
    251         let profile = Profile(name: "jb55")
    252         let tag = user_tag_attr_string(profile: profile, pubkey: test_pubkey)
    253         let appended = append_user_tag(tag: tag, post: .init(string: content), word_range: .init(3...7))
    254         let new_post = appended.post
    255 
    256         try new_post.testAttributes(conditions: [
    257             { let link = $0[.link] as? String; XCTAssertNil(link) },
    258             { let link = $0[.link] as! String; XCTAssertEqual(link, "damus:nostr:\(test_pubkey.npub)") },
    259             { let link = $0[.link] as? String; XCTAssertNil(link) }
    260         ])
    261 
    262         XCTAssertEqual(new_post.string, "cc @jb55 ")
    263     }
    264 
    265     func testNoReply() throws {
    266         let content = "this is a #[0] reply"
    267         let ev = NostrEvent(content: content, keypair: test_keypair, tags: [])!
    268         let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
    269         let event_refs = interpret_event_refs(blocks: blocks, tags:ev.tags)
    270 
    271         XCTAssertEqual(event_refs.count, 0)
    272     }
    273     
    274     func testParseMention() throws {
    275         let note_id = NoteId(hex: "53f60f5114c06f069ffe9da2bc033e533d09cae44d37a8462154a663771a4ce6")!
    276         let tags = [note_id.tag]
    277         let ev = NostrEvent(content: "this is #[0] a mention", keypair: test_keypair, tags: tags)!
    278         let parsed = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
    279 
    280         XCTAssertNotNil(parsed)
    281         XCTAssertEqual(parsed.count, 3)
    282         XCTAssertEqual(parsed[0].asText, "this is ")
    283         XCTAssertNotNil(parsed[1].asMention)
    284         XCTAssertEqual(parsed[2].asText, " a mention")
    285     }
    286     
    287     func testEmptyPostReference() throws {
    288         let parsed = parse_post_blocks(content: "")
    289         XCTAssertEqual(parsed.count, 0)
    290     }
    291     
    292     func testBech32MentionAtStart() throws {
    293         let pk = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")!
    294         let content = "@\(pk.npub) hello there"
    295         let blocks = parse_post_blocks(content: content)
    296         
    297         XCTAssertEqual(blocks.count, 2)
    298         XCTAssertEqual(blocks[0].asMention, .any(.pubkey(pk)))
    299         XCTAssertEqual(blocks[1].asText, " hello there")
    300 
    301     }
    302     
    303     func testBech32MentionAtEnd() throws {
    304         let pk = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")!
    305         let content = "this is a @\(pk.npub)"
    306         let blocks = parse_post_blocks(content: content)
    307         
    308         XCTAssertEqual(blocks.count, 2)
    309         XCTAssertEqual(blocks[1].asMention, .any(.pubkey(pk)))
    310         XCTAssertEqual(blocks[0].asText, "this is a ")
    311     }
    312     
    313     func testNpubMention() throws {
    314         let evid = NoteId(hex: "71ba3e5ddaf48103be294aa370e470fb60b6c8bca3fb01706eecd00054c2f588")!
    315         let pk = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")!
    316         let content = "this is a @\(pk.npub) mention"
    317         let blocks = parse_post_blocks(content: content)
    318         let post = NostrPost(content: content, references: [.event(evid)])
    319         let ev = post_to_event(post: post, keypair: test_keypair_full)!
    320 
    321         XCTAssertEqual(ev.tags.count, 2)
    322         XCTAssertEqual(blocks.count, 3)
    323         XCTAssertEqual(blocks[1].asMention, .any(.pubkey(pk)))
    324         XCTAssertEqual(ev.content, "this is a nostr:npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s mention")
    325     }
    326     
    327     func testNsecMention() throws {
    328         let evid = NoteId(hex: "71ba3e5ddaf48103be294aa370e470fb60b6c8bca3fb01706eecd00054c2f588")!
    329         let pk = Pubkey(hex: "ccf95d668650178defca5ac503693b6668eb77895f610178ff8ed9fe5cf9482e")!
    330         let nsec = "nsec1jmzdz7d0ldqctdxwm5fzue277ttng2pk28n2u8wntc2r4a0w96ssnyukg7"
    331         let content = "this is a @\(nsec) mention"
    332         let blocks = parse_post_blocks(content: content)
    333         let post = NostrPost(content: content, references: [.event(evid)])
    334         let ev = post_to_event(post: post, keypair: test_keypair_full)!
    335 
    336         XCTAssertEqual(ev.tags.count, 2)
    337         XCTAssertEqual(blocks.count, 3)
    338         XCTAssertEqual(blocks[1].asMention, .any(.pubkey(pk)))
    339         XCTAssertEqual(ev.content, "this is a nostr:npub1enu46e5x2qtcmm72ttzsx6fmve5wkauftassz78l3mvluh8efqhqejf3v4 mention")
    340     }
    341     
    342     func testReplyMentions() throws {
    343         let pubkey  = Pubkey(hex: "30c6d1dc7f7c156794fa15055e651b758a61b99f50fcf759de59386050bf6ae2")!
    344         let thread_id = NoteId(hex: "a250fc93570c3e87f9c9b08d6b3ef7b8e05d346df8a52c69e30ffecdb178fb9e")!
    345         let reply_id = NoteId(hex: "9a180a10f16dac9566543ad1fc29616aab272b0cf123ab5d58843e16f4ef03a3")!
    346 
    347         let refs: [RefId]  = [
    348             .event(thread_id),
    349             .event(reply_id),
    350             .pubkey(pubkey)
    351         ]
    352 
    353         let post = NostrPost(content: "this is a (@\(pubkey.npub)) mention", references: refs)
    354         let ev = post_to_event(post: post, keypair: test_keypair_full)!
    355         
    356         XCTAssertEqual(ev.content, "this is a (nostr:\(pubkey.npub)) mention")
    357         XCTAssertEqual(ev.tags[2][1].string(), pubkey.description)
    358     }
    359     
    360     func testInvalidPostReference() throws {
    361         let pk = "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e24"
    362         let content = "this is a @\(pk) mention"
    363         let parsed = parse_post_blocks(content: content)
    364         XCTAssertEqual(parsed.count, 1)
    365         guard case .text(let txt) = parsed[0] else {
    366             XCTAssert(false)
    367             return
    368         }
    369         XCTAssertEqual(txt, content)
    370     }
    371     
    372     func testInvalidPostReferenceEmptyAt() throws {
    373         let content = "this is a @ mention"
    374         let parsed = parse_post_blocks(content: content)
    375         XCTAssertEqual(parsed.count, 1)
    376         guard case .text(let txt) = parsed[0] else {
    377             XCTAssert(false)
    378             return
    379         }
    380         XCTAssertEqual(txt, content)
    381     }
    382     
    383     func testInvalidUriReference() throws {
    384         let id = "6fec2ee6cfff779fe8560976b3d9df782b74577f0caefa7a77c0ed4c3749b5de"
    385         let content = "this is a nostr:z:\(id) event mention"
    386         let parsed = parse_post_blocks(content: content)
    387         
    388         XCTAssertNotNil(parsed)
    389         XCTAssertEqual(parsed.count, 1)
    390         
    391         guard case .text(let txt) = parsed[0] else {
    392             XCTAssertTrue(false)
    393             return
    394         }
    395         
    396         XCTAssertEqual(txt, content)
    397     }
    398     
    399     func testParsePostUriPubkeyReference() throws {
    400         let id = Pubkey(hex: "6fec2ee6cfff779fe8560976b3d9df782b74577f0caefa7a77c0ed4c3749b5de")!
    401         let parsed = parse_post_blocks(content: "this is a nostr:\(id.npub) event mention")
    402 
    403         XCTAssertNotNil(parsed)
    404         XCTAssertEqual(parsed.count, 3)
    405         XCTAssertEqual(parsed[0].asText, "this is a ")
    406         XCTAssertEqual(parsed[1].asMention, .any(.pubkey(id)))
    407         XCTAssertEqual(parsed[2].asText, " event mention")
    408         
    409         guard case .text(let t1) = parsed[0] else {
    410             XCTAssertTrue(false)
    411             return
    412         }
    413         XCTAssertEqual(t1, "this is a ")
    414         
    415         guard case .text(let t2) = parsed[2] else {
    416             XCTAssertTrue(false)
    417             return
    418         }
    419         XCTAssertEqual(t2, " event mention")
    420     }
    421     
    422     func testParsePostUriReference() throws {
    423         let id = NoteId(hex: "6fec2ee6cfff779fe8560976b3d9df782b74577f0caefa7a77c0ed4c3749b5de")!
    424         let parsed = parse_post_blocks(content: "this is a nostr:\(id.bech32) event mention")
    425 
    426         XCTAssertNotNil(parsed)
    427         XCTAssertEqual(parsed.count, 3)
    428         XCTAssertEqual(parsed[0].asText, "this is a ")
    429         XCTAssertEqual(parsed[1].asMention, .any(.note(id)))
    430         XCTAssertEqual(parsed[2].asText, " event mention")
    431 
    432         guard case .text(let t1) = parsed[0] else {
    433             XCTAssertTrue(false)
    434             return
    435         }
    436         XCTAssertEqual(t1, "this is a ")
    437         
    438         guard case .text(let t2) = parsed[2] else {
    439             XCTAssertTrue(false)
    440             return
    441         }
    442         XCTAssertEqual(t2, " event mention")
    443     }
    444     
    445     func testParseInvalidMention() throws {
    446         let parsed = parse_note_content(content: .content("this is #[0] a mention",nil)).blocks
    447 
    448         XCTAssertNotNil(parsed)
    449         XCTAssertEqual(parsed.count, 3)
    450         XCTAssertEqual(parsed[0].asText, "this is ")
    451         XCTAssertEqual(parsed[1].asText, "#[0]")
    452         XCTAssertEqual(parsed[2].asText, " a mention")
    453     }
    454 
    455 }