Files
coracle-rust/coracle-lib/tests/events.rs
T
2026-04-16 16:49:18 -07:00

119 lines
3.5 KiB
Rust

use coracle_lib::events::{
Event, EventContent, EventError, EventTemplate, HashedEvent, OwnedEvent, StampedEvent,
};
use coracle_lib::keys::SecretKey;
use coracle_lib::tags::{Tag, Tags};
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 build_hashed(content: &str, tags: Vec<Tag>) -> HashedEvent {
EventContent::new(content, tags)
.kind(1)
.stamp(1_700_000_000)
.own(fixed_secret().public_key())
.hash()
}
fn sign_fixture() -> Event {
let sk = fixed_secret();
let hashed = build_hashed("hello nostr", vec![Tag::new("t", ["nostr"])]);
let sig = sk.sign(&hashed.id);
hashed.sign(sig)
}
#[test]
fn pipeline_progresses_through_types() {
let content = EventContent::new("hi", Tags::new());
let template: EventTemplate = content.kind(1);
let stamped: StampedEvent = template.stamp(1_700_000_000);
let owned: OwnedEvent = stamped.own(fixed_secret().public_key());
let hashed: HashedEvent = owned.hash();
let sig = fixed_secret().sign(&hashed.id);
let event: Event = hashed.sign(sig);
assert_eq!(event.content, "hi");
assert_eq!(event.kind, 1);
}
#[test]
fn id_is_deterministic() {
let a = build_hashed("hello", vec![]);
let b = build_hashed("hello", vec![]);
assert_eq!(a.id, b.id);
}
#[test]
fn id_changes_with_content() {
let a = build_hashed("hello", vec![]);
let b = build_hashed("goodbye", vec![]);
assert_ne!(a.id, b.id);
}
#[test]
fn sign_and_verify_roundtrip() {
let event = sign_fixture();
assert!(event.verify_id());
event.verify().expect("signature should verify");
}
#[test]
fn tampered_content_fails_id_check() {
let mut event = sign_fixture();
event.content = "something else".to_string();
assert!(!event.verify_id());
assert_eq!(event.verify(), Err(EventError::InvalidId));
}
#[test]
fn tampered_sig_fails_verify() {
let mut event = sign_fixture();
event.sig[0] ^= 0x01;
assert_eq!(event.verify(), Err(EventError::InvalidSignature));
}
#[test]
fn json_roundtrip() {
let event = sign_fixture();
let json = serde_json::to_string(&event).unwrap();
let parsed: Event = serde_json::from_str(&json).unwrap();
assert_eq!(parsed, event);
parsed.verify().expect("roundtripped event still verifies");
}
#[test]
fn json_contains_hex_fields() {
let event = sign_fixture();
let value: serde_json::Value = serde_json::to_value(&event).unwrap();
let obj = value.as_object().unwrap();
assert_eq!(obj["id"].as_str().unwrap().len(), 64);
assert_eq!(obj["pubkey"].as_str().unwrap().len(), 64);
assert_eq!(obj["sig"].as_str().unwrap().len(), 128);
assert_eq!(obj["kind"].as_u64().unwrap(), 1);
assert_eq!(obj["content"].as_str().unwrap(), "hello nostr");
assert!(obj["tags"].is_array());
}
#[test]
fn json_ignores_unknown_fields() {
let event = sign_fixture();
let mut value: serde_json::Value = serde_json::to_value(&event).unwrap();
value
.as_object_mut()
.unwrap()
.insert("custom_field".to_string(), serde_json::json!("ignored"));
let reparsed: Event = serde_json::from_value(value).unwrap();
assert_eq!(reparsed, event);
}
#[test]
fn secret_key_sign_is_deterministic() {
let sk = fixed_secret();
let msg = [42u8; 32];
assert_eq!(sk.sign(&msg), sk.sign(&msg));
}