use crate::{record, FromValue, IntoValue, Record, Span, Value}; use bytes::Bytes; use std::collections::HashMap; // Make nu_protocol available in this namespace, consumers of this crate will // have this without such an export. // The derive macro fully qualifies paths to "nu_protocol". use crate as nu_protocol; trait IntoTestValue { fn into_test_value(self) -> Value; } impl IntoTestValue for T where T: IntoValue, { fn into_test_value(self) -> Value { self.into_value(Span::test_data()) } } #[derive(IntoValue, FromValue, Debug, PartialEq)] struct NamedFieldsStruct where T: IntoValue + FromValue, { array: [u16; 4], bool: bool, char: char, f32: f32, f64: f64, i8: i8, i16: i16, i32: i32, i64: i64, isize: isize, u16: u16, u32: u32, unit: (), tuple: (u32, bool), some: Option, none: Option, vec: Vec, string: String, hashmap: HashMap, nested: Nestee, } #[derive(IntoValue, FromValue, Debug, PartialEq)] struct Nestee { u32: u32, some: Option, none: Option, } impl NamedFieldsStruct { fn make() -> Self { Self { array: [1, 2, 3, 4], bool: true, char: 'a', f32: std::f32::consts::PI, f64: std::f64::consts::E, i8: 127, i16: -32768, i32: 2147483647, i64: -9223372036854775808, isize: 2, u16: 65535, u32: 4294967295, unit: (), tuple: (1, true), some: Some(123), none: None, vec: vec![10, 20, 30], string: "string".to_string(), hashmap: HashMap::from_iter([("a".to_string(), 10), ("b".to_string(), 20)]), nested: Nestee { u32: 3, some: Some(42), none: None, }, } } fn value() -> Value { Value::test_record(record! { "array" => Value::test_list(vec![ Value::test_int(1), Value::test_int(2), Value::test_int(3), Value::test_int(4) ]), "bool" => Value::test_bool(true), "char" => Value::test_string('a'), "f32" => Value::test_float(std::f32::consts::PI.into()), "f64" => Value::test_float(std::f64::consts::E), "i8" => Value::test_int(127), "i16" => Value::test_int(-32768), "i32" => Value::test_int(2147483647), "i64" => Value::test_int(-9223372036854775808), "isize" => Value::test_int(2), "u16" => Value::test_int(65535), "u32" => Value::test_int(4294967295), "unit" => Value::test_nothing(), "tuple" => Value::test_list(vec![ Value::test_int(1), Value::test_bool(true) ]), "some" => Value::test_int(123), "none" => Value::test_nothing(), "vec" => Value::test_list(vec![ Value::test_int(10), Value::test_int(20), Value::test_int(30) ]), "string" => Value::test_string("string"), "hashmap" => Value::test_record(record! { "a" => Value::test_int(10), "b" => Value::test_int(20) }), "nested" => Value::test_record(record! { "u32" => Value::test_int(3), "some" => Value::test_int(42), "none" => Value::test_nothing(), }) }) } } #[test] fn named_fields_struct_into_value() { let expected = NamedFieldsStruct::value(); let actual = NamedFieldsStruct::make().into_test_value(); assert_eq!(expected, actual); } #[test] fn named_fields_struct_from_value() { let expected = NamedFieldsStruct::make(); let actual = NamedFieldsStruct::from_value(NamedFieldsStruct::value()).unwrap(); assert_eq!(expected, actual); } #[test] fn named_fields_struct_roundtrip() { let expected = NamedFieldsStruct::make(); let actual = NamedFieldsStruct::from_value(NamedFieldsStruct::make().into_test_value()).unwrap(); assert_eq!(expected, actual); let expected = NamedFieldsStruct::value(); let actual = NamedFieldsStruct::::from_value(NamedFieldsStruct::value()) .unwrap() .into_test_value(); assert_eq!(expected, actual); } #[test] fn named_fields_struct_missing_value() { let value = Value::test_record(Record::new()); let res: Result, _> = NamedFieldsStruct::from_value(value); assert!(res.is_err()); } #[test] fn named_fields_struct_incorrect_type() { // Should work for every type that is not a record. let value = Value::test_nothing(); let res: Result, _> = NamedFieldsStruct::from_value(value); assert!(res.is_err()); } #[derive(IntoValue, FromValue, Debug, PartialEq, Default)] struct ALotOfOptions { required: bool, float: Option, int: Option, value: Option, nested: Option, } #[test] fn missing_options() { let value = Value::test_record(Record::new()); let res: Result = ALotOfOptions::from_value(value); assert!(res.is_err()); let value = Value::test_record(record! {"required" => Value::test_bool(true)}); let expected = ALotOfOptions { required: true, ..Default::default() }; let actual = ALotOfOptions::from_value(value).unwrap(); assert_eq!(expected, actual); let value = Value::test_record(record! { "required" => Value::test_bool(true), "float" => Value::test_float(std::f64::consts::PI), }); let expected = ALotOfOptions { required: true, float: Some(std::f64::consts::PI), ..Default::default() }; let actual = ALotOfOptions::from_value(value).unwrap(); assert_eq!(expected, actual); let value = Value::test_record(record! { "required" => Value::test_bool(true), "int" => Value::test_int(12), "nested" => Value::test_record(record! { "u32" => Value::test_int(34), }), }); let expected = ALotOfOptions { required: true, int: Some(12), nested: Some(Nestee { u32: 34, some: None, none: None, }), ..Default::default() }; let actual = ALotOfOptions::from_value(value).unwrap(); assert_eq!(expected, actual); } #[derive(IntoValue, FromValue, Debug, PartialEq)] struct UnnamedFieldsStruct(u32, String, T) where T: IntoValue + FromValue; impl UnnamedFieldsStruct { fn make() -> Self { UnnamedFieldsStruct(420, "Hello, tuple!".to_string(), 33.33) } fn value() -> Value { Value::test_list(vec![ Value::test_int(420), Value::test_string("Hello, tuple!"), Value::test_float(33.33), ]) } } #[test] fn unnamed_fields_struct_into_value() { let expected = UnnamedFieldsStruct::value(); let actual = UnnamedFieldsStruct::make().into_test_value(); assert_eq!(expected, actual); } #[test] fn unnamed_fields_struct_from_value() { let expected = UnnamedFieldsStruct::make(); let value = UnnamedFieldsStruct::value(); let actual = UnnamedFieldsStruct::from_value(value).unwrap(); assert_eq!(expected, actual); } #[test] fn unnamed_fields_struct_roundtrip() { let expected = UnnamedFieldsStruct::make(); let actual = UnnamedFieldsStruct::from_value(UnnamedFieldsStruct::make().into_test_value()).unwrap(); assert_eq!(expected, actual); let expected = UnnamedFieldsStruct::value(); let actual = UnnamedFieldsStruct::::from_value(UnnamedFieldsStruct::value()) .unwrap() .into_test_value(); assert_eq!(expected, actual); } #[test] fn unnamed_fields_struct_missing_value() { let value = Value::test_list(vec![]); let res: Result, _> = UnnamedFieldsStruct::from_value(value); assert!(res.is_err()); } #[test] fn unnamed_fields_struct_incorrect_type() { // Should work for every type that is not a record. let value = Value::test_nothing(); let res: Result, _> = UnnamedFieldsStruct::from_value(value); assert!(res.is_err()); } #[derive(IntoValue, FromValue, Debug, PartialEq)] struct UnitStruct; #[test] fn unit_struct_into_value() { let expected = Value::test_nothing(); let actual = UnitStruct.into_test_value(); assert_eq!(expected, actual); } #[test] fn unit_struct_from_value() { let expected = UnitStruct; let actual = UnitStruct::from_value(Value::test_nothing()).unwrap(); assert_eq!(expected, actual); } #[test] fn unit_struct_roundtrip() { let expected = UnitStruct; let actual = UnitStruct::from_value(UnitStruct.into_test_value()).unwrap(); assert_eq!(expected, actual); let expected = Value::test_nothing(); let actual = UnitStruct::from_value(Value::test_nothing()) .unwrap() .into_test_value(); assert_eq!(expected, actual); } #[derive(IntoValue, FromValue, Debug, PartialEq)] enum Enum { AlphaOne, BetaTwo, CharlieThree, } impl Enum { fn make() -> [Self; 3] { [Enum::AlphaOne, Enum::BetaTwo, Enum::CharlieThree] } fn value() -> Value { Value::test_list(vec![ Value::test_string("alpha_one"), Value::test_string("beta_two"), Value::test_string("charlie_three"), ]) } } #[test] fn enum_into_value() { let expected = Enum::value(); let actual = Enum::make().into_test_value(); assert_eq!(expected, actual); } #[test] fn enum_from_value() { let expected = Enum::make(); let actual = <[Enum; 3]>::from_value(Enum::value()).unwrap(); assert_eq!(expected, actual); } #[test] fn enum_roundtrip() { let expected = Enum::make(); let actual = <[Enum; 3]>::from_value(Enum::make().into_test_value()).unwrap(); assert_eq!(expected, actual); let expected = Enum::value(); let actual = <[Enum; 3]>::from_value(Enum::value()) .unwrap() .into_test_value(); assert_eq!(expected, actual); } #[test] fn enum_unknown_variant() { let value = Value::test_string("delta_four"); let res = Enum::from_value(value); assert!(res.is_err()); } #[test] fn enum_incorrect_type() { // Should work for every type that is not a record. let value = Value::test_nothing(); let res = Enum::from_value(value); assert!(res.is_err()); } mod enum_rename_all { use super::*; use crate as nu_protocol; // Generate the `Enum` from before but with all possible `rename_all` variants. macro_rules! enum_rename_all { ($($ident:ident: $case:literal => [$a1:literal, $b2:literal, $c3:literal]),*) => { $( #[derive(Debug, PartialEq, IntoValue, FromValue)] #[nu_value(rename_all = $case)] enum $ident { AlphaOne, BetaTwo, CharlieThree } impl $ident { fn make() -> [Self; 3] { [Self::AlphaOne, Self::BetaTwo, Self::CharlieThree] } fn value() -> Value { Value::test_list(vec![ Value::test_string($a1), Value::test_string($b2), Value::test_string($c3), ]) } } )* #[test] fn into_value() {$({ let expected = $ident::value(); let actual = $ident::make().into_test_value(); assert_eq!(expected, actual); })*} #[test] fn from_value() {$({ let expected = $ident::make(); let actual = <[$ident; 3]>::from_value($ident::value()).unwrap(); assert_eq!(expected, actual); })*} } } enum_rename_all! { Upper: "UPPER CASE" => ["ALPHA ONE", "BETA TWO", "CHARLIE THREE"], Lower: "lower case" => ["alpha one", "beta two", "charlie three"], Title: "Title Case" => ["Alpha One", "Beta Two", "Charlie Three"], Camel: "camelCase" => ["alphaOne", "betaTwo", "charlieThree"], Pascal: "PascalCase" => ["AlphaOne", "BetaTwo", "CharlieThree"], Snake: "snake_case" => ["alpha_one", "beta_two", "charlie_three"], UpperSnake: "UPPER_SNAKE_CASE" => ["ALPHA_ONE", "BETA_TWO", "CHARLIE_THREE"], Kebab: "kebab-case" => ["alpha-one", "beta-two", "charlie-three"], Cobol: "COBOL-CASE" => ["ALPHA-ONE", "BETA-TWO", "CHARLIE-THREE"], Train: "Train-Case" => ["Alpha-One", "Beta-Two", "Charlie-Three"], Flat: "flatcase" => ["alphaone", "betatwo", "charliethree"], UpperFlat: "UPPERFLATCASE" => ["ALPHAONE", "BETATWO", "CHARLIETHREE"] } } mod named_fields_struct_rename_all { use super::*; use crate as nu_protocol; macro_rules! named_fields_struct_rename_all { ($($ident:ident: $case:literal => [$a1:literal, $b2:literal, $c3:literal]),*) => { $( #[derive(Debug, PartialEq, IntoValue, FromValue)] #[nu_value(rename_all = $case)] struct $ident { alpha_one: (), beta_two: (), charlie_three: (), } impl $ident { fn make() -> Self { Self { alpha_one: (), beta_two: (), charlie_three: (), } } fn value() -> Value { Value::test_record(record! { $a1 => Value::test_nothing(), $b2 => Value::test_nothing(), $c3 => Value::test_nothing(), }) } } )* #[test] fn into_value() {$({ let expected = $ident::value(); let actual = $ident::make().into_test_value(); assert_eq!(expected, actual); })*} #[test] fn from_value() {$({ let expected = $ident::make(); let actual = $ident::from_value($ident::value()).unwrap(); assert_eq!(expected, actual); })*} } } named_fields_struct_rename_all! { Upper: "UPPER CASE" => ["ALPHA ONE", "BETA TWO", "CHARLIE THREE"], Lower: "lower case" => ["alpha one", "beta two", "charlie three"], Title: "Title Case" => ["Alpha One", "Beta Two", "Charlie Three"], Camel: "camelCase" => ["alphaOne", "betaTwo", "charlieThree"], Pascal: "PascalCase" => ["AlphaOne", "BetaTwo", "CharlieThree"], Snake: "snake_case" => ["alpha_one", "beta_two", "charlie_three"], UpperSnake: "UPPER_SNAKE_CASE" => ["ALPHA_ONE", "BETA_TWO", "CHARLIE_THREE"], Kebab: "kebab-case" => ["alpha-one", "beta-two", "charlie-three"], Cobol: "COBOL-CASE" => ["ALPHA-ONE", "BETA-TWO", "CHARLIE-THREE"], Train: "Train-Case" => ["Alpha-One", "Beta-Two", "Charlie-Three"], Flat: "flatcase" => ["alphaone", "betatwo", "charliethree"], UpperFlat: "UPPERFLATCASE" => ["ALPHAONE", "BETATWO", "CHARLIETHREE"] } } #[derive(IntoValue, FromValue, Debug, PartialEq)] struct ByteContainer { vec: Vec, bytes: Bytes, } impl ByteContainer { fn make() -> Self { ByteContainer { vec: vec![1, 2, 3], bytes: Bytes::from_static(&[4, 5, 6]), } } fn value() -> Value { Value::test_record(record! { "vec" => Value::test_list(vec![ Value::test_int(1), Value::test_int(2), Value::test_int(3), ]), "bytes" => Value::test_binary(vec![4, 5, 6]), }) } } #[test] fn bytes_into_value() { let expected = ByteContainer::value(); let actual = ByteContainer::make().into_test_value(); assert_eq!(expected, actual); } #[test] fn bytes_from_value() { let expected = ByteContainer::make(); let actual = ByteContainer::from_value(ByteContainer::value()).unwrap(); assert_eq!(expected, actual); } #[test] fn bytes_roundtrip() { let expected = ByteContainer::make(); let actual = ByteContainer::from_value(ByteContainer::make().into_test_value()).unwrap(); assert_eq!(expected, actual); let expected = ByteContainer::value(); let actual = ByteContainer::from_value(ByteContainer::value()) .unwrap() .into_test_value(); assert_eq!(expected, actual); } #[test] fn struct_type_name_attr() { #[derive(FromValue, Debug)] #[nu_value(type_name = "struct")] struct TypeNameStruct; assert_eq!( TypeNameStruct::expected_type().to_string().as_str(), "struct" ); } #[test] fn enum_type_name_attr() { #[derive(FromValue, Debug)] #[nu_value(type_name = "enum")] struct TypeNameEnum; assert_eq!(TypeNameEnum::expected_type().to_string().as_str(), "enum"); }