Add tags chapter
This commit is contained in:
@@ -2,6 +2,7 @@ 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] = [
|
||||
@@ -11,7 +12,7 @@ fn fixed_secret() -> SecretKey {
|
||||
SecretKey::from_hex(&hex::encode(bytes)).unwrap()
|
||||
}
|
||||
|
||||
fn build_hashed(content: &str, tags: Vec<Vec<String>>) -> HashedEvent {
|
||||
fn build_hashed(content: &str, tags: Vec<Tag>) -> HashedEvent {
|
||||
EventContent::new(content, tags)
|
||||
.kind(1)
|
||||
.stamp(1_700_000_000)
|
||||
@@ -21,14 +22,14 @@ fn build_hashed(content: &str, tags: Vec<Vec<String>>) -> HashedEvent {
|
||||
|
||||
fn sign_fixture() -> Event {
|
||||
let sk = fixed_secret();
|
||||
let hashed = build_hashed("hello nostr", vec![vec!["t".into(), "nostr".into()]]);
|
||||
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", vec![]);
|
||||
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());
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
use coracle_lib::tags::{Tag, Tags};
|
||||
|
||||
#[test]
|
||||
fn new_tag_accessors() {
|
||||
let t = Tag::new("e", ["abc", "wss://relay.example", "reply"]);
|
||||
assert_eq!(t.name(), "e");
|
||||
assert_eq!(t.value(), "abc");
|
||||
assert_eq!(t.get(2), Some("wss://relay.example"));
|
||||
assert_eq!(t.get(3), Some("reply"));
|
||||
assert_eq!(t.get(4), None);
|
||||
assert_eq!(t.len(), 4);
|
||||
assert_eq!(t.values().len(), 3);
|
||||
assert!(!t.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_tag_returns_empty_strings() {
|
||||
let t = Tag(Vec::new());
|
||||
assert_eq!(t.name(), "");
|
||||
assert_eq!(t.value(), "");
|
||||
assert!(t.values().is_empty());
|
||||
assert!(t.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_entry_tag_has_empty_value() {
|
||||
let t = Tag::new("-", std::iter::empty::<String>());
|
||||
assert_eq!(t.name(), "-");
|
||||
assert_eq!(t.value(), "");
|
||||
assert_eq!(t.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_and_into_vec_string() {
|
||||
let raw = vec!["t".to_string(), "nostr".to_string()];
|
||||
let tag: Tag = raw.clone().into();
|
||||
assert_eq!(tag.name(), "t");
|
||||
let back: Vec<String> = tag.into();
|
||||
assert_eq!(back, raw);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tag_serde_is_transparent() {
|
||||
let tag = Tag::new("t", ["nostr"]);
|
||||
let json = serde_json::to_string(&tag).unwrap();
|
||||
assert_eq!(json, r#"["t","nostr"]"#);
|
||||
let parsed: Tag = serde_json::from_str(r#"["p","abcdef"]"#).unwrap();
|
||||
assert_eq!(parsed.name(), "p");
|
||||
assert_eq!(parsed.value(), "abcdef");
|
||||
}
|
||||
|
||||
fn sample_tags() -> Tags {
|
||||
Tags::from(vec![
|
||||
Tag::new("t", ["nostr"]),
|
||||
Tag::new("t", ["rust"]),
|
||||
Tag::new("p", ["abcd"]),
|
||||
Tag::new("e", ["ffff", "wss://relay.example", "root"]),
|
||||
])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tags_serde_is_transparent() {
|
||||
let tags = sample_tags();
|
||||
let json = serde_json::to_string(&tags).unwrap();
|
||||
// outer type is just an array of arrays
|
||||
assert!(json.starts_with("[["));
|
||||
let parsed: Tags = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(parsed, tags);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_returns_first_match() {
|
||||
let ts = sample_tags();
|
||||
let t = ts.find("t").unwrap();
|
||||
assert_eq!(t.value(), "nostr");
|
||||
assert!(ts.find("x").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_all_iterates_matches() {
|
||||
let ts = sample_tags();
|
||||
let found: Vec<&str> = ts.find_all("t").map(Tag::value).collect();
|
||||
assert_eq!(found, vec!["nostr", "rust"]);
|
||||
assert_eq!(ts.find_all("p").count(), 1);
|
||||
assert_eq!(ts.find_all("x").count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_and_values_helpers() {
|
||||
let ts = sample_tags();
|
||||
assert_eq!(ts.value("t"), Some("nostr"));
|
||||
assert_eq!(ts.value("p"), Some("abcd"));
|
||||
assert_eq!(ts.value("x"), None);
|
||||
let all_t: Vec<&str> = ts.values("t").collect();
|
||||
assert_eq!(all_t, vec!["nostr", "rust"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn has_checks_presence() {
|
||||
let ts = sample_tags();
|
||||
assert!(ts.has("p"));
|
||||
assert!(ts.has("e"));
|
||||
assert!(!ts.has("q"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tags_deref_to_slice() {
|
||||
let ts = sample_tags();
|
||||
// Deref lets us use slice methods directly.
|
||||
assert_eq!(ts.len(), 4);
|
||||
assert_eq!(ts[0].name(), "t");
|
||||
let names: Vec<&str> = ts.iter().map(Tag::name).collect();
|
||||
assert_eq!(names, vec!["t", "t", "p", "e"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tags_new_is_empty() {
|
||||
let ts = Tags::new();
|
||||
assert!(ts.is_empty());
|
||||
assert_eq!(ts.len(), 0);
|
||||
}
|
||||
Reference in New Issue
Block a user