A better Rust ATProto crate
1use jacquard_derive::lexicon; 2use serde::{Deserialize, Serialize}; 3 4#[lexicon] 5#[derive(Serialize, Deserialize, Debug, PartialEq)] 6#[serde(rename_all = "camelCase")] 7struct TestRecord<'s> { 8 text: &'s str, 9 count: i64, 10} 11 12#[test] 13fn test_lexicon_adds_extra_data_field() { 14 let json = r#"{"text":"hello","count":42,"unknown":"field","another":123}"#; 15 16 let record: TestRecord = serde_json::from_str(json).unwrap(); 17 18 assert_eq!(record.text, "hello"); 19 assert_eq!(record.count, 42); 20 assert_eq!(record.extra_data.len(), 2); 21 assert!(record.extra_data.contains_key("unknown")); 22 assert!(record.extra_data.contains_key("another")); 23} 24 25#[test] 26fn test_lexicon_roundtrip() { 27 use jacquard_common::CowStr; 28 use jacquard_common::types::value::Data; 29 use std::collections::BTreeMap; 30 31 let mut extra = BTreeMap::new(); 32 extra.insert( 33 "custom".into(), 34 Data::String(jacquard_common::types::string::AtprotoStr::String( 35 CowStr::Borrowed("value"), 36 )), 37 ); 38 extra.insert( 39 "number".into(), 40 Data::Integer(42), 41 ); 42 extra.insert( 43 "nested".into(), 44 Data::Object(jacquard_common::types::value::Object({ 45 let mut nested_map = BTreeMap::new(); 46 nested_map.insert( 47 "inner".into(), 48 Data::Boolean(true), 49 ); 50 nested_map 51 })), 52 ); 53 54 let record = TestRecord { 55 text: "test", 56 count: 100, 57 extra_data: extra, 58 }; 59 60 let json = serde_json::to_string(&record).unwrap(); 61 let parsed: TestRecord = serde_json::from_str(&json).unwrap(); 62 63 assert_eq!(record, parsed); 64 assert_eq!(parsed.extra_data.len(), 3); 65 66 // Verify the extra fields were preserved 67 assert!(parsed.extra_data.contains_key("custom")); 68 assert!(parsed.extra_data.contains_key("number")); 69 assert!(parsed.extra_data.contains_key("nested")); 70 71 // Verify the values 72 if let Some(Data::String(s)) = parsed.extra_data.get("custom") { 73 assert_eq!(s.as_str(), "value"); 74 } else { 75 panic!("expected custom field to be a string"); 76 } 77 78 if let Some(Data::Integer(n)) = parsed.extra_data.get("number") { 79 assert_eq!(*n, 42); 80 } else { 81 panic!("expected number field to be an integer"); 82 } 83 84 if let Some(Data::Object(obj)) = parsed.extra_data.get("nested") { 85 assert!(obj.0.contains_key("inner")); 86 } else { 87 panic!("expected nested field to be an object"); 88 } 89}