commit d7ea0fb78b32bd4bb47ce8960307d029f6849e32
parent 60b8e80f98e0cfa86ea86eb6093fd916765243ec
Author: triesap <tyson@radroots.org>
Date: Sun, 21 Jun 2026 21:05:49 +0000
events-codec: expand calendar file encode coverage
- Cover absent optional calendar encode fields for time events, collection event addresses, RSVP relay echoing, and free/busy tags.
- Cover minimal public file metadata encode shape and invalid dimension validation.
- Validate focused calendar/file metadata tests, full radroots_events_codec tests, crate check, diff check, and refreshed coverage run.
Diffstat:
2 files changed, 99 insertions(+), 0 deletions(-)
diff --git a/crates/events_codec/tests/calendar.rs b/crates/events_codec/tests/calendar.rs
@@ -276,6 +276,48 @@ fn calendar_rsvp_to_wire_parts_roundtrips_status_event_id_and_participants() {
}
#[test]
+fn calendar_encode_omits_absent_optional_fields() {
+ let mut time = sample_time_event();
+ time.end = None;
+ time.location = None;
+ let tags = calendar_time_event_build_tags(&time).unwrap();
+ assert!(!tags.iter().any(|tag| tag[0] == TAG_END));
+ assert!(!tags.iter().any(|tag| tag[0] == TAG_LOCATION));
+
+ let mut collection = sample_calendar_collection();
+ collection.events[0] = RadrootsSocialTarget::Address {
+ address: format!("{KIND_CALENDAR_TIME_EVENT}:{EVENT_AUTHOR}:{EVENT_D_TAG}"),
+ author: Some(EVENT_AUTHOR.to_string()),
+ event_kind: None,
+ relays: None,
+ };
+ let tags = calendar_collection_build_tags(&collection).unwrap();
+ assert_eq!(
+ tags.iter()
+ .find(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_A))
+ .map(Vec::len),
+ Some(2)
+ );
+
+ let mut rsvp = sample_rsvp();
+ rsvp.event = RadrootsSocialTarget::Address {
+ address: format!("{KIND_CALENDAR_TIME_EVENT}:{EVENT_AUTHOR}:{EVENT_D_TAG}"),
+ author: Some(EVENT_AUTHOR.to_string()),
+ event_kind: None,
+ relays: None,
+ };
+ rsvp.free_busy = None;
+ let tags = rsvp_build_tags(&rsvp).unwrap();
+ assert_eq!(
+ tags.iter()
+ .find(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_E))
+ .map(Vec::len),
+ Some(2)
+ );
+ assert!(!tags.iter().any(|tag| tag[0] == TAG_FREE_BUSY));
+}
+
+#[test]
fn calendar_codecs_reject_wrong_kind_invalid_dates_and_missing_time_dates() {
assert!(matches!(
date_to_wire_parts_with_kind(&sample_date_event(), KIND_POST),
diff --git a/crates/events_codec/tests/file_metadata.rs b/crates/events_codec/tests/file_metadata.rs
@@ -154,6 +154,63 @@ fn file_metadata_to_wire_parts_roundtrips_nip94_tags() {
}
#[test]
+fn file_metadata_encode_handles_minimal_optional_shape_and_invalid_dimensions() {
+ let mut metadata = sample_metadata();
+ metadata.original_sha256 = None;
+ metadata.size = None;
+ metadata.dimensions = None;
+ metadata.thumbnails = None;
+ metadata.summary = None;
+ metadata.alt = None;
+ metadata.fallback = None;
+ metadata.magnet = None;
+ metadata.content_hashes = None;
+ metadata.services = None;
+ metadata.content = None;
+
+ let parts = to_wire_parts(&metadata).unwrap();
+ assert_eq!(parts.content, "");
+ assert!(
+ !parts
+ .tags
+ .iter()
+ .any(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_SIZE))
+ );
+ assert!(
+ !parts
+ .tags
+ .iter()
+ .any(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_DIMENSIONS))
+ );
+ assert!(
+ !parts
+ .tags
+ .iter()
+ .any(|tag| { tag.first().map(|value| value.as_str()) == Some(TAG_ORIGINAL_SHA256) })
+ );
+
+ let mut metadata = sample_metadata();
+ metadata.dimensions = Some(RadrootsSocialMediaDimensions {
+ width: 0,
+ height: 800,
+ });
+ assert!(matches!(
+ file_metadata_build_tags(&metadata),
+ Err(EventEncodeError::InvalidField("dimensions"))
+ ));
+
+ let mut metadata = sample_metadata();
+ metadata.dimensions = Some(RadrootsSocialMediaDimensions {
+ width: 1200,
+ height: 0,
+ });
+ assert!(matches!(
+ file_metadata_build_tags(&metadata),
+ Err(EventEncodeError::InvalidField("dimensions"))
+ ));
+}
+
+#[test]
fn file_metadata_public_and_private_kind1063_contracts_do_not_cross_decode() {
let public = to_wire_parts(&sample_metadata()).unwrap();
let decoded_public =