use std::convert::TryInto; use serde_lite::{intermediate, Deserialize, Error, Intermediate, Map, Number, Serialize, Update}; use serde_lite_derive::{Deserialize, Serialize, Update}; #[test] fn test_struct_deserialize() { let input = intermediate!({ "number": 33, "hello": "hello", }); #[derive(Deserialize)] struct OuterStruct { #[serde(flatten)] inner: InnerStruct, } #[derive(Deserialize)] struct InnerStruct { number: u32, #[serde(rename = "hello")] greetings: String, #[serde(default)] foo: Option, } let output = OuterStruct::deserialize(&input).unwrap(); assert_eq!(output.inner.number, 33); assert_eq!(output.inner.greetings.as_str(), "hello"); assert!(output.inner.foo.is_none()); assert!(OuterStruct::deserialize(&Intermediate::None).is_err()); } #[test] fn test_struct_update() { let input = intermediate!({ "number": 33, "hello": "hi", }); #[derive(Deserialize, Update)] struct OuterStruct { #[serde(flatten)] inner: InnerStruct, } #[derive(Deserialize, Update)] struct InnerStruct { number: u32, #[serde(rename = "hello")] greetings: String, year: u32, } let mut instance = OuterStruct { inner: InnerStruct { number: 0, greetings: String::new(), year: 2021, }, }; instance.update(&input).unwrap(); assert_eq!(instance.inner.number, 33); assert_eq!(instance.inner.greetings.as_str(), "hi"); assert_eq!(instance.inner.year, 2021); assert!(instance.update(&Intermediate::None).is_err()); } #[test] fn test_tuple_struct_deserialize() { let input1 = intermediate!(10); let input2 = intermediate!([10]); #[derive(Deserialize)] struct SingleElementTuple(u32); let output1 = SingleElementTuple::deserialize(&input1).unwrap(); assert_eq!(output1.0, 10); assert!(SingleElementTuple::deserialize(&input2).is_err()); #[derive(Deserialize)] struct MultiElementStruct(u32, String); let input = intermediate!([32, "hello"]); let output = MultiElementStruct::deserialize(&input).unwrap(); assert_eq!(output.0, 32); assert_eq!(output.1.as_str(), "hello"); assert!(MultiElementStruct::deserialize(&Intermediate::Array(vec![])).is_err()); } #[test] fn test_tuple_struct_update() { let input1 = intermediate!(10); let input2 = intermediate!([20]); #[derive(Deserialize, Update)] struct SingleElementTuple(u32); let mut instance = SingleElementTuple(0); instance.update(&input1).unwrap(); assert_eq!(instance.0, 10); assert!(instance.update(&input2).is_err()); #[derive(Deserialize, Update)] struct MultiElementStruct(u32, String); let input = intermediate!([32, "hello"]); let mut instance = MultiElementStruct(0, String::new()); instance.update(&input).unwrap(); assert_eq!(instance.0, 32); assert_eq!(instance.1.as_str(), "hello"); assert!(instance.update(&Intermediate::Array(vec![])).is_err()); } #[test] fn test_empty_struct_deserialize() { #[derive(Deserialize)] struct UnitStruct; #[derive(Deserialize)] struct EmptyStruct {} #[derive(Deserialize)] struct EmptyTupleStruct(); assert!(UnitStruct::deserialize(&Intermediate::None).is_ok()); assert!(EmptyStruct::deserialize(&Intermediate::None).is_ok()); assert!(EmptyTupleStruct::deserialize(&Intermediate::None).is_ok()); } #[test] fn test_empty_struct_update() { #[derive(Deserialize, Update)] struct UnitStruct; #[derive(Deserialize, Update)] struct EmptyStruct {} #[derive(Deserialize, Update)] struct EmptyTupleStruct(); let mut unit = UnitStruct; let mut empty = EmptyStruct {}; let mut empty_tuple = EmptyTupleStruct(); assert!(unit.update(&Intermediate::None).is_ok()); assert!(empty.update(&Intermediate::None).is_ok()); assert!(empty_tuple.update(&Intermediate::None).is_ok()); } #[test] fn test_enum_deserialize() { let input1 = intermediate!("Variant1"); let input2 = intermediate!({ "Variant1": null, }); let input3 = intermediate!({ "variant2": 20, }); let input4 = intermediate!({ "variant2": [20], }); let input5 = intermediate!({ "Variant3": { "field1": 10, "field2": "hello", }, }); let input6 = intermediate!("foo"); let input7 = intermediate!(null); let input8 = intermediate!({ "Variant4": [], }); let input9 = intermediate!({ "Variant4": [123], }); #[derive(Deserialize)] enum TestEnum { Variant1, #[serde(rename = "variant2")] Variant2(u32), Variant3 { field1: u32, field2: String, }, Variant4(Vec), } let output1 = TestEnum::deserialize(&input1).unwrap(); let output2 = TestEnum::deserialize(&input2).unwrap(); let output3 = TestEnum::deserialize(&input3).unwrap(); let output5 = TestEnum::deserialize(&input5).unwrap(); let output8 = TestEnum::deserialize(&input8).unwrap(); let output9 = TestEnum::deserialize(&input9).unwrap(); assert!(matches!(output1, TestEnum::Variant1)); assert!(matches!(output2, TestEnum::Variant1)); if let TestEnum::Variant2(n) = output3 { assert_eq!(n, 20); } else { panic!("output3 test failed"); } if let TestEnum::Variant3 { field1, field2 } = output5 { assert_eq!(field1, 10); assert_eq!(field2.as_str(), "hello"); } else { panic!("output4 test failed"); } assert!(TestEnum::deserialize(&input4).is_err()); assert!(TestEnum::deserialize(&input6).is_err()); assert!(TestEnum::deserialize(&input7).is_err()); if let TestEnum::Variant4(arr) = output8 { assert_eq!(arr.as_slice(), &[][..]); } else { panic!("output8 test failed"); } if let TestEnum::Variant4(arr) = output9 { assert_eq!(arr.as_slice(), &[123][..]); } else { panic!("output9 test failed"); } } #[test] fn test_enum_update() { let input1 = intermediate!("Variant1"); let input2 = intermediate!({ "Variant1": null, }); let input3 = intermediate!({ "variant2": 20, }); let input4 = intermediate!({ "variant2": [40], }); let input5 = intermediate!({ "Variant3": { "field1": 20, }, }); let input6 = intermediate!("foo"); let input7 = intermediate!(null); let input8 = intermediate!({ "Variant4": [], }); let input9 = intermediate!({ "Variant4": [456], }); #[derive(Deserialize, Update)] enum TestEnum { Variant1, #[serde(rename = "variant2")] Variant2(u32), Variant3 { field1: u32, field2: String, }, Variant4(Vec), } let mut instance = TestEnum::Variant2(0); instance.update(&input1).unwrap(); assert!(matches!(instance, TestEnum::Variant1)); let mut instance = TestEnum::Variant2(0); instance.update(&input2).unwrap(); assert!(matches!(instance, TestEnum::Variant1)); let mut instance = TestEnum::Variant1; instance.update(&input3).unwrap(); if let TestEnum::Variant2(n) = &instance { assert_eq!(*n, 20); } else { panic!("test failed"); } assert!(instance.update(&input4).is_err()); let mut instance = TestEnum::Variant1; assert!(instance.update(&input5).is_err()); let mut instance = TestEnum::Variant3 { field1: 0, field2: String::new(), }; instance.update(&input5).unwrap(); if let TestEnum::Variant3 { field1, field2 } = instance { assert_eq!(field1, 20); assert_eq!(field2.as_str(), ""); } else { panic!("test failed"); } let mut instance = TestEnum::Variant1; assert!(instance.update(&input6).is_err()); assert!(instance.update(&input7).is_err()); let mut instance = TestEnum::Variant4(vec![33]); instance.update(&input8).unwrap(); if let TestEnum::Variant4(arr) = &instance { assert_eq!(arr.as_slice(), &[][..]); } else { panic!("test failed"); } instance.update(&input9).unwrap(); if let TestEnum::Variant4(arr) = instance { assert_eq!(arr.as_slice(), &[456][..]); } else { panic!("test failed"); } } #[test] fn test_internally_tagged_enum_deserialize_and_update() { #[derive(Deserialize, Update)] struct OuterStruct { field: TestEnum, } #[derive(Deserialize, Update)] #[serde(tag = "type")] enum TestEnum { Variant1, Variant2(InnerStruct), } #[derive(Deserialize, Update)] struct InnerStruct { field1: u32, field2: String, } let input = intermediate!({ "field": { "type": "Variant2", "field1": 10, "field2": "hello", }, }); let mut instance = OuterStruct::deserialize(&input).unwrap(); if let TestEnum::Variant2(inner) = &instance.field { assert_eq!(inner.field1, 10); assert_eq!(inner.field2.as_str(), "hello"); } else { panic!("test failed"); } let input = intermediate!({ "field": { "type": "Variant2", "field2": "world", }, }); instance.update(&input).unwrap(); if let TestEnum::Variant2(inner) = &instance.field { assert_eq!(inner.field1, 10); assert_eq!(inner.field2.as_str(), "world"); } else { panic!("test failed"); } } #[test] fn test_adjacently_tagged_enum_deserialize_and_update() { #[derive(Deserialize, Update)] struct OuterStruct { field: TestEnum, } #[derive(Deserialize, Update)] #[serde(tag = "type", content = "content")] enum TestEnum { Variant1, Variant2(InnerStruct), } #[derive(Deserialize, Update)] struct InnerStruct { field1: u32, field2: String, } let input = intermediate!({ "field": { "type": "Variant2", "content": { "field1": 10, "field2": "hello", }, }, }); let mut instance = OuterStruct::deserialize(&input).unwrap(); if let TestEnum::Variant2(inner) = &instance.field { assert_eq!(inner.field1, 10); assert_eq!(inner.field2.as_str(), "hello"); } else { panic!("test failed"); } let input = intermediate!({ "field": { "type": "Variant2", "content": { "field2": "world", }, }, }); instance.update(&input).unwrap(); if let TestEnum::Variant2(inner) = &instance.field { assert_eq!(inner.field1, 10); assert_eq!(inner.field2.as_str(), "world"); } else { panic!("test failed"); } } #[test] fn test_struct_serialize() { #[derive(Serialize)] struct OuterTestStruct { field1: u32, field2: InnerTestStruct, #[serde(flatten)] field3: InnerTestStruct, } #[derive(Serialize)] struct InnerTestStruct { inner1: bool, inner2: String, } let instance = OuterTestStruct { field1: 10, field2: InnerTestStruct { inner1: true, inner2: String::from("hello"), }, field3: InnerTestStruct { inner1: false, inner2: String::from("world"), }, }; let data = instance.serialize().unwrap(); let map = data.as_map().unwrap(); assert_eq!(map.len(), 4); assert_eq!(get_unsigned_int_field(map, "field1"), 10); let field2 = get_map_field(map, "field2"); assert_eq!(field2.len(), 2); assert_eq!(get_bool_field(field2, "inner1"), true); assert_eq!(get_str_field(field2, "inner2"), "hello"); assert_eq!(get_bool_field(map, "inner1"), false); assert_eq!(get_str_field(map, "inner2"), "world"); } #[test] fn test_externally_tagged_enum_serialize() { #[derive(Serialize)] struct OuterTestStruct { field5: ExternallyTaggedEnum, field6: ExternallyTaggedEnum, field7: ExternallyTaggedEnum, field8: ExternallyTaggedEnum, field9: ExternallyTaggedEnum, field10: ExternallyTaggedEnum, field11: ExternallyTaggedEnum, } #[derive(Serialize)] struct InnerTestStruct { inner1: bool, inner2: String, } #[derive(Serialize)] enum ExternallyTaggedEnum { Variant1, #[serde(rename = "v2")] Variant2(u32), Variant3(u32, String), Variant4 { field1: u32, #[serde(flatten)] field2: InnerTestStruct, }, Variant5(InnerTestStruct), Variant6(Vec), } let instance = OuterTestStruct { field5: ExternallyTaggedEnum::Variant1, field6: ExternallyTaggedEnum::Variant2(20), field7: ExternallyTaggedEnum::Variant3(30, String::from("sss")), field8: ExternallyTaggedEnum::Variant4 { field1: 40, field2: InnerTestStruct { inner1: true, inner2: String::from("zzz"), }, }, field9: ExternallyTaggedEnum::Variant5(InnerTestStruct { inner1: false, inner2: String::from("abc"), }), field10: ExternallyTaggedEnum::Variant6(vec![]), field11: ExternallyTaggedEnum::Variant6(vec![50]), }; let data = instance.serialize().unwrap(); let map = data.as_map().unwrap(); assert_eq!(get_str_field(map, "field5"), "Variant1"); let field6 = get_map_field(map, "field6"); assert_eq!(field6.len(), 1); assert_eq!(get_unsigned_int_field(field6, "v2"), 20); let field7 = get_map_field(map, "field7"); assert_eq!(field7.len(), 1); let arr = get_array_field(field7, "Variant3"); assert_eq!(arr.len(), 2); let n: u64 = arr[0].as_number().unwrap().try_into().unwrap(); assert_eq!(n, 30); assert_eq!(arr[1].as_str().unwrap(), "sss"); let field8 = get_map_field(map, "field8"); assert_eq!(field8.len(), 1); let inner = get_map_field(field8, "Variant4"); assert_eq!(inner.len(), 3); assert_eq!(get_unsigned_int_field(inner, "field1"), 40); assert_eq!(get_bool_field(inner, "inner1"), true); assert_eq!(get_str_field(inner, "inner2"), "zzz"); let field9 = get_map_field(map, "field9"); assert_eq!(field9.len(), 1); let inner = get_map_field(field9, "Variant5"); assert_eq!(inner.len(), 2); assert_eq!(get_bool_field(inner, "inner1"), false); assert_eq!(get_str_field(inner, "inner2"), "abc"); let field10 = get_map_field(map, "field10"); assert_eq!(field10.len(), 1); let arr = get_array_field(field10, "Variant6"); assert_eq!(arr.len(), 0); let field11 = get_map_field(map, "field11"); assert_eq!(field11.len(), 1); let arr = get_array_field(field11, "Variant6"); assert_eq!(arr.len(), 1); let n: u64 = arr[0].as_number().unwrap().try_into().unwrap(); assert_eq!(n, 50); } #[test] fn test_internally_tagged_enum_serialize() { #[derive(Serialize)] struct OuterTestStruct { field4: EnumContainerStruct, field10: InternallyTaggedEnum, field11: InternallyTaggedEnum, field12: InternallyTaggedEnum, } #[derive(Serialize)] struct InnerTestStruct { inner1: bool, inner2: String, } #[derive(Serialize)] struct EnumContainerStruct { e1: InternallyTaggedEnum, #[serde(flatten)] e2: InternallyTaggedEnum, } #[derive(Serialize)] #[serde(tag = "variant")] enum InternallyTaggedEnum { Variant1, #[serde(rename = "v2")] Variant2(u32), Variant3(u32, String), Variant4 { field1: u32, #[serde(flatten)] field2: InnerTestStruct, }, Variant5(InnerTestStruct), } let instance = OuterTestStruct { field4: EnumContainerStruct { e1: InternallyTaggedEnum::Variant4 { field1: 30, field2: InnerTestStruct { inner1: true, inner2: String::from("foo"), }, }, e2: InternallyTaggedEnum::Variant5(InnerTestStruct { inner1: false, inner2: String::from("bar"), }), }, field10: InternallyTaggedEnum::Variant1, field11: InternallyTaggedEnum::Variant4 { field1: 50, field2: InnerTestStruct { inner1: true, inner2: String::from("xyz"), }, }, field12: InternallyTaggedEnum::Variant5(InnerTestStruct { inner1: true, inner2: String::from("qwerty"), }), }; let data = instance.serialize().unwrap(); let map = data.as_map().unwrap(); let field4 = get_map_field(map, "field4"); assert_eq!(field4.len(), 4); let e1 = get_map_field(field4, "e1"); assert_eq!(e1.len(), 4); assert_eq!(get_str_field(e1, "variant"), "Variant4"); assert_eq!(get_unsigned_int_field(e1, "field1"), 30); assert_eq!(get_bool_field(e1, "inner1"), true); assert_eq!(get_str_field(e1, "inner2"), "foo"); assert_eq!(get_str_field(field4, "variant"), "Variant5"); assert_eq!(get_bool_field(field4, "inner1"), false); assert_eq!(get_str_field(field4, "inner2"), "bar"); let field10 = get_map_field(map, "field10"); assert_eq!(field10.len(), 1); assert_eq!(get_str_field(field10, "variant"), "Variant1"); let field11 = get_map_field(map, "field11"); assert_eq!(field11.len(), 4); assert_eq!(get_str_field(field11, "variant"), "Variant4"); assert_eq!(get_unsigned_int_field(field11, "field1"), 50); assert_eq!(get_bool_field(field11, "inner1"), true); assert_eq!(get_str_field(field11, "inner2"), "xyz"); let field12 = get_map_field(map, "field12"); assert_eq!(field12.len(), 3); assert_eq!(get_str_field(field12, "variant"), "Variant5"); assert_eq!(get_bool_field(field12, "inner1"), true); assert_eq!(get_str_field(field12, "inner2"), "qwerty"); let instance = InternallyTaggedEnum::Variant2(10); assert!(instance.serialize().is_err()); let instance = InternallyTaggedEnum::Variant3(20, String::from("foo")); assert!(instance.serialize().is_err()); } #[test] fn test_adjacently_tagged_enum_serialize() { #[derive(Serialize)] struct OuterTestStruct { field13: AdjacentlyTaggedEnum, field14: AdjacentlyTaggedEnum, } #[derive(Serialize)] #[serde(tag = "variant", content = "content")] enum AdjacentlyTaggedEnum { Variant1, Variant2(u32, String), } let instance = OuterTestStruct { field13: AdjacentlyTaggedEnum::Variant1, field14: AdjacentlyTaggedEnum::Variant2(60, String::from("asdf")), }; let data = instance.serialize().unwrap(); let map = data.as_map().unwrap(); let field13 = get_map_field(map, "field13"); assert_eq!(field13.len(), 2); assert_eq!(get_str_field(field13, "variant"), "Variant1"); assert!(field13.get("content").unwrap().is_none()); let field14 = get_map_field(map, "field14"); assert_eq!(field14.len(), 2); assert_eq!(get_str_field(field14, "variant"), "Variant2"); let arr = get_array_field(field14, "content"); assert_eq!(arr.len(), 2); let n: u64 = arr[0].as_number().unwrap().try_into().unwrap(); assert_eq!(n, 60); assert_eq!(arr[1].as_str().unwrap(), "asdf"); } #[test] #[allow(unused_variables)] fn test_skip_deserializing() { #[derive(Deserialize, Update)] struct TestStruct { field1: u32, #[serde(skip)] field2: u32, #[serde(skip_deserializing)] field3: u32, } let mut map = Map::new(); map.insert_with_static_key("field1", Intermediate::Number(Number::UnsignedInt(10))); map.insert_with_static_key("field2", Intermediate::Number(Number::UnsignedInt(20))); map.insert_with_static_key("field3", Intermediate::Number(Number::UnsignedInt(30))); let input = Intermediate::Map(map); let mut instance = TestStruct::deserialize(&input).unwrap(); assert_eq!(instance.field1, 10); assert_eq!(instance.field2, u32::default()); assert_eq!(instance.field3, u32::default()); instance.update(&input).unwrap(); assert_eq!(instance.field1, 10); assert_eq!(instance.field2, u32::default()); assert_eq!(instance.field3, u32::default()); } #[test] #[allow(unused_variables)] fn test_skip_serializing() { #[derive(Serialize)] struct TestStruct { field1: u32, #[serde(skip)] field2: u32, #[serde(skip_serializing)] field3: u32, #[serde(skip_serializing_if = "Option::is_none")] field4: Option, } let mut instance = TestStruct { field1: 1, field2: 2, field3: 3, field4: Some(4), }; let data = instance.serialize().unwrap(); let map = data.as_map().unwrap(); assert_eq!(map.len(), 2); assert_eq!(get_unsigned_int_field(map, "field1"), 1); assert_eq!(get_unsigned_int_field(map, "field4"), 4); instance.field4 = None; let data = instance.serialize().unwrap(); let map = data.as_map().unwrap(); assert_eq!(map.len(), 1); assert_eq!(get_unsigned_int_field(map, "field1"), 1); } #[test] fn test_serialize_with() { struct CustomType(u32); #[derive(Serialize)] struct TestStruct { #[serde(serialize_with = "serialize_custom_type")] field: CustomType, } fn serialize_custom_type(val: &CustomType) -> Result { let CustomType(inner) = val; inner.serialize() } let val = TestStruct { field: CustomType(10), }; let data = val.serialize().unwrap(); let fields = data.as_map().unwrap(); assert_eq!(fields.len(), 1); assert_eq!(get_unsigned_int_field(fields, "field"), 10); } #[test] fn test_deserialize_with() { struct CustomType(u32); #[derive(Deserialize)] struct TestStruct { #[serde(deserialize_with = "deserialize_custom_type")] field: CustomType, } fn deserialize_custom_type(val: &Intermediate) -> Result { Ok(CustomType(u32::deserialize(val)?)) } let input = intermediate!({ "field": 15 }); let res = TestStruct::deserialize(&input).unwrap(); assert_eq!(res.field.0, 15); } #[test] fn test_update_with() { struct CustomType(u32); #[derive(Deserialize, Update)] struct TestStruct { #[serde( deserialize_with = "deserialize_custom_type", update_with = "update_custom_type" )] field: CustomType, } fn deserialize_custom_type(val: &Intermediate) -> Result { Ok(CustomType(u32::deserialize(val)?)) } fn update_custom_type(val: &mut CustomType, input: &Intermediate) -> Result<(), Error> { u32::update(&mut val.0, input)?; Ok(()) } let input = intermediate!({ "field": 15 }); let mut val = TestStruct { field: CustomType(10), }; val.update(&input).unwrap(); assert_eq!(val.field.0, 15); } /// Helper. fn get_map_field<'a>(map: &'a Map, name: &str) -> &'a Map { map.get(name).unwrap().as_map().unwrap() } /// Helper. fn get_array_field<'a>(map: &'a Map, name: &str) -> &'a [Intermediate] { map.get(name).unwrap().as_array().unwrap() } /// Helper. fn get_bool_field(map: &Map, name: &str) -> bool { map.get(name).unwrap().as_bool().unwrap() } /// Helper. fn get_unsigned_int_field(map: &Map, name: &str) -> u64 { map.get(name) .unwrap() .as_number() .unwrap() .try_into() .unwrap() } /// Helper. fn get_str_field<'a>(map: &'a Map, name: &str) -> &'a str { map.get(name).unwrap().as_str().unwrap() }