A better Rust ATProto crate
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: ensure deterministic field ordering in builder state types

+43 -40
+4 -2
crates/jacquard-lexicon/src/codegen/builder_gen/state_mod.rs
··· 13 13 use crate::codegen::utils::make_ident; 14 14 15 15 /// Information about a required field for builder state generation 16 - #[derive(Debug, Clone, Hash, PartialEq, Eq)] 16 + #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] 17 17 pub struct RequiredField { 18 18 /// Field name (snake_case) 19 19 pub name_snake: SmolStr, ··· 47 47 }) 48 48 .collect(); 49 49 50 - set.into_iter().collect() 50 + let mut fields: Vec<_> = set.into_iter().collect(); 51 + fields.sort(); 52 + fields 51 53 } 52 54 53 55 /// Generate the complete state module for a builder
+39 -38
crates/jacquard-lexicon/src/codegen/builder_gen/tests.rs
··· 46 46 let _parsed: syn::File = syn::parse2(tokens).expect("Generated code should parse"); 47 47 } 48 48 49 - // TODO: re-enable these tests once i have time to get them to properly check and not be order-dependent 50 - // #[test] 51 - // fn test_collect_required_fields_object() { 52 - // let obj = LexObject { 53 - // description: None, 54 - // required: Some(vec![ 55 - // SmolStr::new_static("foo"), 56 - // SmolStr::new_static("barBaz"), 57 - // ]), 58 - // nullable: None, 59 - // properties: Default::default(), 60 - // }; 49 + #[test] 50 + fn test_collect_required_fields_object() { 51 + let obj = LexObject { 52 + description: None, 53 + required: Some(vec![ 54 + SmolStr::new_static("foo"), 55 + SmolStr::new_static("barBaz"), 56 + ]), 57 + nullable: None, 58 + properties: Default::default(), 59 + }; 61 60 62 - // let schema = BuilderSchema::Object(&obj); 63 - // let fields = collect_required_fields(&schema); 61 + let schema = BuilderSchema::Object(&obj); 62 + let fields = collect_required_fields(&schema); 64 63 65 - // assert_eq!(fields.len(), 2); 66 - // assert_eq!(fields[0].name_snake, "foo"); 67 - // assert_eq!(fields[0].name_pascal, "Foo"); 68 - // assert_eq!(fields[1].name_snake, "bar_baz"); 69 - // assert_eq!(fields[1].name_pascal, "BarBaz"); 70 - // } 64 + assert_eq!(fields.len(), 2); 65 + // bar_baz comes before foo alphabetically 66 + assert_eq!(fields[0].name_snake, "bar_baz"); 67 + assert_eq!(fields[0].name_pascal, "BarBaz"); 68 + assert_eq!(fields[1].name_snake, "foo"); 69 + assert_eq!(fields[1].name_pascal, "Foo"); 70 + } 71 71 72 - // #[test] 73 - // fn test_collect_required_fields_parameters() { 74 - // let params = LexXrpcParameters { 75 - // description: None, 76 - // required: Some(vec![ 77 - // SmolStr::new_static("limit"), 78 - // SmolStr::new_static("cursor"), 79 - // ]), 80 - // properties: Default::default(), 81 - // }; 72 + #[test] 73 + fn test_collect_required_fields_parameters() { 74 + let params = LexXrpcParameters { 75 + description: None, 76 + required: Some(vec![ 77 + SmolStr::new_static("limit"), 78 + SmolStr::new_static("cursor"), 79 + ]), 80 + properties: Default::default(), 81 + }; 82 82 83 - // let schema = BuilderSchema::Parameters(&params); 84 - // let fields = collect_required_fields(&schema); 83 + let schema = BuilderSchema::Parameters(&params); 84 + let fields = collect_required_fields(&schema); 85 85 86 - // assert_eq!(fields.len(), 2); 87 - // assert_eq!(fields[1].name_snake, "limit"); 88 - // assert_eq!(fields[1].name_pascal, "Limit"); 89 - // assert_eq!(fields[0].name_snake, "cursor"); 90 - // assert_eq!(fields[0].name_pascal, "Cursor"); 91 - // } 86 + assert_eq!(fields.len(), 2); 87 + // cursor comes before limit alphabetically 88 + assert_eq!(fields[0].name_snake, "cursor"); 89 + assert_eq!(fields[0].name_pascal, "Cursor"); 90 + assert_eq!(fields[1].name_snake, "limit"); 91 + assert_eq!(fields[1].name_pascal, "Limit"); 92 + } 92 93 93 94 #[test] 94 95 fn test_state_module_generation() {