use coracle_lib::addresses::{Address, AddressError}; use coracle_lib::events::EventContent; use coracle_lib::keys::SecretKey; use coracle_lib::tags::Tag; fn fixed_secret() -> SecretKey { let bytes: [u8; 32] = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, ]; SecretKey::from_hex(&hex::encode(bytes)).unwrap() } fn make_signed_event(kind: u16, tags: Vec) -> coracle_lib::events::Event { let sk = fixed_secret(); let pk = sk.public_key(); let hashed = EventContent::new("test", tags) .kind(kind) .stamp(1_700_000_000) .own(pk) .hash(); let sig = sk.sign(&hashed.id); hashed.sign(sig) } // --- Construction --- #[test] fn new_basic() { let pk = fixed_secret().public_key(); let addr = Address::new(30023, pk, "my-article"); assert_eq!(addr.kind, 30023); assert_eq!(addr.pubkey, pk); assert_eq!(addr.identifier, "my-article"); assert!(addr.hints.is_empty()); } #[test] fn hints_builder() { let pk = fixed_secret().public_key(); let addr = Address::new(30023, pk, "my-article") .hints(["wss://relay.example.com", "wss://other.relay"]); assert_eq!(addr.hints.len(), 2); assert_eq!(addr.hints[0], "wss://relay.example.com"); } #[test] fn equality_ignores_hints() { let pk = fixed_secret().public_key(); let a = Address::new(30023, pk, "slug"); let b = Address::new(30023, pk, "slug").hints(["wss://relay.example.com"]); assert_eq!(a, b); } // --- from_event --- #[test] fn from_event_addressable() { let event = make_signed_event(30023, vec![Tag::new("d", ["my-article"])]); let addr = Address::from_event(&event).unwrap(); assert_eq!(addr.kind, 30023); assert_eq!(addr.identifier, "my-article"); assert_eq!(addr.pubkey, event.pubkey); assert!(addr.hints.is_empty()); } #[test] fn from_event_replaceable_kind_0() { let event = make_signed_event(0, vec![]); let addr = Address::from_event(&event).unwrap(); assert_eq!(addr.kind, 0); assert_eq!(addr.identifier, ""); } #[test] fn from_event_replaceable_kind_3() { let event = make_signed_event(3, vec![]); let addr = Address::from_event(&event).unwrap(); assert_eq!(addr.kind, 3); assert_eq!(addr.identifier, ""); } #[test] fn from_event_replaceable_range() { let event = make_signed_event(10002, vec![]); let addr = Address::from_event(&event).unwrap(); assert_eq!(addr.kind, 10002); assert_eq!(addr.identifier, ""); } #[test] fn from_event_replaceable_ignores_d_tag() { let event = make_signed_event(0, vec![Tag::new("d", ["should-be-ignored"])]); let addr = Address::from_event(&event).unwrap(); assert_eq!(addr.kind, 0); assert_eq!(addr.identifier, ""); } #[test] fn from_event_regular_returns_none() { let event = make_signed_event(1, vec![]); assert!(Address::from_event(&event).is_none()); } #[test] fn from_event_ephemeral_returns_none() { let event = make_signed_event(20000, vec![]); assert!(Address::from_event(&event).is_none()); } // --- Display / FromStr --- #[test] fn display_roundtrip() { let pk = fixed_secret().public_key(); let addr = Address::new(30023, pk, "my-article"); let s = addr.to_string(); assert!(s.starts_with("30023:")); assert!(s.ends_with(":my-article")); let parsed: Address = s.parse().unwrap(); assert_eq!(parsed, addr); } #[test] fn fromstr_empty_identifier() { let pk = fixed_secret().public_key(); let addr = Address::new(0, pk, ""); let s = addr.to_string(); let parsed: Address = s.parse().unwrap(); assert_eq!(parsed.identifier, ""); assert_eq!(parsed, addr); } #[test] fn fromstr_identifier_with_colons() { let pk = fixed_secret().public_key(); let addr = Address::new(30023, pk, "has:colons:inside"); let s = addr.to_string(); let parsed: Address = s.parse().unwrap(); assert_eq!(parsed.identifier, "has:colons:inside"); assert_eq!(parsed, addr); } #[test] fn fromstr_invalid() { assert!("not-an-address".parse::
().is_err()); assert!("123".parse::
().is_err()); assert!("abc:def:ghi".parse::
().is_err()); } // --- naddr encoding --- #[test] fn naddr_roundtrip_no_relays() { let pk = fixed_secret().public_key(); let addr = Address::new(30023, pk, "my-article"); let naddr = addr.to_naddr(); assert!(naddr.starts_with("naddr1")); let decoded = Address::from_naddr(&naddr).unwrap(); assert_eq!(decoded, addr); assert!(decoded.hints.is_empty()); } #[test] fn naddr_roundtrip_with_relays() { let pk = fixed_secret().public_key(); let addr = Address::new(30023, pk, "my-article") .hints(["wss://relay.example.com", "wss://other.relay"]); let naddr = addr.to_naddr(); let decoded = Address::from_naddr(&naddr).unwrap(); assert_eq!(decoded, addr); assert_eq!( decoded.hints, vec!["wss://relay.example.com", "wss://other.relay"] ); } #[test] fn naddr_roundtrip_empty_identifier() { let pk = fixed_secret().public_key(); let addr = Address::new(10002, pk, ""); let naddr = addr.to_naddr(); let decoded = Address::from_naddr(&naddr).unwrap(); assert_eq!(decoded, addr); } #[test] fn fromstr_accepts_naddr() { let pk = fixed_secret().public_key(); let addr = Address::new(30023, pk, "my-article") .hints(["wss://relay.example.com"]); let naddr = addr.to_naddr(); let parsed: Address = naddr.parse().unwrap(); assert_eq!(parsed, addr); assert_eq!(parsed.hints, vec!["wss://relay.example.com"]); } #[test] fn from_naddr_wrong_prefix() { let pk = fixed_secret().public_key(); let npub = pk.to_npub(); let err = Address::from_naddr(&npub).unwrap_err(); assert!(matches!(err, AddressError::WrongPrefix { .. })); }