mirror of
git://jb55.com/damus
synced 2024-10-01 17:30:44 +00:00
nip19: add bech32 TLV url parsing
Create shortened URLs for bech32 with TLV data strings. Additionally, upon clicking on an nevent URL the user is directed to the note. Lightning-url: LNURL1DP68GURN8GHJ7EM9W3SKCCNE9E3K7MF0D3H82UNVWQHKWUN9V4HXGCTHDC6RZVGR8SW3G Signed-off-by: kernelkind <kernelkind@gmail.com> Reviewed-by: William Casarin <jb55@jb55.com> Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
parent
af75eed83a
commit
d07ad67778
@ -492,21 +492,15 @@ struct ContentView: View {
|
||||
open_profile(pubkey: pubkey)
|
||||
|
||||
case .note(let noteId):
|
||||
guard let target = damus_state.events.lookup(noteId) else {
|
||||
return
|
||||
}
|
||||
|
||||
switch local.type {
|
||||
case .dm:
|
||||
selected_timeline = .dms
|
||||
damus_state.dms.set_active_dm(target.pubkey)
|
||||
navigationCoordinator.push(route: Route.DMChat(dms: damus_state.dms.active_model))
|
||||
case .like, .zap, .mention, .repost:
|
||||
open_event(ev: target)
|
||||
case .profile_zap:
|
||||
// Handled separately above.
|
||||
openEvent(noteId: noteId, notificationType: local.type)
|
||||
case .nevent(let nevent):
|
||||
openEvent(noteId: nevent.noteid, notificationType: local.type)
|
||||
case .nprofile(let nprofile):
|
||||
open_profile(pubkey: nprofile.author)
|
||||
case .nrelay(_):
|
||||
break
|
||||
case .naddr(let naddr):
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -725,6 +719,22 @@ struct ContentView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func openEvent(noteId: NoteId, notificationType: LocalNotificationType) {
|
||||
guard let target = damus_state.events.lookup(noteId) else {
|
||||
return
|
||||
}
|
||||
|
||||
switch notificationType {
|
||||
case .dm:
|
||||
selected_timeline = .dms
|
||||
damus_state.dms.set_active_dm(target.pubkey)
|
||||
navigationCoordinator.push(route: Route.DMChat(dms: damus_state.dms.active_model))
|
||||
case .like, .zap, .mention, .repost:
|
||||
open_event(ev: target)
|
||||
case .profile_zap:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
@ -1082,6 +1092,8 @@ func on_open_url(state: DamusState, url: URL, result: @escaping (OpenResult?) ->
|
||||
case .param, .quote:
|
||||
// doesn't really make sense here
|
||||
break
|
||||
case .naddr(let naddr):
|
||||
break // TODO: fix
|
||||
}
|
||||
case .filter(let filt):
|
||||
result(.filter(filt))
|
||||
|
@ -113,7 +113,7 @@ func is_already_following(contacts: NostrEvent, follow: FollowRef) -> Bool {
|
||||
case let (.pubkey(pk), .pubkey(follow_pk)):
|
||||
return pk == follow_pk
|
||||
case (.hashtag, .pubkey), (.pubkey, .hashtag),
|
||||
(.event, _), (.quote, _), (.param, _):
|
||||
(.event, _), (.quote, _), (.param, _), (.naddr, _):
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import Foundation
|
||||
enum MentionType: AsciiCharacter, TagKey {
|
||||
case p
|
||||
case e
|
||||
case a
|
||||
case r
|
||||
|
||||
var keychar: AsciiCharacter {
|
||||
self.rawValue
|
||||
@ -17,21 +19,26 @@ enum MentionType: AsciiCharacter, TagKey {
|
||||
}
|
||||
|
||||
enum MentionRef: TagKeys, TagConvertible, Equatable, Hashable {
|
||||
case pubkey(Pubkey) // TODO: handle nprofile
|
||||
case pubkey(Pubkey)
|
||||
case note(NoteId)
|
||||
case nevent(NEvent)
|
||||
case nprofile(NProfile)
|
||||
case nrelay(String)
|
||||
case naddr(NAddr)
|
||||
|
||||
var key: MentionType {
|
||||
switch self {
|
||||
case .pubkey: return .p
|
||||
case .note: return .e
|
||||
case .nevent: return .e
|
||||
case .nprofile: return .p
|
||||
case .nrelay: return .r
|
||||
case .naddr: return .a
|
||||
}
|
||||
}
|
||||
|
||||
var bech32: String {
|
||||
switch self {
|
||||
case .pubkey(let pubkey): return bech32_pubkey(pubkey)
|
||||
case .note(let noteId): return bech32_note_id(noteId)
|
||||
}
|
||||
return Bech32Object.encode(toBech32Object())
|
||||
}
|
||||
|
||||
static func from_bech32(str: String) -> MentionRef? {
|
||||
@ -46,6 +53,10 @@ enum MentionRef: TagKeys, TagConvertible, Equatable, Hashable {
|
||||
switch self {
|
||||
case .pubkey(let pubkey): return pubkey
|
||||
case .note: return nil
|
||||
case .nevent(let nevent): return nevent.author
|
||||
case .nprofile(let nprofile): return nprofile.author
|
||||
case .nrelay: return nil
|
||||
case .naddr: return nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +64,10 @@ enum MentionRef: TagKeys, TagConvertible, Equatable, Hashable {
|
||||
switch self {
|
||||
case .pubkey(let pubkey): return ["p", pubkey.hex()]
|
||||
case .note(let noteId): return ["e", noteId.hex()]
|
||||
case .nevent(let nevent): return ["e", nevent.noteid.hex()]
|
||||
case .nprofile(let nprofile): return ["p", nprofile.author.hex()]
|
||||
case .nrelay(let url): return ["r", url]
|
||||
case .naddr(let naddr): return ["a", naddr.kind.description + ":" + naddr.author.hex() + ":" + naddr.identifier.string()]
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,14 +79,45 @@ enum MentionRef: TagKeys, TagConvertible, Equatable, Hashable {
|
||||
guard let t0 = i.next(),
|
||||
let chr = t0.single_char,
|
||||
let mention_type = MentionType(rawValue: chr),
|
||||
let id = i.next()?.id()
|
||||
let element = i.next()
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch mention_type {
|
||||
case .p: return .pubkey(Pubkey(id))
|
||||
case .e: return .note(NoteId(id))
|
||||
case .p:
|
||||
guard let data = element.id() else { return nil }
|
||||
return .pubkey(Pubkey(data))
|
||||
case .e:
|
||||
guard let data = element.id() else { return nil }
|
||||
return .note(NoteId(data))
|
||||
case .a:
|
||||
let str = element.string()
|
||||
let data = str.split(separator: ":")
|
||||
if(data.count != 3) { return nil }
|
||||
|
||||
guard let pubkey = Pubkey(hex: String(data[1])) else { return nil }
|
||||
guard let kind = UInt32(data[0]) else { return nil }
|
||||
|
||||
return .naddr(NAddr(identifier: String(data[2]), author: pubkey, relays: [], kind: kind))
|
||||
case .r: return .nrelay(element.string())
|
||||
}
|
||||
}
|
||||
|
||||
func toBech32Object() -> Bech32Object {
|
||||
switch self {
|
||||
case .pubkey(let pk):
|
||||
return .npub(pk)
|
||||
case .note(let noteid):
|
||||
return .note(noteid)
|
||||
case .naddr(let naddr):
|
||||
return .naddr(naddr)
|
||||
case .nevent(let nevent):
|
||||
return .nevent(nevent)
|
||||
case .nprofile(let nprofile):
|
||||
return .nprofile(nprofile)
|
||||
case .nrelay(let url):
|
||||
return .nrelay(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,4 +297,3 @@ func post_to_event(post: NostrPost, keypair: FullKeypair) -> NostrEvent? {
|
||||
.joined(separator: "")
|
||||
return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: post.kind.rawValue, tags: post_tags.tags)
|
||||
}
|
||||
|
||||
|
@ -182,26 +182,31 @@ func attributed_string_attach_icon(_ astr: inout AttributedString, img: UIImage)
|
||||
astr.append(wrapped)
|
||||
}
|
||||
|
||||
func mention_str(_ m: Mention<MentionRef>, profiles: Profiles) -> CompatibleText {
|
||||
switch m.ref {
|
||||
case .pubkey(let pk):
|
||||
let npub = bech32_pubkey(pk)
|
||||
func getDisplayName(pk: Pubkey, profiles: Profiles) -> String {
|
||||
let profile_txn = profiles.lookup(id: pk)
|
||||
let profile = profile_txn?.unsafeUnownedValue
|
||||
let disp = Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 50)
|
||||
var attributedString = AttributedString(stringLiteral: "@\(disp)")
|
||||
attributedString.link = URL(string: "damus:nostr:\(npub)")
|
||||
attributedString.foregroundColor = DamusColors.purple
|
||||
return Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 50)
|
||||
}
|
||||
|
||||
return CompatibleText(attributed: attributedString)
|
||||
case .note(let note_id):
|
||||
let bevid = bech32_note_id(note_id)
|
||||
var attributedString = AttributedString(stringLiteral: "@\(abbrev_pubkey(bevid))")
|
||||
attributedString.link = URL(string: "damus:nostr:\(bevid)")
|
||||
attributedString.foregroundColor = DamusColors.purple
|
||||
func mention_str(_ m: Mention<MentionRef>, profiles: Profiles) -> CompatibleText {
|
||||
let bech32String = Bech32Object.encode(m.ref.toBech32Object())
|
||||
|
||||
return CompatibleText(attributed: attributedString)
|
||||
let attributedStringLiteral: String = {
|
||||
switch m.ref {
|
||||
case .pubkey(let pk): return getDisplayName(pk: pk, profiles: profiles)
|
||||
case .note: return "@\(abbrev_pubkey(bech32String))"
|
||||
case .nevent: return "@\(abbrev_pubkey(bech32String))"
|
||||
case .nprofile(let nprofile): return getDisplayName(pk: nprofile.author, profiles: profiles)
|
||||
case .nrelay(let url): return url
|
||||
case .naddr: return "@\(abbrev_pubkey(bech32String))"
|
||||
}
|
||||
}()
|
||||
|
||||
var attributedString = AttributedString(stringLiteral: attributedStringLiteral)
|
||||
attributedString.link = URL(string: "damus:nostr:\(bech32String)")
|
||||
attributedString.foregroundColor = DamusColors.purple
|
||||
|
||||
return CompatibleText(attributed: attributedString)
|
||||
}
|
||||
|
||||
// trim suffix whitespace and newlines
|
||||
|
@ -121,6 +121,7 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
|
||||
case quote(QuoteId)
|
||||
case hashtag(TagElem)
|
||||
case param(TagElem)
|
||||
case naddr(NAddr)
|
||||
|
||||
var key: RefKey {
|
||||
switch self {
|
||||
@ -129,11 +130,12 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
|
||||
case .quote: return .q
|
||||
case .hashtag: return .t
|
||||
case .param: return .d
|
||||
case .naddr: return .a
|
||||
}
|
||||
}
|
||||
|
||||
enum RefKey: AsciiCharacter, TagKey, CustomStringConvertible {
|
||||
case e, p, t, d, q
|
||||
case e, p, t, d, q, a
|
||||
|
||||
var keychar: AsciiCharacter {
|
||||
self.rawValue
|
||||
@ -155,6 +157,8 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
|
||||
case .quote(let quote): return quote.hex()
|
||||
case .hashtag(let string): return string.string()
|
||||
case .param(let string): return string.string()
|
||||
case .naddr(let naddr):
|
||||
return naddr.kind.description + ":" + naddr.author.hex() + ":" + naddr.identifier
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,6 +178,7 @@ enum RefId: TagConvertible, TagKeys, Equatable, Hashable {
|
||||
case .q: return t1.id().map({ .quote(QuoteId($0)) })
|
||||
case .t: return .hashtag(t1)
|
||||
case .d: return .param(t1)
|
||||
case .a: return .naddr(NAddr(identifier: "", author: Pubkey(Data()), relays: [], kind: 0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,47 +150,18 @@ fileprivate extension Block {
|
||||
self = .invoice(Invoice(description: description, amount: amount, string: invstr, expiry: b11.expiry, payment_hash: payment_hash, created_at: created_at))
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Block {
|
||||
/// Failable initializer for the C-backed type `mention_bech32_block_t`. This initializer will inspect the
|
||||
/// bech32 type code and build the appropriate enum type.
|
||||
init?(bech32 b: mention_bech32_block_t) {
|
||||
switch b.bech32.type {
|
||||
case NOSTR_BECH32_NOTE:
|
||||
let note = b.bech32.data.note;
|
||||
let note_id = NoteId(Data(bytes: note.event_id, count: 32))
|
||||
self = .mention(.any(.note(note_id)))
|
||||
case NOSTR_BECH32_NEVENT:
|
||||
let nevent = b.bech32.data.nevent;
|
||||
let note_id = NoteId(Data(bytes: nevent.event_id, count: 32))
|
||||
self = .mention(.any(.note(note_id)))
|
||||
case NOSTR_BECH32_NPUB:
|
||||
let npub = b.bech32.data.npub
|
||||
let pubkey = Pubkey(Data(bytes: npub.pubkey, count: 32))
|
||||
self = .mention(.any(.pubkey(pubkey)))
|
||||
case NOSTR_BECH32_NSEC:
|
||||
let nsec = b.bech32.data.nsec
|
||||
let privkey = Privkey(Data(bytes: nsec.nsec, count: 32))
|
||||
guard let pubkey = privkey_to_pubkey(privkey: privkey) else { return nil }
|
||||
self = .mention(.any(.pubkey(pubkey)))
|
||||
case NOSTR_BECH32_NPROFILE:
|
||||
let nprofile = b.bech32.data.nprofile
|
||||
let pubkey = Pubkey(Data(bytes: nprofile.pubkey, count: 32))
|
||||
self = .mention(.any(.pubkey(pubkey)))
|
||||
case NOSTR_BECH32_NRELAY:
|
||||
let nrelay = b.bech32.data.nrelay
|
||||
guard let relay_str = String(nrelay.relay) else {
|
||||
guard let decoded = decodeCBech32(b.bech32) else {
|
||||
return nil
|
||||
}
|
||||
self = .relay(relay_str)
|
||||
case NOSTR_BECH32_NADDR:
|
||||
// TODO: wtf do I do with this
|
||||
guard let naddr = String(b.str) else {
|
||||
return nil
|
||||
}
|
||||
self = .text("nostr:" + naddr)
|
||||
default:
|
||||
guard let ref = decoded.toMentionRef() else {
|
||||
return nil
|
||||
}
|
||||
self = .mention(.any(ref))
|
||||
}
|
||||
}
|
||||
extension Block {
|
||||
@ -201,10 +172,7 @@ extension Block {
|
||||
return "#[\(idx)]"
|
||||
}
|
||||
|
||||
switch m.ref {
|
||||
case .pubkey(let pk): return "nostr:\(pk.npub)"
|
||||
case .note(let note_id): return "nostr:\(note_id.bech32)"
|
||||
}
|
||||
return "nostr:" + Bech32Object.encode(m.ref.toBech32Object())
|
||||
case .relay(let relay):
|
||||
return relay
|
||||
case .text(let txt):
|
||||
|
@ -16,7 +16,7 @@ fileprivate extension String {
|
||||
}
|
||||
}
|
||||
|
||||
struct NEvent : Equatable {
|
||||
struct NEvent : Equatable, Hashable {
|
||||
let noteid: NoteId
|
||||
let relays: [String]
|
||||
let author: Pubkey?
|
||||
@ -49,12 +49,12 @@ struct NEvent : Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
struct NProfile : Equatable {
|
||||
struct NProfile : Equatable, Hashable {
|
||||
let author: Pubkey
|
||||
let relays: [String]
|
||||
}
|
||||
|
||||
struct NAddr : Equatable {
|
||||
struct NAddr : Equatable, Hashable {
|
||||
let identifier: String
|
||||
let author: Pubkey
|
||||
let relays: [String]
|
||||
@ -107,6 +107,29 @@ enum Bech32Object : Equatable {
|
||||
return bech32_encode(hrp: "nscript", data)
|
||||
}
|
||||
}
|
||||
|
||||
func toMentionRef() -> MentionRef? {
|
||||
switch self {
|
||||
case .nsec(let privkey):
|
||||
guard let pubkey = privkey_to_pubkey(privkey: privkey) else { return nil }
|
||||
return .pubkey(pubkey)
|
||||
case .npub(let pubkey):
|
||||
return .pubkey(pubkey)
|
||||
case .note(let noteid):
|
||||
return .note(noteid)
|
||||
case .nscript(_):
|
||||
return nil
|
||||
case .nevent(let nevent):
|
||||
return .nevent(nevent)
|
||||
case .nprofile(let nprofile):
|
||||
return .nprofile(nprofile)
|
||||
case .nrelay(let relayURL):
|
||||
return .nrelay(relayURL)
|
||||
case .naddr(let naddr):
|
||||
return .naddr(naddr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func decodeCBech32(_ b: nostr_bech32_t) -> Bech32Object? {
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import SwiftUI
|
||||
@testable import damus
|
||||
|
||||
class NoteContentViewTests: XCTestCase {
|
||||
@ -36,4 +37,100 @@ class NoteContentViewTests: XCTestCase {
|
||||
XCTAssertTrue((parsed.blocks[0].asURL != nil), "NoteContentView does not correctly parse an image block when url in JSON content contains optional escaped slashes.")
|
||||
}
|
||||
|
||||
func testMentionStr_Pubkey_ContainsAbbreviated() throws {
|
||||
let compatibleText = createCompatibleText(test_pubkey.npub)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: "17ldvg64:nq5mhr77")
|
||||
}
|
||||
|
||||
func testMentionStr_Pubkey_ContainsFullBech32() {
|
||||
let compatableText = createCompatibleText(test_pubkey.npub)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatableText, expected: test_pubkey.npub)
|
||||
}
|
||||
|
||||
func testMentionStr_Nprofile_ContainsAbbreviated() throws {
|
||||
let compatibleText = createCompatibleText("nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p")
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: "180cvv07:wsyjh6w6")
|
||||
}
|
||||
|
||||
func testMentionStr_Nprofile_ContainsFullBech32() throws {
|
||||
let bech = "nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p"
|
||||
let compatibleText = createCompatibleText(bech)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: bech)
|
||||
}
|
||||
|
||||
func testMentionStr_Note_ContainsAbbreviated() {
|
||||
let compatibleText = createCompatibleText(test_note.id.bech32)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: "note1qqq:qqn2l0z3")
|
||||
}
|
||||
|
||||
func testMentionStr_Note_ContainsFullBech32() {
|
||||
let compatableText = createCompatibleText(test_note.id.bech32)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatableText, expected: test_note.id.bech32)
|
||||
}
|
||||
|
||||
func testMentionStr_Nevent_ContainsAbbreviated() {
|
||||
let bech = "nevent1qqstna2yrezu5wghjvswqqculvvwxsrcvu7uc0f78gan4xqhvz49d9spr3mhxue69uhkummnw3ez6un9d3shjtn4de6x2argwghx6egpr4mhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet5nxnepm"
|
||||
let compatibleText = createCompatibleText(bech)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: "nevent1q:t5nxnepm")
|
||||
}
|
||||
|
||||
func testMentionStr_Nevent_ContainsFullBech32() throws {
|
||||
let bech = "nevent1qqstna2yrezu5wghjvswqqculvvwxsrcvu7uc0f78gan4xqhvz49d9spr3mhxue69uhkummnw3ez6un9d3shjtn4de6x2argwghx6egpr4mhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet5nxnepm"
|
||||
let compatibleText = createCompatibleText(bech)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: bech)
|
||||
}
|
||||
|
||||
func testMentionStr_Nrelay_ContainsAbbreviated() {
|
||||
let bech = "nrelay1qqt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueq4r295t"
|
||||
let compatibleText = createCompatibleText(bech)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: "wss://relay.nostr.band")
|
||||
}
|
||||
|
||||
func testMentionStr_Nrelay_ContainsFullBech32() {
|
||||
let bech = "nrelay1qqt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueq4r295t"
|
||||
let compatibleText = createCompatibleText(bech)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: bech)
|
||||
}
|
||||
|
||||
func testMentionStr_Naddr_ContainsAbbreviated() {
|
||||
let bech = "naddr1qqxnzdesxqmnxvpexqunzvpcqyt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueqzypve7elhmamff3sr5mgxxms4a0rppkmhmn7504h96pfcdkpplvl2jqcyqqq823cnmhuld"
|
||||
let compatibleText = createCompatibleText(bech)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: "naddr1qq:3cnmhuld")
|
||||
}
|
||||
|
||||
func testMentionStr_Naddr_ContainsFullBech32() {
|
||||
let bech = "naddr1qqxnzdesxqmnxvpexqunzvpcqyt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueqzypve7elhmamff3sr5mgxxms4a0rppkmhmn7504h96pfcdkpplvl2jqcyqqq823cnmhuld"
|
||||
let compatibleText = createCompatibleText(bech)
|
||||
|
||||
assertCompatibleTextHasExpectedString(compatibleText: compatibleText, expected: bech)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func assertCompatibleTextHasExpectedString(compatibleText: CompatibleText, expected: String) {
|
||||
guard let hasExpected = compatibleText.items.first?.attributed_string()?.description.contains(expected) else {
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertTrue(hasExpected)
|
||||
}
|
||||
|
||||
private func createCompatibleText(_ bechString: String) -> CompatibleText {
|
||||
guard let mentionRef = Bech32Object.parse(bechString)?.toMentionRef() else {
|
||||
XCTFail("Failed to create MentionRef from Bech32 string")
|
||||
return CompatibleText()
|
||||
}
|
||||
return mention_str(.any(mentionRef), profiles: test_damus_state.profiles)
|
||||
}
|
||||
|
@ -229,4 +229,46 @@ class damusTests: XCTestCase {
|
||||
XCTAssertEqual(txt, "there is no mention here")
|
||||
}
|
||||
|
||||
func testTagGeneration_Nevent_ContainsETag() {
|
||||
let ev = createEventFromContentString("nevent1qqstna2yrezu5wghjvswqqculvvwxsrcvu7uc0f78gan4xqhvz49d9spr3mhxue69uhkummnw3ez6un9d3shjtn4de6x2argwghx6egpr4mhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet5nxnepm")
|
||||
|
||||
XCTAssertEqual(ev.tags.count, 1)
|
||||
XCTAssertEqual(ev.tags[0][0].string(), "e")
|
||||
XCTAssertEqual(ev.tags[0][1].string(), "b9f5441e45ca39179320e0031cfb18e34078673dcc3d3e3a3b3a981760aa5696")
|
||||
}
|
||||
|
||||
func testTagGeneration_Nprofile_ContainsPTag() {
|
||||
let ev = createEventFromContentString("nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p")
|
||||
|
||||
XCTAssertEqual(ev.tags.count, 1)
|
||||
XCTAssertEqual(ev.tags[0][0].string(), "p")
|
||||
XCTAssertEqual(ev.tags[0][1].string(), "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")
|
||||
}
|
||||
|
||||
func testTagGeneration_Nrelay_ContainsRTag() {
|
||||
let ev = createEventFromContentString("nrelay1qqt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueq4r295t")
|
||||
|
||||
XCTAssertEqual(ev.tags.count, 1)
|
||||
XCTAssertEqual(ev.tags[0][0].string(), "r")
|
||||
XCTAssertEqual(ev.tags[0][1].string(), "wss://relay.nostr.band")
|
||||
}
|
||||
|
||||
func testTagGeneration_Naddr_ContainsATag(){
|
||||
let ev = createEventFromContentString("naddr1qqxnzdesxqmnxvpexqunzvpcqyt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueqzypve7elhmamff3sr5mgxxms4a0rppkmhmn7504h96pfcdkpplvl2jqcyqqq823cnmhuld")
|
||||
|
||||
XCTAssertEqual(ev.tags.count, 1)
|
||||
XCTAssertEqual(ev.tags[0][0].string(), "a")
|
||||
XCTAssertEqual(ev.tags[0][1].string(), "30023:599f67f7df7694c603a6d0636e15ebc610db77dcfd47d6e5d05386d821fb3ea9:1700730909108")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func createEventFromContentString(_ content: String) -> NostrEvent {
|
||||
let post = NostrPost(content: content, references: [])
|
||||
guard let ev = post_to_event(post: post, keypair: test_keypair_full) else {
|
||||
XCTFail("Could not create event")
|
||||
return test_note
|
||||
}
|
||||
|
||||
return ev
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user