lib

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

codec_error_job.rs (6077B)


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