lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

gift_wrap.rs (8310B)


      1 mod common;
      2 #[path = "../src/test_fixtures.rs"]
      3 mod test_fixtures;
      4 
      5 use common::{AUTHOR, EVENT_ID, EVENT_SIG};
      6 use radroots_event::envelope::kind::{KIND_GIFT_WRAP, KIND_MESSAGE};
      7 use radroots_event::social::gift_wrap::{GiftWrap, GiftWrapRecipient};
      8 
      9 use radroots_event_codec::decode::EventParseError;
     10 use radroots_event_codec::decode::gift_wrap::{
     11     data_from_event, gift_wrap_from_tags, parsed_from_event,
     12 };
     13 use radroots_event_codec::encode::EventEncodeError;
     14 use radroots_event_codec::encode::gift_wrap::{
     15     gift_wrap_build_tags, to_wire_parts, to_wire_parts_with_kind,
     16 };
     17 use test_fixtures::RELAY_PRIMARY_WSS;
     18 
     19 fn sample_gift_wrap() -> GiftWrap {
     20     GiftWrap {
     21         recipient: GiftWrapRecipient {
     22             public_key: "pubkey".to_string(),
     23             relay_url: Some(RELAY_PRIMARY_WSS.to_string()),
     24         },
     25         content: "encrypted".to_string(),
     26         expiration: Some(1700000000),
     27     }
     28 }
     29 
     30 #[test]
     31 fn gift_wrap_build_tags_requires_recipient() {
     32     let mut gift_wrap = sample_gift_wrap();
     33     gift_wrap.recipient.public_key = "  ".to_string();
     34 
     35     let err = gift_wrap_build_tags(&gift_wrap).unwrap_err();
     36     assert!(matches!(
     37         err,
     38         EventEncodeError::EmptyRequiredField("recipient.public_key")
     39     ));
     40 }
     41 
     42 #[test]
     43 fn gift_wrap_to_wire_parts_sets_kind_content_and_tags() {
     44     let gift_wrap = sample_gift_wrap();
     45     let parts = to_wire_parts(&gift_wrap).unwrap();
     46 
     47     assert_eq!(parts.kind, KIND_GIFT_WRAP);
     48     assert_eq!(parts.content, "encrypted");
     49     assert_eq!(
     50         parts.tags,
     51         vec![
     52             vec![
     53                 "p".to_string(),
     54                 "pubkey".to_string(),
     55                 RELAY_PRIMARY_WSS.to_string()
     56             ],
     57             vec!["expiration".to_string(), "1700000000".to_string()],
     58         ]
     59     );
     60 }
     61 
     62 #[test]
     63 fn gift_wrap_from_tags_rejects_wrong_kind() {
     64     let gift_wrap = sample_gift_wrap();
     65     let parts = to_wire_parts(&gift_wrap).unwrap();
     66 
     67     let err = gift_wrap_from_tags(KIND_MESSAGE, &parts.tags, &parts.content).unwrap_err();
     68     assert!(matches!(
     69         err,
     70         EventParseError::InvalidKind {
     71             expected: "1059",
     72             got: KIND_MESSAGE
     73         }
     74     ));
     75 }
     76 
     77 #[test]
     78 fn gift_wrap_from_tags_requires_p_tag() {
     79     let err = gift_wrap_from_tags(KIND_GIFT_WRAP, &[], "payload").unwrap_err();
     80     assert!(matches!(err, EventParseError::MissingTag("p")));
     81 
     82     let err = gift_wrap_from_tags(KIND_GIFT_WRAP, &[vec!["p".to_string()]], "payload").unwrap_err();
     83     assert!(matches!(err, EventParseError::InvalidTag("p")));
     84 }
     85 
     86 #[test]
     87 fn gift_wrap_from_tags_rejects_invalid_expiration_and_relay() {
     88     let err = gift_wrap_from_tags(
     89         KIND_GIFT_WRAP,
     90         &[
     91             vec![
     92                 "p".to_string(),
     93                 "pubkey".to_string(),
     94                 RELAY_PRIMARY_WSS.to_string(),
     95             ],
     96             vec!["expiration".to_string(), " ".to_string()],
     97         ],
     98         "payload",
     99     )
    100     .unwrap_err();
    101     assert!(matches!(err, EventParseError::InvalidTag("expiration")));
    102 
    103     let err = gift_wrap_from_tags(
    104         KIND_GIFT_WRAP,
    105         &[
    106             vec![
    107                 "p".to_string(),
    108                 "pubkey".to_string(),
    109                 RELAY_PRIMARY_WSS.to_string(),
    110             ],
    111             vec!["expiration".to_string(), "invalid".to_string()],
    112         ],
    113         "payload",
    114     )
    115     .unwrap_err();
    116     assert!(matches!(
    117         err,
    118         EventParseError::InvalidNumber("expiration", _)
    119     ));
    120 
    121     let err = gift_wrap_from_tags(
    122         KIND_GIFT_WRAP,
    123         &[vec!["p".to_string(), "pubkey".to_string(), " ".to_string()]],
    124         "payload",
    125     )
    126     .unwrap_err();
    127     assert!(matches!(err, EventParseError::InvalidTag("p")));
    128 }
    129 
    130 #[test]
    131 fn gift_wrap_metadata_and_index_from_event_roundtrip() {
    132     let gift_wrap = sample_gift_wrap();
    133     let parts = to_wire_parts(&gift_wrap).unwrap();
    134 
    135     let metadata = data_from_event(
    136         "id".to_string(),
    137         "author".to_string(),
    138         11,
    139         parts.kind,
    140         parts.content.clone(),
    141         parts.tags.clone(),
    142     )
    143     .unwrap();
    144     assert_eq!(metadata.id, "id");
    145     assert_eq!(metadata.author, "author");
    146     assert_eq!(metadata.published_at, 11);
    147     assert_eq!(
    148         metadata.data.recipient.public_key,
    149         gift_wrap.recipient.public_key
    150     );
    151     assert_eq!(
    152         metadata.data.recipient.relay_url,
    153         gift_wrap.recipient.relay_url
    154     );
    155     assert_eq!(metadata.data.content, gift_wrap.content);
    156     assert_eq!(metadata.data.expiration, gift_wrap.expiration);
    157 
    158     let index = parsed_from_event(
    159         EVENT_ID.to_string(),
    160         AUTHOR.to_string(),
    161         11,
    162         parts.kind,
    163         parts.content,
    164         parts.tags,
    165         EVENT_SIG.to_string(),
    166     )
    167     .unwrap();
    168     assert_eq!(index.event.kind_u32(), KIND_GIFT_WRAP);
    169     assert_eq!(index.event.signature_hex(), EVENT_SIG);
    170     assert_eq!(index.data.data.recipient.public_key, "pubkey");
    171 }
    172 
    173 #[test]
    174 fn gift_wrap_build_tags_handles_optional_expiration_and_invalid_relay() {
    175     let mut gift_wrap = sample_gift_wrap();
    176     gift_wrap.expiration = None;
    177     let tags = gift_wrap_build_tags(&gift_wrap).unwrap();
    178     assert_eq!(
    179         tags,
    180         vec![vec![
    181             "p".to_string(),
    182             "pubkey".to_string(),
    183             RELAY_PRIMARY_WSS.to_string()
    184         ]]
    185     );
    186 
    187     let mut gift_wrap = sample_gift_wrap();
    188     gift_wrap.recipient.relay_url = Some(" ".to_string());
    189     let err = gift_wrap_build_tags(&gift_wrap).unwrap_err();
    190     assert!(matches!(
    191         err,
    192         EventEncodeError::EmptyRequiredField("recipient.relay_url")
    193     ));
    194 
    195     let mut gift_wrap = sample_gift_wrap();
    196     gift_wrap.recipient.relay_url = None;
    197     let tags = gift_wrap_build_tags(&gift_wrap).unwrap();
    198     assert_eq!(tags[0], vec!["p".to_string(), "pubkey".to_string()]);
    199 }
    200 
    201 #[test]
    202 fn gift_wrap_to_wire_parts_requires_content_and_accepts_default_kind() {
    203     let mut gift_wrap = sample_gift_wrap();
    204     gift_wrap.content = " ".to_string();
    205     let err = to_wire_parts(&gift_wrap).unwrap_err();
    206     assert!(matches!(
    207         err,
    208         EventEncodeError::EmptyRequiredField("content")
    209     ));
    210 
    211     let parts = to_wire_parts_with_kind(&sample_gift_wrap(), KIND_GIFT_WRAP).unwrap();
    212     assert_eq!(parts.kind, KIND_GIFT_WRAP);
    213     assert_eq!(parts.content, "encrypted");
    214 
    215     let mut gift_wrap = sample_gift_wrap();
    216     gift_wrap.recipient.public_key = " ".to_string();
    217     let err = to_wire_parts(&gift_wrap).unwrap_err();
    218     assert!(matches!(
    219         err,
    220         EventEncodeError::EmptyRequiredField("recipient.public_key")
    221     ));
    222 }
    223 
    224 #[test]
    225 fn gift_wrap_to_wire_parts_with_kind_rejects_wrong_kind() {
    226     let err = to_wire_parts_with_kind(&sample_gift_wrap(), KIND_MESSAGE).unwrap_err();
    227     assert!(matches!(err, EventEncodeError::InvalidKind(KIND_MESSAGE)));
    228 }
    229 
    230 #[test]
    231 fn gift_wrap_from_tags_handles_missing_expiration_and_rejects_empty_fields() {
    232     let parsed = gift_wrap_from_tags(
    233         KIND_GIFT_WRAP,
    234         &[vec!["p".to_string(), "pubkey".to_string()]],
    235         "payload",
    236     )
    237     .unwrap();
    238     assert_eq!(parsed.recipient.public_key, "pubkey");
    239     assert!(parsed.recipient.relay_url.is_none());
    240     assert!(parsed.expiration.is_none());
    241 
    242     let err = gift_wrap_from_tags(
    243         KIND_GIFT_WRAP,
    244         &[vec!["p".to_string(), " ".to_string()]],
    245         "payload",
    246     )
    247     .unwrap_err();
    248     assert!(matches!(err, EventParseError::InvalidTag("p")));
    249 
    250     let err = gift_wrap_from_tags(
    251         KIND_GIFT_WRAP,
    252         &[vec!["p".to_string(), "pubkey".to_string()]],
    253         " ",
    254     )
    255     .unwrap_err();
    256     assert!(matches!(err, EventParseError::InvalidTag("content")));
    257 }
    258 
    259 #[test]
    260 fn gift_wrap_metadata_and_index_propagate_parse_errors() {
    261     let tags = vec![vec!["p".to_string(), "pubkey".to_string()]];
    262     let err = data_from_event(
    263         "id".to_string(),
    264         "author".to_string(),
    265         11,
    266         KIND_GIFT_WRAP,
    267         " ".to_string(),
    268         tags.clone(),
    269     )
    270     .unwrap_err();
    271     assert!(matches!(err, EventParseError::InvalidTag("content")));
    272 
    273     let err = parsed_from_event(
    274         "id".to_string(),
    275         "author".to_string(),
    276         11,
    277         KIND_GIFT_WRAP,
    278         " ".to_string(),
    279         tags,
    280         "sig".to_string(),
    281     )
    282     .unwrap_err();
    283     assert!(matches!(err, EventParseError::InvalidTag("content")));
    284 }