Files
coracle-rust/coracle-lib/tests/addresses.rs
T
2026-04-17 16:43:56 -07:00

207 lines
5.8 KiB
Rust

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<Tag>) -> 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::<Address>().is_err());
assert!("123".parse::<Address>().is_err());
assert!("abc:def:ghi".parse::<Address>().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 { .. }));
}