lib

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

codec_error_job.rs (6285B)


      1 #[path = "../src/test_fixtures.rs"]
      2 mod test_fixtures;
      3 
      4 use std::error::Error as _;
      5 
      6 use radroots_event_codec::decode::EventParseError;
      7 use radroots_event_codec::decode::job::JobParseError;
      8 use radroots_event_codec::encode::EventEncodeError;
      9 use radroots_event_codec::encode::job::{
     10     JobEncodeError, assert_no_inputs_when_encrypted, push_provider_tag, push_relay_tag,
     11     push_status_tag,
     12 };
     13 #[cfg(feature = "json")]
     14 use serde::Serialize;
     15 #[cfg(feature = "json")]
     16 use serde::ser::{Error as _, Serializer};
     17 use test_fixtures::{FIXTURE_ALICE_PUBLIC_KEY_HEX, RELAY_PRIMARY_WSS};
     18 
     19 #[test]
     20 fn parse_error_display_and_source_cover_variants() {
     21     let missing = EventParseError::MissingTag("d");
     22     assert_eq!(missing.to_string(), "missing tag: d");
     23     assert_eq!(missing.code(), "missing_tag");
     24     assert!(missing.source().is_none());
     25 
     26     let invalid = EventParseError::InvalidTag("a");
     27     assert_eq!(invalid.to_string(), "invalid tag structure for 'a'");
     28     assert_eq!(invalid.code(), "invalid_tag");
     29     assert!(invalid.source().is_none());
     30 
     31     let invalid_kind = EventParseError::InvalidKind {
     32         expected: "30340",
     33         got: 1,
     34     };
     35     assert_eq!(invalid_kind.to_string(), "invalid kind 1 (expected 30340)");
     36     assert_eq!(invalid_kind.code(), "invalid_kind");
     37     assert!(invalid_kind.source().is_none());
     38 
     39     let parse_int = "x".parse::<u32>().expect_err("parse int error");
     40     let invalid_number = EventParseError::InvalidNumber("count", parse_int);
     41     assert!(
     42         invalid_number
     43             .to_string()
     44             .contains("invalid number in 'count'")
     45     );
     46     assert_eq!(invalid_number.code(), "invalid_number");
     47     assert!(invalid_number.source().is_some());
     48 
     49     let invalid_json = EventParseError::InvalidJson("content");
     50     assert_eq!(invalid_json.to_string(), "invalid JSON in 'content'");
     51     assert_eq!(invalid_json.code(), "invalid_json");
     52     assert!(invalid_json.source().is_none());
     53 }
     54 
     55 #[test]
     56 fn encode_error_display_covers_variants() {
     57     let invalid_kind = EventEncodeError::InvalidKind(30402);
     58     assert_eq!(invalid_kind.to_string(), "invalid event kind: 30402");
     59     assert_eq!(invalid_kind.code(), "invalid_kind");
     60 
     61     let empty_required = EventEncodeError::EmptyRequiredField("content");
     62     assert_eq!(empty_required.to_string(), "empty required field: content");
     63     assert_eq!(empty_required.code(), "empty_required_field");
     64 
     65     let invalid_field = EventEncodeError::InvalidField("d");
     66     assert_eq!(invalid_field.to_string(), "invalid field: d");
     67     assert_eq!(invalid_field.code(), "invalid_field");
     68 
     69     let json = EventEncodeError::Json;
     70     assert_eq!(json.to_string(), "failed to serialize JSON");
     71     assert_eq!(json.code(), "json");
     72 }
     73 
     74 #[test]
     75 fn job_encode_helpers_cover_status_provider_relay_and_inputs() {
     76     let mut tags: Vec<Vec<String>> = Vec::new();
     77     push_status_tag(&mut tags, "ok", None);
     78     push_status_tag(&mut tags, "warning", Some("detail"));
     79     push_provider_tag(&mut tags, FIXTURE_ALICE_PUBLIC_KEY_HEX);
     80     push_relay_tag(&mut tags, RELAY_PRIMARY_WSS);
     81 
     82     assert_eq!(tags[0], vec!["status".to_string(), "ok".to_string()]);
     83     assert_eq!(
     84         tags[1],
     85         vec![
     86             "status".to_string(),
     87             "warning".to_string(),
     88             "detail".to_string(),
     89         ]
     90     );
     91     assert_eq!(
     92         tags[2],
     93         vec!["p".to_string(), FIXTURE_ALICE_PUBLIC_KEY_HEX.to_string(),]
     94     );
     95     assert_eq!(
     96         tags[3],
     97         vec!["relays".to_string(), RELAY_PRIMARY_WSS.to_string()]
     98     );
     99 
    100     assert!(assert_no_inputs_when_encrypted(&tags));
    101     let tags_with_input = vec![vec!["i".to_string(), "amount".to_string()]];
    102     assert!(!assert_no_inputs_when_encrypted(&tags_with_input));
    103 }
    104 
    105 #[cfg(feature = "json")]
    106 #[test]
    107 fn job_json_content_covers_success_and_error_paths() {
    108     #[derive(Clone)]
    109     struct BrokenSerialize;
    110 
    111     impl Serialize for BrokenSerialize {
    112         fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
    113         where
    114             S: Serializer,
    115         {
    116             Err(S::Error::custom("forced serialization error"))
    117         }
    118     }
    119 
    120     let ok = radroots_event_codec::encode::job::json_content(&vec!["ok".to_string()])
    121         .expect("json content");
    122     assert_eq!(ok, "[\"ok\"]");
    123 
    124     let err = radroots_event_codec::encode::job::json_content(&BrokenSerialize)
    125         .expect_err("json content error");
    126     assert!(matches!(
    127         err,
    128         JobEncodeError::EmptyRequiredField("content-json")
    129     ));
    130 }
    131 
    132 #[test]
    133 fn job_encode_error_display_covers_variants() {
    134     assert_eq!(
    135         JobEncodeError::MissingProvidersForEncrypted.to_string(),
    136         "encrypted=true requires at least one provider ('p') tag"
    137     );
    138     assert_eq!(
    139         JobEncodeError::InvalidKind(7000).to_string(),
    140         "invalid job event kind: 7000"
    141     );
    142     assert_eq!(
    143         JobEncodeError::EmptyRequiredField("content").to_string(),
    144         "empty required field: content"
    145     );
    146 }
    147 
    148 #[test]
    149 fn job_parse_error_display_and_source_covers_variants() {
    150     let kind = JobParseError::KindOutOfRange(u32::from(u16::MAX) + 1);
    151     assert!(kind.to_string().contains("Nostr event kind"));
    152     assert!(kind.source().is_none());
    153 
    154     let missing = JobParseError::MissingTag("e");
    155     assert_eq!(missing.to_string(), "missing tag: e");
    156     assert!(missing.source().is_none());
    157 
    158     let invalid = JobParseError::InvalidTag("status");
    159     assert_eq!(invalid.to_string(), "invalid tag structure for 'status'");
    160     assert!(invalid.source().is_none());
    161 
    162     let invalid_number = JobParseError::InvalidNumber("amount", "x".parse::<u32>().unwrap_err());
    163     assert!(
    164         invalid_number
    165             .to_string()
    166             .contains("invalid number in 'amount'")
    167     );
    168     assert!(invalid_number.source().is_some());
    169 
    170     let non_whole = JobParseError::NonWholeSats("amount");
    171     assert!(non_whole.to_string().contains("whole number of sats"));
    172     assert!(non_whole.source().is_none());
    173 
    174     let overflow = JobParseError::AmountOverflow("amount");
    175     assert!(overflow.to_string().contains("does not fit u32 sat"));
    176     assert!(overflow.source().is_none());
    177 
    178     let missing_chain = JobParseError::MissingChainTag("e");
    179     assert_eq!(missing_chain.to_string(), "missing required chain tag: e");
    180     assert!(missing_chain.source().is_none());
    181 }