lib

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

geochat.rs (7413B)


      1 use radroots_events::{
      2     geochat::RadrootsGeoChat,
      3     kinds::{KIND_GEOCHAT, KIND_POST},
      4 };
      5 use radroots_events_codec::error::{EventEncodeError, EventParseError};
      6 use radroots_events_codec::geochat::decode::{
      7     data_from_event, geochat_from_tags, parsed_from_event,
      8 };
      9 use radroots_events_codec::geochat::encode::{geochat_build_tags, to_wire_parts};
     10 
     11 #[test]
     12 fn geochat_build_tags_requires_geohash() {
     13     let geochat = RadrootsGeoChat {
     14         geohash: "  ".to_string(),
     15         content: "hello".to_string(),
     16         nickname: None,
     17         teleported: false,
     18     };
     19 
     20     let err = geochat_build_tags(&geochat).unwrap_err();
     21     assert!(matches!(
     22         err,
     23         EventEncodeError::EmptyRequiredField("geohash")
     24     ));
     25 }
     26 
     27 #[test]
     28 fn geochat_build_tags_requires_nickname_if_present() {
     29     let geochat = RadrootsGeoChat {
     30         geohash: "dr5rsj7".to_string(),
     31         content: "hello".to_string(),
     32         nickname: Some(" ".to_string()),
     33         teleported: false,
     34     };
     35 
     36     let err = geochat_build_tags(&geochat).unwrap_err();
     37     assert!(matches!(
     38         err,
     39         EventEncodeError::EmptyRequiredField("nickname")
     40     ));
     41 }
     42 
     43 #[test]
     44 fn geochat_build_tags_omits_optional_nickname_and_teleport_when_disabled() {
     45     let geochat = RadrootsGeoChat {
     46         geohash: "dr5rsj7".to_string(),
     47         content: "hello".to_string(),
     48         nickname: None,
     49         teleported: false,
     50     };
     51 
     52     let tags = geochat_build_tags(&geochat).unwrap();
     53     assert_eq!(tags, vec![vec!["g".to_string(), "dr5rsj7".to_string()]]);
     54 }
     55 
     56 #[test]
     57 fn geochat_to_wire_parts_requires_content() {
     58     let geochat = RadrootsGeoChat {
     59         geohash: "dr5rsj7".to_string(),
     60         content: "  ".to_string(),
     61         nickname: None,
     62         teleported: false,
     63     };
     64 
     65     let err = to_wire_parts(&geochat).unwrap_err();
     66     assert!(matches!(
     67         err,
     68         EventEncodeError::EmptyRequiredField("content")
     69     ));
     70 
     71     let geochat = RadrootsGeoChat {
     72         geohash: " ".to_string(),
     73         content: "hello".to_string(),
     74         nickname: None,
     75         teleported: false,
     76     };
     77     let err = to_wire_parts(&geochat).unwrap_err();
     78     assert!(matches!(
     79         err,
     80         EventEncodeError::EmptyRequiredField("geohash")
     81     ));
     82 }
     83 
     84 #[test]
     85 fn geochat_to_wire_parts_sets_tags() {
     86     let geochat = RadrootsGeoChat {
     87         geohash: "dr5rsj7".to_string(),
     88         content: "hello".to_string(),
     89         nickname: Some("alex".to_string()),
     90         teleported: true,
     91     };
     92 
     93     let parts = to_wire_parts(&geochat).unwrap();
     94     assert_eq!(parts.kind, KIND_GEOCHAT);
     95     assert_eq!(parts.content, "hello");
     96     assert_eq!(
     97         parts.tags,
     98         vec![
     99             vec!["g".to_string(), "dr5rsj7".to_string()],
    100             vec!["n".to_string(), "alex".to_string()],
    101             vec!["t".to_string(), "teleport".to_string()],
    102         ]
    103     );
    104 }
    105 
    106 #[test]
    107 fn geochat_from_tags_requires_kind_geohash_and_content() {
    108     let tags = vec![vec!["g".to_string(), "dr5rsj7".to_string()]];
    109     let err = geochat_from_tags(KIND_POST, &tags, "hello").unwrap_err();
    110     assert!(matches!(
    111         err,
    112         EventParseError::InvalidKind {
    113             expected: "20000",
    114             got: KIND_POST
    115         }
    116     ));
    117 
    118     let err = geochat_from_tags(KIND_GEOCHAT, &tags, "  ").unwrap_err();
    119     assert!(matches!(err, EventParseError::InvalidTag("content")));
    120 
    121     let err = geochat_from_tags(KIND_GEOCHAT, &[], "hello").unwrap_err();
    122     assert!(matches!(err, EventParseError::MissingTag("g")));
    123 }
    124 
    125 #[test]
    126 fn geochat_roundtrip_from_tags() {
    127     let tags = vec![
    128         vec!["g".to_string(), "dr5rsj7".to_string()],
    129         vec!["n".to_string(), "alex".to_string()],
    130         vec!["t".to_string(), "teleport".to_string()],
    131     ];
    132 
    133     let geochat = geochat_from_tags(KIND_GEOCHAT, &tags, "hello").unwrap();
    134 
    135     assert_eq!(geochat.geohash, "dr5rsj7");
    136     assert_eq!(geochat.content, "hello");
    137     assert_eq!(geochat.nickname.as_deref(), Some("alex"));
    138     assert!(geochat.teleported);
    139 }
    140 
    141 #[test]
    142 fn geochat_from_tags_rejects_invalid_optional_tags() {
    143     let err = geochat_from_tags(
    144         KIND_GEOCHAT,
    145         &[vec!["g".to_string(), " ".to_string()]],
    146         "hello",
    147     )
    148     .unwrap_err();
    149     assert!(matches!(err, EventParseError::InvalidTag("g")));
    150 
    151     let err = geochat_from_tags(
    152         KIND_GEOCHAT,
    153         &[
    154             vec!["g".to_string(), "dr5rsj7".to_string()],
    155             vec!["n".to_string(), " ".to_string()],
    156         ],
    157         "hello",
    158     )
    159     .unwrap_err();
    160     assert!(matches!(err, EventParseError::InvalidTag("n")));
    161 
    162     let err = geochat_from_tags(
    163         KIND_GEOCHAT,
    164         &[
    165             vec!["g".to_string(), "dr5rsj7".to_string()],
    166             vec!["t".to_string(), " ".to_string()],
    167         ],
    168         "hello",
    169     )
    170     .unwrap_err();
    171     assert!(matches!(err, EventParseError::InvalidTag("t")));
    172 
    173     let geochat = geochat_from_tags(
    174         KIND_GEOCHAT,
    175         &[
    176             vec!["g".to_string(), "dr5rsj7".to_string()],
    177             vec!["t".to_string(), "moving".to_string()],
    178         ],
    179         "hello",
    180     )
    181     .unwrap();
    182     assert!(!geochat.teleported);
    183 }
    184 
    185 #[test]
    186 fn geochat_from_tags_rejects_missing_tag_values() {
    187     let err = geochat_from_tags(KIND_GEOCHAT, &[vec!["g".to_string()]], "hello").unwrap_err();
    188     assert!(matches!(err, EventParseError::InvalidTag("g")));
    189 
    190     let err = geochat_from_tags(
    191         KIND_GEOCHAT,
    192         &[
    193             vec!["g".to_string(), "dr5rsj7".to_string()],
    194             vec!["n".to_string()],
    195         ],
    196         "hello",
    197     )
    198     .unwrap_err();
    199     assert!(matches!(err, EventParseError::InvalidTag("n")));
    200 
    201     let err = geochat_from_tags(
    202         KIND_GEOCHAT,
    203         &[
    204             vec!["g".to_string(), "dr5rsj7".to_string()],
    205             vec!["t".to_string()],
    206         ],
    207         "hello",
    208     )
    209     .unwrap_err();
    210     assert!(matches!(err, EventParseError::InvalidTag("t")));
    211 }
    212 
    213 #[test]
    214 fn geochat_metadata_and_index_from_event_roundtrip() {
    215     let tags = vec![
    216         vec!["g".to_string(), "dr5rsj7".to_string()],
    217         vec!["n".to_string(), "alex".to_string()],
    218         vec!["t".to_string(), "teleport".to_string()],
    219     ];
    220     let metadata = data_from_event(
    221         "id".to_string(),
    222         "author".to_string(),
    223         77,
    224         KIND_GEOCHAT,
    225         "hello".to_string(),
    226         tags.clone(),
    227     )
    228     .unwrap();
    229     assert_eq!(metadata.id, "id");
    230     assert_eq!(metadata.author, "author");
    231     assert_eq!(metadata.published_at, 77);
    232     assert_eq!(metadata.kind, KIND_GEOCHAT);
    233     assert_eq!(metadata.data.geohash, "dr5rsj7");
    234     assert!(metadata.data.teleported);
    235 
    236     let index = parsed_from_event(
    237         "id".to_string(),
    238         "author".to_string(),
    239         77,
    240         KIND_GEOCHAT,
    241         "hello".to_string(),
    242         tags,
    243         "sig".to_string(),
    244     )
    245     .unwrap();
    246     assert_eq!(index.event.kind, KIND_GEOCHAT);
    247     assert_eq!(index.event.sig, "sig");
    248     assert_eq!(index.data.data.geohash, "dr5rsj7");
    249 }
    250 
    251 #[test]
    252 fn geochat_index_from_event_propagates_parse_errors() {
    253     let err = parsed_from_event(
    254         "id".to_string(),
    255         "author".to_string(),
    256         77,
    257         KIND_POST,
    258         "hello".to_string(),
    259         vec![vec!["g".to_string(), "dr5rsj7".to_string()]],
    260         "sig".to_string(),
    261     )
    262     .unwrap_err();
    263     assert!(matches!(
    264         err,
    265         EventParseError::InvalidKind {
    266             expected: "20000",
    267             got: KIND_POST
    268         }
    269     ));
    270 }