From 6e114183349d443e27784044a981f40642921c6d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 27 Jun 2023 12:38:01 +0200 Subject: [PATCH 1/3] Improve serde_json compatibility testing --- src/ser/mod.rs | 192 +++++++++++++++++++++---------------------------- 1 file changed, 81 insertions(+), 111 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index d50b2fe2..2491a876 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -535,6 +535,20 @@ mod tests { use serde::{Serialize, Serializer}; use serde_derive::{Deserialize, Serialize}; + #[macro_export] + macro_rules! assert_serde_json_serialize_eq { + ($target:expr,) => { + assert_serde_json_serialize_eq!($target); + }; + ($target:expr) => { + assert_eq!( + crate::to_string($target).unwrap(), + ::serde_json::to_string($target).unwrap(), + "Serialization does not match serde_json" + ); + }; + } + #[test] fn bool() { assert_eq!(to_string(&true).unwrap(), "true"); @@ -640,9 +654,11 @@ mod tests { r#""9223372036854775808""# ); assert_eq!( - to_string::(&std::u128::MAX).unwrap(), + to_string::(&u128::MAX).unwrap(), r#""340282366920938463463374607431768211455""# ); + // Currently failing, see https://github.com/CosmWasm/serde-json-wasm/issues/54 + // assert_serde_json_serialize_eq!(&u128::MAX); assert_eq!(to_string::(&0).unwrap(), r#""0""#); assert_eq!(to_string::(&1).unwrap(), r#""1""#); @@ -666,14 +682,16 @@ mod tests { r#""9223372036854775808""# ); assert_eq!( - to_string::(&std::i128::MAX).unwrap(), + to_string::(&i128::MAX).unwrap(), r#""170141183460469231731687303715884105727""# ); assert_eq!(to_string::(&-1).unwrap(), r#""-1""#); assert_eq!( - to_string::(&std::i128::MIN).unwrap(), + to_string::(&i128::MIN).unwrap(), r#""-170141183460469231731687303715884105728""# ); + // Currently failing, see https://github.com/CosmWasm/serde-json-wasm/issues/54 + // assert_serde_json_serialize_eq!(&i128::MIN); } #[test] @@ -690,25 +708,16 @@ mod tests { let pair: Pair = (1, 2); assert_eq!(to_string(&pair).unwrap(), "[1,2]"); - assert_eq!( - to_string(&pair).unwrap(), - serde_json::to_string(&pair).unwrap() - ); + assert_serde_json_serialize_eq!(&pair); let wrapped: Wrapped = (5,); assert_eq!(to_string(&wrapped).unwrap(), "[5]"); - assert_eq!( - to_string(&wrapped).unwrap(), - serde_json::to_string(&wrapped).unwrap() - ); + assert_serde_json_serialize_eq!(&wrapped); #[allow(clippy::let_unit_value)] let unit: Unit = (); assert_eq!(to_string(&unit).unwrap(), "null"); - assert_eq!( - to_string(&unit).unwrap(), - serde_json::to_string(&unit).unwrap() - ); + assert_serde_json_serialize_eq!(&unit); type BigPair = (u128, u128); @@ -718,6 +727,8 @@ mod tests { to_string(&pair).unwrap(), r#"["340282366920938463463374607431768211455","340282366920938463463374607431768211455"]"# ); + // Currently failing, see https://github.com/CosmWasm/serde-json-wasm/issues/54 + // assert_serde_json_serialize_eq!(&pair); } #[test] @@ -729,10 +740,7 @@ mod tests { Exit, } assert_eq!(to_string(&Op::Exit).unwrap(), r#""Exit""#); - assert_eq!( - to_string(&Op::Exit).unwrap(), - serde_json::to_string(&Op::Exit).unwrap() - ); + assert_serde_json_serialize_eq!(&Op::Exit); // Numeric values are ignored 🤷 #[derive(Serialize)] @@ -741,15 +749,10 @@ mod tests { Ordered = 42, } assert_eq!(to_string(&Order::Unordered).unwrap(), r#""Unordered""#); - assert_eq!( - to_string(&Order::Unordered).unwrap(), - serde_json::to_string(&Order::Unordered).unwrap() - ); + assert_serde_json_serialize_eq!(&Order::Unordered); + assert_eq!(to_string(&Order::Ordered).unwrap(), r#""Ordered""#); - assert_eq!( - to_string(&Order::Ordered).unwrap(), - serde_json::to_string(&Order::Ordered).unwrap() - ); + assert_serde_json_serialize_eq!(&Order::Ordered); } #[test] @@ -761,20 +764,13 @@ mod tests { Add(i64, i64), } assert_eq!(to_string(&Op::Exit()).unwrap(), r#"{"Exit":[]}"#); - assert_eq!( - to_string(&Op::Exit()).unwrap(), - serde_json::to_string(&Op::Exit()).unwrap() - ); + assert_serde_json_serialize_eq!(&Op::Exit()); + assert_eq!(to_string(&Op::Square(2)).unwrap(), r#"{"Square":2}"#); - assert_eq!( - to_string(&Op::Square(2)).unwrap(), - serde_json::to_string(&Op::Square(2)).unwrap() - ); + assert_serde_json_serialize_eq!(&Op::Square(2)); + assert_eq!(to_string(&Op::Add(3, 4)).unwrap(), r#"{"Add":[3,4]}"#); - assert_eq!( - to_string(&Op::Add(3, 4)).unwrap(), - serde_json::to_string(&Op::Add(3, 4)).unwrap() - ); + assert_serde_json_serialize_eq!(&Op::Add(3, 4)); } #[test] @@ -786,26 +782,19 @@ mod tests { Add { a: i64, b: i64 }, } assert_eq!(to_string(&Op::Exit {}).unwrap(), r#"{"Exit":{}}"#); - assert_eq!( - to_string(&Op::Exit {}).unwrap(), - serde_json::to_string(&Op::Exit {}).unwrap() - ); + assert_serde_json_serialize_eq!(&Op::Exit {}); + assert_eq!( to_string(&Op::Square { input: 2 }).unwrap(), r#"{"Square":{"input":2}}"# ); - assert_eq!( - to_string(&Op::Square { input: 2 }).unwrap(), - serde_json::to_string(&Op::Square { input: 2 }).unwrap() - ); + assert_serde_json_serialize_eq!(&Op::Square { input: 2 }); + assert_eq!( to_string(&Op::Add { a: 3, b: 4 }).unwrap(), r#"{"Add":{"a":3,"b":4}}"# ); - assert_eq!( - to_string(&Op::Add { a: 3, b: 4 }).unwrap(), - serde_json::to_string(&Op::Add { a: 3, b: 4 }).unwrap() - ); + assert_serde_json_serialize_eq!(&Op::Add { a: 3, b: 4 }); } #[test] @@ -896,11 +885,16 @@ mod tests { #[derive(Serialize)] struct CommentId(u32); + // string assert_eq!( to_string(&Address("home".to_string())).unwrap(), r#""home""# ); + assert_serde_json_serialize_eq!(&Address("home".to_string())); + + // number assert_eq!(to_string(&CommentId(42)).unwrap(), r#"42"#); + assert_serde_json_serialize_eq!(&CommentId(42)); } #[test] @@ -911,6 +905,7 @@ mod tests { } assert_eq!(to_string(&Led { led: true }).unwrap(), r#"{"led":true}"#); + assert_serde_json_serialize_eq!(&Led { led: true }); } #[test] @@ -924,21 +919,19 @@ mod tests { to_string(&Temperature { temperature: 127 }).unwrap(), r#"{"temperature":127}"# ); - assert_eq!( to_string(&Temperature { temperature: 20 }).unwrap(), r#"{"temperature":20}"# ); - assert_eq!( to_string(&Temperature { temperature: -17 }).unwrap(), r#"{"temperature":-17}"# ); - assert_eq!( to_string(&Temperature { temperature: -128 }).unwrap(), r#"{"temperature":-128}"# ); + assert_serde_json_serialize_eq!(&Temperature { temperature: -128 }); } #[test] @@ -955,12 +948,16 @@ mod tests { .unwrap(), r#"{"description":"An ambient temperature sensor"}"# ); + assert_serde_json_serialize_eq!(&Property { + description: Some("An ambient temperature sensor"), + }); // XXX Ideally this should produce "{}" assert_eq!( to_string(&Property { description: None }).unwrap(), r#"{"description":null}"# ); + assert_serde_json_serialize_eq!(&Property { description: None }); } #[test] @@ -974,6 +971,7 @@ mod tests { to_string(&Temperature { temperature: 20 }).unwrap(), r#"{"temperature":20}"# ); + assert_serde_json_serialize_eq!(&Temperature { temperature: 20 }); } #[test] @@ -982,19 +980,13 @@ mod tests { struct Nothing; assert_eq!(to_string(&Nothing).unwrap(), r#"null"#); - assert_eq!( - to_string(&Nothing).unwrap(), - serde_json::to_string(&Nothing).unwrap() - ); + assert_serde_json_serialize_eq!(&Nothing); #[derive(Serialize)] struct Empty {} assert_eq!(to_string(&Empty {}).unwrap(), r#"{}"#); - assert_eq!( - to_string(&Empty {}).unwrap(), - serde_json::to_string(&Empty {}).unwrap() - ); + assert_serde_json_serialize_eq!(&Empty {}); #[derive(Serialize)] struct Tuple { @@ -1006,6 +998,7 @@ mod tests { to_string(&Tuple { a: true, b: false }).unwrap(), r#"{"a":true,"b":false}"# ); + assert_serde_json_serialize_eq!(&Tuple { a: true, b: false }); } #[test] @@ -1038,11 +1031,7 @@ mod tests { to_string(&users).unwrap(), r#"{"users":["joe","alice"],"limit":20,"offset":100,"total":102}"# ); - assert_eq!( - to_string(&users).unwrap(), - serde_json::to_string(&users).unwrap(), - "serialization must match serde_json implementation" - ); + assert_serde_json_serialize_eq!(&users); } #[test] @@ -1050,12 +1039,15 @@ mod tests { use std::collections::BTreeMap; // empty map - assert_eq!(to_string(&BTreeMap::<(), ()>::new()).unwrap(), r#"{}"#); + let empty = BTreeMap::<(), ()>::new(); + assert_eq!(to_string(&empty).unwrap(), r#"{}"#); + assert_serde_json_serialize_eq!(&empty); // One element with unit type let mut map = BTreeMap::<&str, ()>::new(); map.insert("set_element", ()); assert_eq!(to_string(&map).unwrap(), r#"{"set_element":null}"#); + assert_serde_json_serialize_eq!(&map); let mut two_values = BTreeMap::new(); two_values.insert("my_name", "joseph"); @@ -1064,6 +1056,7 @@ mod tests { to_string(&two_values).unwrap(), r#"{"her_name":"aline","my_name":"joseph"}"# ); + assert_serde_json_serialize_eq!(&two_values); let mut nested_map = BTreeMap::new(); nested_map.insert("two_entries", two_values.clone()); @@ -1074,6 +1067,7 @@ mod tests { to_string(&nested_map).unwrap(), r#"{"one_entry":{"her_name":"aline"},"two_entries":{"her_name":"aline","my_name":"joseph"}}"# ); + assert_serde_json_serialize_eq!(&nested_map); } #[test] @@ -1081,12 +1075,15 @@ mod tests { use std::collections::HashMap; // empty map - assert_eq!(to_string(&HashMap::<(), ()>::new()).unwrap(), r#"{}"#); + let empty = HashMap::<(), ()>::new(); + assert_eq!(to_string(&empty).unwrap(), r#"{}"#); + assert_serde_json_serialize_eq!(&empty); // One element let mut map = HashMap::new(); map.insert("my_age", 28); assert_eq!(to_string(&map).unwrap(), r#"{"my_age":28}"#); + assert_serde_json_serialize_eq!(&map); #[derive(Debug, Serialize, PartialEq, Eq, Hash)] pub struct NewType(String); @@ -1095,6 +1092,7 @@ mod tests { let mut map = HashMap::new(); map.insert(NewType(String::from("my_age")), 44); assert_eq!(to_string(&map).unwrap(), r#"{"my_age":44}"#); + assert_serde_json_serialize_eq!(&map); #[derive(Debug, Serialize, PartialEq, Eq, Hash)] #[serde(rename_all = "lowercase")] @@ -1106,6 +1104,7 @@ mod tests { let mut map = HashMap::new(); map.insert(MyResult::Err, 404); assert_eq!(to_string(&map).unwrap(), r#"{"err":404}"#); + assert_serde_json_serialize_eq!(&map); // HashMap does not have deterministic iteration order (except in the Wasm target). // So the two element map is serialized as one of two options. @@ -1117,48 +1116,7 @@ mod tests { serialized == r#"{"her_name":"aline","my_name":"joseph"}"# || serialized == r#"{"my_name":"joseph","her_name":"aline"}"# ); - } - - #[test] - fn map_serialization_matches_json_serde() { - use std::collections::BTreeMap; - - fn ser_actual(value: &T) -> String { - to_string(value).unwrap() - } - - fn ser_expected(value: &T) -> String { - serde_json::to_string(value).unwrap() - } - - let map = BTreeMap::<(), ()>::new(); - assert_eq!(ser_actual(&map), ser_expected(&map)); - - let mut two_values = BTreeMap::new(); - two_values.insert("my_name", "joseph"); - two_values.insert("her_name", "aline"); - assert_eq!(ser_actual(&two_values), ser_expected(&two_values)); - - let mut nested_map = BTreeMap::new(); - nested_map.insert("two_entries", two_values.clone()); - two_values.remove("my_name"); - nested_map.insert("one_entry", two_values); - assert_eq!(ser_actual(&nested_map), ser_expected(&nested_map)); - - // One element with unit type - let mut map = BTreeMap::<&str, ()>::new(); - map.insert("set_element", ()); - assert_eq!(ser_actual(&map), ser_expected(&map)); - - // numeric keys - let mut map = BTreeMap::new(); - map.insert(10i8, "my_age"); - assert_eq!(ser_actual(&map), ser_expected(&map)); - - // numeric values - let mut scores = BTreeMap::new(); - scores.insert("player A", 1234212); - assert_eq!(ser_actual(&scores), ser_expected(&scores)); + assert_serde_json_serialize_eq!(&two_values); } #[test] @@ -1169,16 +1127,19 @@ mod tests { let mut map = HashMap::new(); map.insert(10i8, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); // i16 key let mut map = HashMap::new(); map.insert(10i16, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); // i32 key let mut map = HashMap::new(); map.insert(10i32, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); // i64 key let mut map = HashMap::new(); @@ -1189,11 +1150,13 @@ mod tests { let mut map = HashMap::new(); map.insert(10i128, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); // u8 key let mut map = HashMap::new(); map.insert(10u8, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); // u16 key let mut map = HashMap::new(); @@ -1204,16 +1167,19 @@ mod tests { let mut map = HashMap::new(); map.insert(10u32, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); // u64 key let mut map = HashMap::new(); map.insert(10u64, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); // u128 key let mut map = HashMap::new(); map.insert(10u128, "my_age"); assert_eq!(to_string(&map).unwrap(), r#"{"10":"my_age"}"#); + assert_serde_json_serialize_eq!(&map); } #[test] @@ -1297,12 +1263,14 @@ mod tests { assert_eq!(json, r#"{"err":"some error"}"#.to_string()); let loaded = crate::from_str(&json).expect("re-load err enum"); assert_eq!(err_input, loaded); + assert_serde_json_serialize_eq!(&err_input); let unit = MyResult::Unit(()); let json = to_string(&unit).expect("encode unit enum"); assert_eq!(json, r#"{"unit":null}"#.to_string()); let loaded = crate::from_str(&json).expect("re-load unit enum"); assert_eq!(unit, loaded); + assert_serde_json_serialize_eq!(&unit); let empty_list = MyResult::Ok(Response { log: Some("log message".to_string()), @@ -1316,6 +1284,7 @@ mod tests { ); let loaded = crate::from_str(&json).expect("re-load ok enum"); assert_eq!(empty_list, loaded); + assert_serde_json_serialize_eq!(&empty_list); let full_list = MyResult::Ok(Response { log: None, @@ -1329,5 +1298,6 @@ mod tests { ); let loaded = crate::from_str(&json).expect("re-load ok enum"); assert_eq!(full_list, loaded); + assert_serde_json_serialize_eq!(&full_list); } } From b859f543c16857cd273245c9155babddad41e791 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 27 Jun 2023 12:44:21 +0200 Subject: [PATCH 2/3] Remove comments about omitting None values --- src/ser/mod.rs | 1 - src/ser/struct_.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 2491a876..60d69716 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -952,7 +952,6 @@ mod tests { description: Some("An ambient temperature sensor"), }); - // XXX Ideally this should produce "{}" assert_eq!( to_string(&Property { description: None }).unwrap(), r#"{"description":null}"# diff --git a/src/ser/struct_.rs b/src/ser/struct_.rs index 502d0346..5a15036a 100644 --- a/src/ser/struct_.rs +++ b/src/ser/struct_.rs @@ -21,7 +21,6 @@ impl<'a> ser::SerializeStruct for SerializeStruct<'a> { where T: ser::Serialize, { - // XXX if `value` is `None` we not produce any output for this field if !self.first { self.ser.buf.push(b','); } @@ -50,7 +49,6 @@ impl<'a> ser::SerializeStructVariant for SerializeStruct<'a> { where T: ser::Serialize, { - // XXX if `value` is `None` we not produce any output for this field if !self.first { self.ser.buf.push(b','); } From d98dab60b9245acee3e38ddf924ee24426fd6565 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Tue, 27 Jun 2023 12:45:18 +0200 Subject: [PATCH 3/3] Update serde_json --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d065619c..a3386ade 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index dbec3b5d..a56dbfa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,4 +27,4 @@ serde = { version = "^1.0.80", default-features = false, features = ["alloc"] } [dev-dependencies] serde_derive = "^1.0.80" -serde_json = "^1.0.59" +serde_json = "^1.0.99"