A better Rust ATProto crate
at oauth 3.8 kB view raw
1use jacquard_derive::open_union; 2use serde::{Deserialize, Serialize}; 3 4#[open_union] 5#[derive(Serialize, Deserialize, Debug, PartialEq)] 6#[serde(tag = "$type")] 7enum TestUnion<'s> { 8 #[serde(rename = "com.example.typeA")] 9 TypeA { value: &'s str }, 10 #[serde(rename = "com.example.typeB")] 11 TypeB { count: i64 }, 12} 13 14#[test] 15fn test_open_union_known_variant() { 16 let json = r#"{"$type":"com.example.typeA","value":"hello"}"#; 17 let union: TestUnion = serde_json::from_str(json).unwrap(); 18 19 match union { 20 TestUnion::TypeA { value } => assert_eq!(value, "hello"), 21 _ => panic!("expected TypeA"), 22 } 23} 24 25#[test] 26fn test_open_union_unknown_variant() { 27 use jacquard_common::types::value::Data; 28 29 let json = r#"{"$type":"com.example.unknown","data":"something"}"#; 30 let union: TestUnion = serde_json::from_str(json).unwrap(); 31 32 match union { 33 TestUnion::Unknown(Data::Object(obj)) => { 34 // Verify the captured data contains the expected fields 35 assert!(obj.0.contains_key("$type")); 36 assert!(obj.0.contains_key("data")); 37 38 // Check the actual values 39 if let Some(Data::String(type_str)) = obj.0.get("$type") { 40 assert_eq!(type_str.as_str(), "com.example.unknown"); 41 } else { 42 panic!("expected $type field to be a string"); 43 } 44 45 if let Some(Data::String(data_str)) = obj.0.get("data") { 46 assert_eq!(data_str.as_str(), "something"); 47 } else { 48 panic!("expected data field to be a string"); 49 } 50 } 51 _ => panic!("expected Unknown variant with Object data"), 52 } 53} 54 55#[test] 56fn test_open_union_roundtrip() { 57 let union = TestUnion::TypeB { count: 42 }; 58 let json = serde_json::to_string(&union).unwrap(); 59 let parsed: TestUnion = serde_json::from_str(&json).unwrap(); 60 61 assert_eq!(union, parsed); 62 63 // Verify the $type field is present 64 assert!(json.contains(r#""$type":"com.example.typeB""#)); 65} 66 67#[test] 68fn test_open_union_unknown_roundtrip() { 69 use jacquard_common::types::value::{Data, Object}; 70 use std::collections::BTreeMap; 71 72 // Create an Unknown variant with complex data 73 let mut map = BTreeMap::new(); 74 map.insert( 75 "$type".into(), 76 Data::String(jacquard_common::types::string::AtprotoStr::String( 77 "com.example.custom".into(), 78 )), 79 ); 80 map.insert("field1".into(), Data::Integer(123)); 81 map.insert("field2".into(), Data::Boolean(false)); 82 83 let union = TestUnion::Unknown(Data::Object(Object(map))); 84 85 let json = serde_json::to_string(&union).unwrap(); 86 let parsed: TestUnion = serde_json::from_str(&json).unwrap(); 87 88 // Should deserialize back as Unknown since the type is not recognized 89 match parsed { 90 TestUnion::Unknown(Data::Object(obj)) => { 91 assert_eq!(obj.0.len(), 3); 92 assert!(obj.0.contains_key("$type")); 93 assert!(obj.0.contains_key("field1")); 94 assert!(obj.0.contains_key("field2")); 95 96 // Verify values 97 if let Some(Data::String(s)) = obj.0.get("$type") { 98 assert_eq!(s.as_str(), "com.example.custom"); 99 } else { 100 panic!("expected $type to be a string"); 101 } 102 103 if let Some(Data::Integer(n)) = obj.0.get("field1") { 104 assert_eq!(*n, 123); 105 } else { 106 panic!("expected field1 to be an integer"); 107 } 108 109 if let Some(Data::Boolean(b)) = obj.0.get("field2") { 110 assert_eq!(*b, false); 111 } else { 112 panic!("expected field2 to be a boolean"); 113 } 114 } 115 _ => panic!("expected Unknown variant"), 116 } 117}