use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt::Debug; use serde::de::DeserializeOwned; use shiny_configuration::value::deserializer::ValueDeserializer; use shiny_configuration::value::number::Number; use shiny_configuration::value::serializer::ValueSerializer; use shiny_configuration::value::Value; macro_rules! value_map { ($($key:expr => $value:expr),* $(,)?) => ({ let mut map: std::collections::HashMap = std::collections::HashMap::new(); $(map.insert($key.to_string(), $value.into());)* shiny_configuration::value::Value::Map(map) }); } // T -> Value -> YAML -> Value -> T fn assert_serde_eq(input: T, expected_value: Value) where T: Serialize + DeserializeOwned + Debug + PartialEq, { // T -> Value let value = input .serialize(ValueSerializer) .expect(&format!("Failed to serialize into Value {:?}", &input)); assert_eq!(&value, &expected_value); // Value -> Yaml let value_wrapped = Value::Map(HashMap::from([("value".to_string(), value)])); let toml_string = serde_yaml::to_string(&value_wrapped) .expect(&format!("Failed to serialize into YAML {value_wrapped:?}")); // Yaml -> Value let value: Value = serde_yaml::from_str(&toml_string) .expect(&format!("Failed to deserialize from YAML {toml_string}")); let value = value .get("value") .map(|v| v.clone()) .unwrap_or(Value::None); // Value -> T let deserialized = T::deserialize(ValueDeserializer(&value)).expect(&format!("Failed to deserialize from Value {value:?}")); assert_eq!(deserialized, input); } #[test] fn test_basic_types() { // Numbers assert_serde_eq(42i8, Value::Number(Number::Integer(42))); assert_serde_eq(42i16, Value::Number(Number::Integer(42))); assert_serde_eq(42i32, Value::Number(Number::Integer(42))); assert_serde_eq(42i64, Value::Number(Number::Integer(42))); assert_serde_eq(-42i16, Value::Number(Number::Integer(-42))); assert_serde_eq(-42i32, Value::Number(Number::Integer(-42))); assert_serde_eq(-42i64, Value::Number(Number::Integer(-42))); assert_serde_eq(42u8, Value::Number(Number::UInteger(42))); assert_serde_eq(42u16, Value::Number(Number::UInteger(42))); assert_serde_eq(42u32, Value::Number(Number::UInteger(42))); assert_serde_eq(42u64, Value::Number(Number::UInteger(42))); assert_serde_eq(42f32, Value::Number(Number::Float(42.0))); assert_serde_eq(42f64, Value::Number(Number::Float(42.0))); // String, char and bytes assert_serde_eq('c', Value::String("c".to_string())); assert_serde_eq("hello".to_string(), Value::String("hello".to_string())); // Bool assert_serde_eq(true, Value::Bool(true)); assert_serde_eq(false, Value::Bool(false)); // Option assert_serde_eq((), Value::None); assert_serde_eq(Option::::None, Value::None); assert_serde_eq(Some(42i32), Value::Number(Number::Integer(42))); // Vec assert_serde_eq( [1u8, 2u8, 3u8], Value::Array(vec![ Value::Number(Number::UInteger(1)), Value::Number(Number::UInteger(2)), Value::Number(Number::UInteger(3)), ]), ); // Map assert_serde_eq( HashMap::from([("1".to_string(), 1i32), ("2".to_string(), 2i32)]), value_map! { "1" => 1i32, "2" => 2i32 }, ); } #[test] fn test_serialize_deserialize_unit_struct() { #[derive(Serialize, Deserialize, Debug, PartialEq)] struct UnitStruct; assert_serde_eq(UnitStruct, Value::None); } #[test] fn test_serialize_deserialize_unit_variant() { #[derive(Serialize, Deserialize, Debug, PartialEq)] enum UnitVariant { A, B, } assert_serde_eq(UnitVariant::A, Value::String("A".to_string())); } #[test] fn test_serialize_deserialize_newtype_struct() { #[derive(Serialize, Deserialize, Debug, PartialEq)] struct Newtype(i32); assert_serde_eq(Newtype(42), Value::Number(Number::Integer(42))); } #[test] fn test_serialize_deserialize_newtype_variant() { #[derive(Serialize, Deserialize, Debug, PartialEq)] enum NewtypeVariant { I32(i32), String(String), } assert_serde_eq( NewtypeVariant::I32(1), value_map! { "I32" => Value::Number(Number::Integer(1)) }, ); } #[test] fn test_serialize_deserialize_tuple() { assert_serde_eq( (1, true, "test_string".to_string()), Value::Array(vec![ Value::Number(Number::Integer(1)), Value::Bool(true), Value::String("test_string".to_string()), ]), ); } #[test] fn test_serialize_deserialize_tuple_struct() { #[derive(Debug, Serialize, Deserialize, PartialEq)] struct TupleStruct(i32, i32, bool); assert_serde_eq( TupleStruct(1, -1, false), Value::Array(vec![ Value::Number(Number::Integer(1)), Value::Number(Number::Integer(-1)), Value::Bool(false), ]), ); } #[test] fn test_serialize_deserialize_tuple_variant() { #[derive(Debug, Serialize, Deserialize, PartialEq)] enum TupleVariant { I(i32, i32), S(String, String), } assert_serde_eq( TupleVariant::I(1, -1), value_map! { "I" => vec![ Value::Number(Number::Integer(1)), Value::Number(Number::Integer(-1)), ] }, ); } #[test] fn test_serialize_deserialize_struct() { #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Struct { i: i32, u: u32, } assert_serde_eq( Struct { i: -1, u: 1 }, value_map! { "i" => -1i32, "u" => 1u32 }, ); } #[test] fn test_serialize_deserialize_enum() { #[derive(Debug, Serialize, Deserialize, PartialEq)] enum Enum { I { value: i32 }, S { value: String }, } assert_serde_eq( Enum::I { value: 1 }, value_map! { "I" => value_map! { "value" => 1i32 } }, ); }