lib

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

geochat.rs (7487B)


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