lib

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

tests.rs (9015B)


      1 use super::*;
      2 use radroots_event::post::AuthoredUpdate;
      3 
      4 #[test]
      5 fn thread_exclusion_precedes_ask_and_media_projection() {
      6     let projection = project_inbound_post_parts(
      7         KIND_POST,
      8         &[
      9             vec!["e".to_string(), "parent".to_string()],
     10             vec!["t".to_string(), "radroots-ask".to_string()],
     11             vec!["imeta".to_string(), "x malformed".to_string()],
     12         ],
     13         "reply",
     14     )
     15     .unwrap();
     16 
     17     assert_eq!(
     18         projection.classification(),
     19         RadrootsPostClassification::ThreadExcluded
     20     );
     21     assert!(projection.imeta().is_empty());
     22     assert!(projection.diagnostics().is_empty());
     23 }
     24 
     25 #[test]
     26 fn every_empty_or_malformed_event_reference_is_thread_excluded() {
     27     for event_reference in [
     28         vec!["e".to_string()],
     29         vec!["e".to_string(), String::new()],
     30         vec!["e".to_string(), "not-an-event-id".to_string()],
     31     ] {
     32         let projection =
     33             project_inbound_post_parts(KIND_POST, &[event_reference], "candidate").unwrap();
     34 
     35         assert_eq!(
     36             projection.classification(),
     37             RadrootsPostClassification::ThreadExcluded
     38         );
     39         assert!(!projection.classification().is_root_card());
     40     }
     41 }
     42 
     43 #[test]
     44 fn normalized_ask_precedes_malformed_media_and_retains_diagnostics() {
     45     let projection = project_inbound_post_parts(
     46         KIND_POST,
     47         &[
     48             vec!["t".to_string(), " RADROOTS-ASK ".to_string()],
     49             vec![
     50                 "imeta".to_string(),
     51                 "url https://cdn.example/leaf.webp".to_string(),
     52                 "x malformed".to_string(),
     53             ],
     54         ],
     55         "Question https://cdn.example/leaf.webp",
     56     )
     57     .unwrap();
     58 
     59     assert_eq!(projection.classification(), RadrootsPostClassification::Ask);
     60     assert_eq!(
     61         diagnostic_codes(projection.diagnostics()),
     62         ["imeta_metadata_missing", "imeta_hash_invalid"]
     63     );
     64     assert_eq!(
     65         projection.ask_marker().unwrap(),
     66         ["t".to_string(), " RADROOTS-ASK ".to_string()]
     67     );
     68 }
     69 
     70 #[test]
     71 fn photo_preserves_repeatable_fallbacks_and_ordered_unknown_fields() {
     72     let projection = project_inbound_post_parts(
     73         KIND_POST,
     74         &[qualifying_imeta(vec![
     75             "fallback https://cache-one.example/harvest.webp",
     76             "x-farm cultivar-strawberry",
     77             "fallback https://cache-two.example/harvest.webp",
     78             "future-field retained value",
     79         ])],
     80         "Harvest https://cdn.example/harvest.webp",
     81     )
     82     .unwrap();
     83     let media = &projection.imeta()[0];
     84 
     85     assert_eq!(
     86         projection.classification(),
     87         RadrootsPostClassification::PhotoUpdate
     88     );
     89     assert_eq!(
     90         media.fallbacks(),
     91         [
     92             "https://cache-one.example/harvest.webp".to_string(),
     93             "https://cache-two.example/harvest.webp".to_string(),
     94         ]
     95     );
     96     assert_eq!(
     97         media.unknown_fields(),
     98         [
     99             "x-farm cultivar-strawberry".to_string(),
    100             "future-field retained value".to_string(),
    101         ]
    102     );
    103     assert!(media.qualifies_photo());
    104 }
    105 
    106 #[test]
    107 fn duplicate_singletons_and_mixed_imeta_downgrade_to_update() {
    108     let mut duplicate = qualifying_imeta(Vec::new());
    109     duplicate.insert(
    110         3,
    111         "x bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".to_string(),
    112     );
    113     let malformed = vec![
    114         "imeta".to_string(),
    115         "url https://cdn.example/leaf.webp".to_string(),
    116         "x malformed".to_string(),
    117     ];
    118     let projection = project_inbound_post_parts(
    119         KIND_POST,
    120         &[duplicate, malformed],
    121         "Harvest https://cdn.example/harvest.webp and https://cdn.example/leaf.webp",
    122     )
    123     .unwrap();
    124 
    125     assert_eq!(
    126         projection.classification(),
    127         RadrootsPostClassification::Update
    128     );
    129     assert_eq!(
    130         diagnostic_codes(projection.diagnostics()),
    131         [
    132             "imeta_singleton_duplicate",
    133             "imeta_metadata_missing",
    134             "imeta_hash_invalid",
    135         ]
    136     );
    137 }
    138 
    139 #[test]
    140 fn duplicate_urls_and_excess_imeta_downgrade_to_update() {
    141     let duplicate = qualifying_imeta(Vec::new());
    142     let projection = project_inbound_post_parts(
    143         KIND_POST,
    144         &[duplicate.clone(), duplicate],
    145         "Harvest https://cdn.example/harvest.webp",
    146     )
    147     .unwrap();
    148     assert_eq!(
    149         projection.classification(),
    150         RadrootsPostClassification::Update
    151     );
    152     assert_eq!(
    153         diagnostic_codes(projection.diagnostics()),
    154         ["duplicate_imeta_url"]
    155     );
    156 
    157     let imeta = qualifying_imeta(Vec::new());
    158     let tags = vec![imeta; RADROOTS_POST_IMETA_MAX_COUNT + 1];
    159     let projection =
    160         project_inbound_post_parts(KIND_POST, &tags, "Harvest https://cdn.example/harvest.webp")
    161             .unwrap();
    162     assert_eq!(
    163         projection.classification(),
    164         RadrootsPostClassification::Update
    165     );
    166     assert_eq!(
    167         projection.diagnostics().first(),
    168         Some(&RadrootsPostDiagnostic::ImetaCountExceeded)
    169     );
    170 }
    171 
    172 #[test]
    173 fn invalid_imeta_fields_report_stable_ordered_diagnostics() {
    174     let projection = project_inbound_post_parts(
    175         KIND_POST,
    176         &[vec![
    177             "imeta".to_string(),
    178             "url ftp://cdn.example/harvest.webp".to_string(),
    179             "x AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".to_string(),
    180             "m image/webp;quality=90".to_string(),
    181             "dim 01x0".to_string(),
    182             "size 0".to_string(),
    183             "alt \t".to_string(),
    184             "fallback file:///harvest.webp".to_string(),
    185         ]],
    186         "Harvest ftp://cdn.example/harvest.webp",
    187     )
    188     .unwrap();
    189 
    190     assert_eq!(
    191         projection.classification(),
    192         RadrootsPostClassification::Update
    193     );
    194     assert_eq!(
    195         diagnostic_codes(projection.diagnostics()),
    196         [
    197             "imeta_url_invalid",
    198             "imeta_hash_invalid",
    199             "imeta_mime_invalid",
    200             "imeta_dimensions_invalid",
    201             "imeta_size_invalid",
    202             "imeta_alt_invalid",
    203             "imeta_fallback_url_invalid",
    204         ]
    205     );
    206 }
    207 
    208 #[test]
    209 fn malformed_fields_and_oversized_alt_never_qualify_photo() {
    210     let oversized_alt = "a".repeat(RADROOTS_POST_ALT_MAX_BYTES + 1);
    211     let mut tag = qualifying_imeta(Vec::new());
    212     tag.push("malformed".to_string());
    213     tag[6] = format!("alt {oversized_alt}");
    214     let projection = project_inbound_post_parts(
    215         KIND_POST,
    216         &[tag],
    217         "Harvest https://cdn.example/harvest.webp",
    218     )
    219     .unwrap();
    220 
    221     assert_eq!(
    222         projection.classification(),
    223         RadrootsPostClassification::Update
    224     );
    225     assert_eq!(
    226         diagnostic_codes(projection.diagnostics()),
    227         ["imeta_field_invalid", "imeta_alt_too_large"]
    228     );
    229 }
    230 
    231 #[test]
    232 fn malformed_and_duplicate_normalized_ask_markers_are_distinct() {
    233     let malformed = project_inbound_post_parts(
    234         KIND_POST,
    235         &[vec![
    236             "t".to_string(),
    237             "RADROOTS-ASK".to_string(),
    238             "extra".to_string(),
    239         ]],
    240         "Question",
    241     )
    242     .unwrap();
    243     assert_eq!(
    244         malformed.classification(),
    245         RadrootsPostClassification::Update
    246     );
    247     assert_eq!(
    248         diagnostic_codes(malformed.diagnostics()),
    249         ["ask_marker_shape"]
    250     );
    251 
    252     let error = project_inbound_post_parts(
    253         KIND_POST,
    254         &[
    255             vec!["t".to_string(), "radroots-ask".to_string()],
    256             vec!["t".to_string(), " RADROOTS-ASK ".to_string()],
    257         ],
    258         "Question",
    259     )
    260     .unwrap_err();
    261     assert_eq!(error.code(), "ask_marker_count");
    262 }
    263 
    264 #[test]
    265 fn empty_inbound_root_is_update_without_becoming_valid_authored_content() {
    266     let projection = project_inbound_post_parts(KIND_POST, &[], "\t").unwrap();
    267     assert_eq!(
    268         projection.classification(),
    269         RadrootsPostClassification::Update
    270     );
    271     assert!(AuthoredUpdate::new("\t").is_err());
    272 }
    273 
    274 #[test]
    275 fn projection_rejects_wrong_kind_and_oversized_content() {
    276     assert_eq!(
    277         project_inbound_post_parts(20, &[], "photo")
    278             .unwrap_err()
    279             .code(),
    280         "invalid_kind"
    281     );
    282     let oversized = "x".repeat(RADROOTS_POST_CONTENT_MAX_BYTES + 1);
    283     assert_eq!(
    284         project_inbound_post_parts(KIND_POST, &[], &oversized)
    285             .unwrap_err()
    286             .code(),
    287         "post_content_too_large"
    288     );
    289 }
    290 
    291 fn qualifying_imeta(extra: Vec<&str>) -> Vec<String> {
    292     let mut tag = vec![
    293         "imeta".to_string(),
    294         "url https://cdn.example/harvest.webp".to_string(),
    295         "x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_string(),
    296         "m image/webp".to_string(),
    297         "dim 1200x900".to_string(),
    298         "size 12345".to_string(),
    299         "alt Harvest".to_string(),
    300     ];
    301     tag.extend(extra.into_iter().map(str::to_string));
    302     tag
    303 }
    304 
    305 fn diagnostic_codes(diagnostics: &[RadrootsPostDiagnostic]) -> Vec<&'static str> {
    306     diagnostics
    307         .iter()
    308         .map(|diagnostic| diagnostic.code())
    309         .collect()
    310 }