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<String>,
}
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<u32>),
}
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<u32>),
}
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<u32>),
}
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<u32>,
}
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<Intermediate, Error> {
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<CustomType, Error> {
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<CustomType, Error> {
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);
}
fn get_map_field<'a>(map: &'a Map, name: &str) -> &'a Map {
map.get(name).unwrap().as_map().unwrap()
}
fn get_array_field<'a>(map: &'a Map, name: &str) -> &'a [Intermediate] {
map.get(name).unwrap().as_array().unwrap()
}
fn get_bool_field(map: &Map, name: &str) -> bool {
map.get(name).unwrap().as_bool().unwrap()
}
fn get_unsigned_int_field(map: &Map, name: &str) -> u64 {
map.get(name)
.unwrap()
.as_number()
.unwrap()
.try_into()
.unwrap()
}
fn get_str_field<'a>(map: &'a Map, name: &str) -> &'a str {
map.get(name).unwrap().as_str().unwrap()
}