use testsyn::{parse_str, Item}; use json_typegen_shared::{codegen, ImportStyle, Options}; /// Function to test AST equality, not string equality fn code_output_test(name: &str, input: &str, expected: &str) { let mut options = Options::default(); options.import_style = ImportStyle::AssumeExisting; let res = codegen(name, input, options); let output = res.unwrap(); assert_eq!( // Wrapping in mod Foo { } since there is no impl Parse for Vec parse_str::(&format!("mod Foo {{ {} }}", &output)).unwrap(), parse_str::(&format!("mod Foo {{ {} }}", expected)).unwrap(), "\n\nUnexpected output code:\n input: {}\n output:\n{}\n expected: {}", input, output, expected ); } #[test] fn empty_object() { code_output_test( "Root", r##" {} "##, r##" #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Root {} "##, ); } #[test] fn list_of_numbers() { code_output_test( "Numbers", r##" [1, 2, 3] "##, r##" pub type Numbers = Vec; "##, ); } #[test] fn point() { code_output_test( "Point", r##" { "x": 2, "y": 3 } "##, r##" #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Point { pub x: i64, pub y: i64, } "##, ); } #[test] fn pub_crate_point() { code_output_test( "pub(crate) Point", r##" { "x": 2, "y": 3 } "##, r##" #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub(crate) struct Point { pub x: i64, pub y: i64, } "##, ); } #[test] fn optionals() { code_output_test( "Optionals", r##" [ { "in_both": 5, "missing": 5, "has_null": 5 }, { "in_both": 5, "has_null": null, "added": 5 } ] "##, r##" pub type Optionals = Vec; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Optional { pub in_both: i64, pub missing: Option, pub has_null: Option, pub added: Option, } "##, ); } #[test] fn fallback() { code_output_test( "FallbackExamples", r##" [ { "only_null": null, "conflicting": 5, "empty_array": [] }, { "only_null": null, "conflicting": "five", "empty_array": [] } ] "##, r##" pub type FallbackExamples = Vec; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct FallbackExample { pub only_null: Value, pub conflicting: Value, pub empty_array: Vec, } "##, ); } #[test] fn nesting() { code_output_test( "NestedTypes", r##" [ { "nested": { "a": 5, "doubly_nested": { "c": 10 } }, "in_array": [{ "b": 5 }] } ] "##, r##" pub type NestedTypes = Vec; #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct NestedType { pub nested: Nested, pub in_array: Vec, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Nested { pub a: i64, pub doubly_nested: DoublyNested, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct DoublyNested { pub c: i64, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct InArray { pub b: i64, } "##, ); } #[test] fn tuple() { code_output_test( "Pagination", r##" [ { "pages": 1, "items": 3 }, [ { "name": "John" }, { "name": "James" }, { "name": "Jake" } ] ] "##, r##" pub type Pagination = (Pagination2, Vec); #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Pagination2 { pub pages: i64, pub items: i64, } #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Pagination3 { pub name : String, } "##, ); } #[test] fn rename() { code_output_test( "Renamed", r##" { "type": 5 } "##, r##" #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Renamed { #[serde(rename = "type")] pub type_field: i64, } "##, ); }