From cd41b005b27bd827bf750a53bad92693917a1f71 Mon Sep 17 00:00:00 2001 From: AurelienFT Date: Wed, 11 Oct 2023 10:53:53 +0200 Subject: [PATCH 1/3] Add tests serialization --- massa-serialization/src/lib.rs | 231 +++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) diff --git a/massa-serialization/src/lib.rs b/massa-serialization/src/lib.rs index 60f5778d575..6d7a3d974f7 100644 --- a/massa-serialization/src/lib.rs +++ b/massa-serialization/src/lib.rs @@ -479,3 +479,234 @@ where .parse(buffer) } } + +#[cfg(test)] +mod tests { + use num::rational::Ratio; + + use crate::{DeserializeError, Deserializer, Serializer}; + + #[test] + fn test_u64_serializer_deserializer_works() { + let u64_serializer = super::U64VarIntSerializer::new(); + let number = 3u64; + let mut buffer = Vec::new(); + u64_serializer + .serialize(&number, &mut buffer) + .expect("Failed to serialize 3"); + assert_eq!(buffer, vec![3]); + let u64_deserializer = super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(number), + ); + let result = u64_deserializer.deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, number); + } + + #[test] + fn test_u64_serializer_deserializer_works_big_number() { + let u64_serializer = super::U64VarIntSerializer::default(); + let number = 10_000_000u64; + let mut buffer = Vec::new(); + u64_serializer + .serialize(&number, &mut buffer) + .expect("Failed to serialize 10_000_000"); + assert_eq!(buffer, vec![128, 173, 226, 4]); + let u64_deserializer = super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(number), + ); + let result = u64_deserializer.deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, number); + } + + #[test] + fn test_u64_serializer_deserializer_bad_limit() { + let u64_serializer = super::U64VarIntSerializer::new(); + let mut buffer = Vec::new(); + u64_serializer + .serialize(&3u64, &mut buffer) + .expect("Failed to serialize 3"); + assert_eq!(buffer, vec![3]); + let u64_deserializer = super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Excluded(3), + ); + let result = u64_deserializer.deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!( + format!("{}", err), + "Parsing Error: Failed u64 deserialization / Fail / Input: [3]\n" + ); + } + + #[test] + fn test_u64_empty_vec() { + let buffer = vec![]; + let u64_deserializer = super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(3), + ); + let result = u64_deserializer.deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!( + format!("{}", err), + "Parsing Error: Failed u64 deserialization / Fail / Input: []\n" + ); + } + + #[test] + fn test_option_serializer_value_works() { + let option_serializer = super::OptionSerializer::new(super::U64VarIntSerializer::new()); + let mut buffer = Vec::new(); + option_serializer + .serialize(&Some(3u64), &mut buffer) + .expect("Failed to serialize Some(3)"); + assert_eq!(buffer, vec![b'1', 3]); + let option_deserializer = + super::OptionDeserializer::new(super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(3), + )); + let result = option_deserializer.deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, Some(3u64)); + } + + #[test] + fn test_option_serializer_none_works() { + let option_serializer = super::OptionSerializer::new(super::U64VarIntSerializer::new()); + let mut buffer = Vec::new(); + option_serializer + .serialize(&None, &mut buffer) + .expect("Failed to serialize None"); + assert_eq!(buffer, vec![b'0']); + let option_deserializer = + super::OptionDeserializer::new(super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(3), + )); + let result = option_deserializer.deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, None); + } + + #[test] + fn test_option_bad_serialized_vec() { + let buffer = vec![2]; + let option_deserializer = + super::OptionDeserializer::new(super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(3), + )); + let result = option_deserializer.deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(format!("{}", err), "Parsing Error: Option<_> deserializer failed / Alternative / Some(_) / Tag / Input: [2]\n"); + } + + #[test] + fn test_option_empty_vec() { + let buffer = vec![]; + let option_deserializer = + super::OptionDeserializer::new(super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(3), + )); + let result = option_deserializer.deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(format!("{}", err), "Parsing Error: Option<_> deserializer failed / Alternative / Some(_) / Tag / Input: []\n"); + } + + #[test] + fn test_bool_serializer_deserializer_works() { + let bool_serializer = super::BoolSerializer::new(); + let mut buffer = Vec::new(); + bool_serializer + .serialize(&true, &mut buffer) + .expect("Failed to serialize true"); + assert_eq!(buffer, vec![1]); + let bool_deserializer = super::BoolDeserializer::new(); + let result = bool_deserializer.deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, true); + } + + #[test] + fn test_bool_bad_serialized_vec() { + let buffer = vec![2]; + let bool_deserializer = super::BoolDeserializer::new(); + let result = bool_deserializer.deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!( + format!("{}", err), + "Parsing Error: Failed bool deserialization / Fail / Input: [2]\n" + ); + } + + #[test] + fn test_bool_empty_vec() { + let buffer = vec![]; + let bool_deserializer = super::BoolDeserializer::new(); + let result = bool_deserializer.deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!( + format!("{}", err), + "Parsing Error: Failed bool deserialization / Fail / Input: []\n" + ); + } + + #[test] + fn test_ratio_serializer_deserializer_works() { + let ratio_serializer = super::RatioSerializer::new(super::U64VarIntSerializer::new()); + let mut buffer = Vec::new(); + ratio_serializer + .serialize(&Ratio::new(3u64, 4u64), &mut buffer) + .expect("Failed to serialize Ratio(3, 4)"); + assert_eq!(buffer, vec![3, 4]); + let ratio_deserializer = super::RatioDeserializer::new(super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(4), + )); + let result = ratio_deserializer.deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, Ratio::new(3u64, 4u64)); + } + + #[test] + fn test_ratio_serializer_deserializer_bad_limits() { + let ratio_serializer = super::RatioSerializer::new(super::U64VarIntSerializer::new()); + let mut buffer = Vec::new(); + ratio_serializer + .serialize(&Ratio::new(3u64, 4u64), &mut buffer) + .expect("Failed to serialize Ratio(3, 4)"); + assert_eq!(buffer, vec![3, 4]); + let ratio_deserializer = super::RatioDeserializer::new(super::U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(3), + )); + let result = ratio_deserializer.deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(format!("{}", err), "Parsing Error: Ratio<_> deserializer failed / denom deser failed / Failed u64 deserialization / Fail / Input: [4]\n"); + } +} From cf3c979db216c483da2063ed96a4f60a842fcf3a Mon Sep 17 00:00:00 2001 From: AurelienFT Date: Wed, 11 Oct 2023 15:45:30 +0200 Subject: [PATCH 2/3] Add parametric tests. --- Cargo.lock | 9 ++- Cargo.toml | 1 + massa-serialization/Cargo.toml | 3 + massa-serialization/src/lib.rs | 123 +++++++++++++++++---------------- 4 files changed, 77 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c2e456dcc9..293dfaba4a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3273,6 +3273,7 @@ dependencies = [ "displaydoc", "nom", "num", + "paste", "thiserror", "unsigned-varint 0.7.2", ] @@ -3821,6 +3822,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "pathdiff" version = "0.2.1" @@ -4194,7 +4201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2 1.0.67", "quote 1.0.33", "syn 2.0.37", diff --git a/Cargo.toml b/Cargo.toml index f6738e2998e..02ffad3c484 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,6 +148,7 @@ num = "=0.4" num_enum = "0.7" paginate = "1.1" parking_lot = "0.12" +paste = "1.0" pbkdf2 = { version = "=0.12", features = ["simple"] } prometheus = "0.13" rand = "0.8" diff --git a/massa-serialization/Cargo.toml b/massa-serialization/Cargo.toml index 1b6b97fbe8a..2082997bf0f 100644 --- a/massa-serialization/Cargo.toml +++ b/massa-serialization/Cargo.toml @@ -12,3 +12,6 @@ thiserror = {workspace = true} nom = {workspace = true} unsigned-varint = {workspace = true, "features" = ["nom"]} num = {workspace = true} + +[dev-dependencies] +paste = {workspace = true} diff --git a/massa-serialization/src/lib.rs b/massa-serialization/src/lib.rs index 6d7a3d974f7..9fbc59f82f9 100644 --- a/massa-serialization/src/lib.rs +++ b/massa-serialization/src/lib.rs @@ -482,70 +482,77 @@ where #[cfg(test)] mod tests { + use crate::{DeserializeError, Deserializer, Serializer}; use num::rational::Ratio; + use paste::paste; + + macro_rules! gen_test_varint { + ($($type:ident, $bs:ident, $ds:ident);*) => { + $( + paste! { + #[test] + fn []() { + let [< $type _serializer >] = super::$bs::new(); + let number = [<3 $type >]; + let mut buffer = Vec::new(); + [< $type _serializer >].serialize(&number, &mut buffer).expect(concat!("Failed to serialize ", stringify!($type), " 3")); + assert_eq!(buffer, vec![3]); + let [< $type _deserializer >] = super::$ds::new(std::ops::Bound::Included([<0 $type >]), std::ops::Bound::Included(number)); + let result = [< $type _deserializer >].deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, number); + } - use crate::{DeserializeError, Deserializer, Serializer}; + #[test] + fn []() { + let [< $type _serializer >] = super::$bs::new(); + let number = [<60_500 $type>]; + let mut buffer = Vec::new(); + [< $type _serializer >].serialize(&number, &mut buffer).expect(concat!("Failed to serialize ", stringify!($type), " 10_000_000")); + assert_eq!(buffer, vec![212, 216, 3]); + let [< $type _deserializer >] = super::$ds::new(std::ops::Bound::Included([<0 $type >]), std::ops::Bound::Included(number)); + let result = [< $type _deserializer >].deserialize::(&buffer); + assert!(result.is_ok()); + let (rest, value) = result.unwrap(); + assert!(rest.is_empty()); + assert_eq!(value, number); + } - #[test] - fn test_u64_serializer_deserializer_works() { - let u64_serializer = super::U64VarIntSerializer::new(); - let number = 3u64; - let mut buffer = Vec::new(); - u64_serializer - .serialize(&number, &mut buffer) - .expect("Failed to serialize 3"); - assert_eq!(buffer, vec![3]); - let u64_deserializer = super::U64VarIntDeserializer::new( - std::ops::Bound::Included(0), - std::ops::Bound::Included(number), - ); - let result = u64_deserializer.deserialize::(&buffer); - assert!(result.is_ok()); - let (rest, value) = result.unwrap(); - assert!(rest.is_empty()); - assert_eq!(value, number); - } + #[test] + fn []() { + let [< $type _serializer >] = super::$bs::new(); + let number = [<3 $type >]; + let mut buffer = Vec::new(); + [< $type _serializer >].serialize(&number, &mut buffer).expect(concat!("Failed to serialize ", stringify!($type), " 3")); + assert_eq!(buffer, vec![3]); + let [< $type _deserializer >] = super::$ds::new(std::ops::Bound::Included([<0 $type >]), std::ops::Bound::Excluded(number)); + let result = [< $type _deserializer >].deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(format!("{}", err), concat!("Parsing Error: Failed ", stringify!($type), " deserialization / Fail / Input: [3]\n")); + } - #[test] - fn test_u64_serializer_deserializer_works_big_number() { - let u64_serializer = super::U64VarIntSerializer::default(); - let number = 10_000_000u64; - let mut buffer = Vec::new(); - u64_serializer - .serialize(&number, &mut buffer) - .expect("Failed to serialize 10_000_000"); - assert_eq!(buffer, vec![128, 173, 226, 4]); - let u64_deserializer = super::U64VarIntDeserializer::new( - std::ops::Bound::Included(0), - std::ops::Bound::Included(number), - ); - let result = u64_deserializer.deserialize::(&buffer); - assert!(result.is_ok()); - let (rest, value) = result.unwrap(); - assert!(rest.is_empty()); - assert_eq!(value, number); + #[test] + fn []() { + let buffer = vec![]; + let [< $type _deserializer >] = super::$ds::new(std::ops::Bound::Included([<0 $type >]), std::ops::Bound::Included($type::MAX)); + let result = [< $type _deserializer >].deserialize::(&buffer); + assert!(result.is_err()); + let err = result.unwrap_err(); + assert_eq!(format!("{}", err), concat!("Parsing Error: Failed ", stringify!($type), " deserialization / Fail / Input: []\n")); + } + } + )* + }; } - #[test] - fn test_u64_serializer_deserializer_bad_limit() { - let u64_serializer = super::U64VarIntSerializer::new(); - let mut buffer = Vec::new(); - u64_serializer - .serialize(&3u64, &mut buffer) - .expect("Failed to serialize 3"); - assert_eq!(buffer, vec![3]); - let u64_deserializer = super::U64VarIntDeserializer::new( - std::ops::Bound::Included(0), - std::ops::Bound::Excluded(3), - ); - let result = u64_deserializer.deserialize::(&buffer); - assert!(result.is_err()); - let err = result.unwrap_err(); - assert_eq!( - format!("{}", err), - "Parsing Error: Failed u64 deserialization / Fail / Input: [3]\n" - ); - } + gen_test_varint!( + u16, U16VarIntSerializer, U16VarIntDeserializer; + u32, U32VarIntSerializer, U32VarIntDeserializer; + u64, U64VarIntSerializer, U64VarIntDeserializer + ); #[test] fn test_u64_empty_vec() { From 1a2cb0edefd4154faee2203089ae3ed557409ffc Mon Sep 17 00:00:00 2001 From: AurelienFT Date: Thu, 12 Oct 2023 08:25:31 +0200 Subject: [PATCH 3/3] add comments --- massa-serialization/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/massa-serialization/src/lib.rs b/massa-serialization/src/lib.rs index 9fbc59f82f9..26be9c2cc83 100644 --- a/massa-serialization/src/lib.rs +++ b/massa-serialization/src/lib.rs @@ -486,6 +486,12 @@ mod tests { use num::rational::Ratio; use paste::paste; + // This macro creates a suite of tests for all types of numbers declared as parameters. Ths list of the + // tests for each type : + // - Test with a normal case that everything works + // - Test with a normal case but a more bigger number that everything works + // - Test with a number that is out of the range of the deserializer + // - Test to give an empty buffer to the deserializer macro_rules! gen_test_varint { ($($type:ident, $bs:ident, $ds:ident);*) => { $(