commit a8c83655b40f5a85265c27fb12f4c5165632cda2
parent 30cb226d21a1709252b2cfd1914ce3c42640dcd0
Author: triesap <tyson@radroots.org>
Date: Sun, 21 Jun 2026 20:30:13 +0000
events-codec: expand profile decode coverage
- Cover optional profile metadata extraction, invalid scalar bot handling, and non-object JSON rejection.
- Exercise profile type tag selection across short, unrelated, unknown, and later valid tags.
- Assert parsed profile events preserve wire event fields and decoded profile data.
- Validate focused profile tests, full radroots_events_codec tests, crate check, diff check, and refreshed coverage run.
Diffstat:
1 file changed, 98 insertions(+), 8 deletions(-)
diff --git a/crates/events_codec/tests/profile.rs b/crates/events_codec/tests/profile.rs
@@ -1,14 +1,17 @@
#![cfg(feature = "serde_json")]
use radroots_events::{
- kinds::KIND_POST,
+ kinds::{KIND_POST, KIND_PROFILE},
profile::{
- RADROOTS_PROFILE_TYPE_TAG_ANY, RADROOTS_PROFILE_TYPE_TAG_FARM,
- RADROOTS_PROFILE_TYPE_TAG_KEY, RADROOTS_PROFILE_TYPE_TAG_RADROOTSD, RadrootsProfileType,
+ RADROOTS_PROFILE_TYPE_TAG_ANY, RADROOTS_PROFILE_TYPE_TAG_COOP,
+ RADROOTS_PROFILE_TYPE_TAG_FARM, RADROOTS_PROFILE_TYPE_TAG_KEY,
+ RADROOTS_PROFILE_TYPE_TAG_RADROOTSD, RadrootsProfileType,
},
};
use radroots_events_codec::error::EventParseError;
-use radroots_events_codec::profile::decode::profile_from_content;
+use radroots_events_codec::profile::decode::{
+ data_from_event, parsed_from_event, profile_from_content,
+};
#[test]
fn profile_from_content_parses_bot_boolean() {
@@ -29,6 +32,32 @@ fn profile_from_content_parses_bot_string() {
}
#[test]
+fn profile_from_content_parses_optional_metadata_and_ignores_invalid_scalars() {
+ let content = r#"{"name":"alice","display_name":"Alice","nip05":"alice@example.test","about":"farm account","website":"https://farm.example.test","picture":"https://farm.example.test/pic.png","banner":"https://farm.example.test/banner.png","lud06":"lnurl1farm","lud16":"alice@example.test","bot":12}"#;
+ let profile = profile_from_content(content).unwrap();
+
+ assert_eq!(profile.name, "alice");
+ assert_eq!(profile.display_name.as_deref(), Some("Alice"));
+ assert_eq!(profile.nip05.as_deref(), Some("alice@example.test"));
+ assert_eq!(profile.about.as_deref(), Some("farm account"));
+ assert_eq!(
+ profile.website.as_deref(),
+ Some("https://farm.example.test")
+ );
+ assert_eq!(
+ profile.picture.as_deref(),
+ Some("https://farm.example.test/pic.png")
+ );
+ assert_eq!(
+ profile.banner.as_deref(),
+ Some("https://farm.example.test/banner.png")
+ );
+ assert_eq!(profile.lud06.as_deref(), Some("lnurl1farm"));
+ assert_eq!(profile.lud16.as_deref(), Some("alice@example.test"));
+ assert_eq!(profile.bot, None);
+}
+
+#[test]
fn profile_from_content_rejects_missing_name() {
let content = r#"{"display_name":"alice"}"#;
let err = profile_from_content(content).unwrap_err();
@@ -36,6 +65,12 @@ fn profile_from_content_rejects_missing_name() {
}
#[test]
+fn profile_from_content_rejects_non_object_json() {
+ let err = profile_from_content("[]").unwrap_err();
+ assert!(matches!(err, EventParseError::InvalidJson("content")));
+}
+
+#[test]
fn profile_from_content_rejects_invalid_json() {
let err = profile_from_content("{").unwrap_err();
assert!(matches!(err, EventParseError::InvalidJson("content")));
@@ -43,7 +78,7 @@ fn profile_from_content_rejects_invalid_json() {
#[test]
fn profile_metadata_rejects_wrong_kind() {
- let err = radroots_events_codec::profile::decode::data_from_event(
+ let err = data_from_event(
"id".to_string(),
"author".to_string(),
1,
@@ -64,7 +99,7 @@ fn profile_metadata_rejects_wrong_kind() {
#[test]
fn profile_metadata_reads_profile_type_tag() {
- let metadata = radroots_events_codec::profile::decode::data_from_event(
+ let metadata = data_from_event(
"id".to_string(),
"author".to_string(),
1,
@@ -82,7 +117,7 @@ fn profile_metadata_reads_profile_type_tag() {
#[test]
fn profile_metadata_reads_profile_type_any_tag() {
- let metadata = radroots_events_codec::profile::decode::data_from_event(
+ let metadata = data_from_event(
"id".to_string(),
"author".to_string(),
1,
@@ -100,7 +135,7 @@ fn profile_metadata_reads_profile_type_any_tag() {
#[test]
fn profile_metadata_reads_profile_type_radrootsd_tag() {
- let metadata = radroots_events_codec::profile::decode::data_from_event(
+ let metadata = data_from_event(
"id".to_string(),
"author".to_string(),
1,
@@ -118,3 +153,58 @@ fn profile_metadata_reads_profile_type_radrootsd_tag() {
Some(RadrootsProfileType::Radrootsd)
);
}
+
+#[test]
+fn profile_metadata_ignores_short_unknown_and_unrelated_profile_type_tags() {
+ let metadata = data_from_event(
+ "id".to_string(),
+ "author".to_string(),
+ 1,
+ KIND_PROFILE,
+ "{\"name\":\"alice\"}".to_string(),
+ vec![
+ vec![RADROOTS_PROFILE_TYPE_TAG_KEY.to_string()],
+ vec![
+ RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(),
+ "radroots:type:unknown".to_string(),
+ ],
+ vec!["x".to_string(), RADROOTS_PROFILE_TYPE_TAG_COOP.to_string()],
+ vec![
+ RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(),
+ RADROOTS_PROFILE_TYPE_TAG_COOP.to_string(),
+ ],
+ ],
+ )
+ .expect("metadata");
+
+ assert_eq!(metadata.data.profile_type, Some(RadrootsProfileType::Coop));
+}
+
+#[test]
+fn profile_parsed_event_preserves_wire_event_and_decoded_data() {
+ let parsed = parsed_from_event(
+ "event-id".to_string(),
+ "author-pubkey".to_string(),
+ 42,
+ KIND_PROFILE,
+ "{\"name\":\"alice\"}".to_string(),
+ vec![vec![
+ RADROOTS_PROFILE_TYPE_TAG_KEY.to_string(),
+ RADROOTS_PROFILE_TYPE_TAG_FARM.to_string(),
+ ]],
+ "event-sig".to_string(),
+ )
+ .expect("parsed profile");
+
+ assert_eq!(parsed.event.id, "event-id");
+ assert_eq!(parsed.event.author, "author-pubkey");
+ assert_eq!(parsed.event.created_at, 42);
+ assert_eq!(parsed.event.kind, KIND_PROFILE);
+ assert_eq!(parsed.event.content, "{\"name\":\"alice\"}");
+ assert_eq!(parsed.event.sig, "event-sig");
+ assert_eq!(parsed.data.data.profile.name, "alice");
+ assert_eq!(
+ parsed.data.data.profile_type,
+ Some(RadrootsProfileType::Farm)
+ );
+}