From fcc4a58617ea27a061f445b576e3fafc91ad6998 Mon Sep 17 00:00:00 2001 From: Azriel Hoh Date: Mon, 22 Oct 2018 09:40:16 +1300 Subject: Implemented deserialization for external enums. Issue #225 --- tests/enum_external_deserialize.rs | 153 +++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 tests/enum_external_deserialize.rs (limited to 'tests') diff --git a/tests/enum_external_deserialize.rs b/tests/enum_external_deserialize.rs new file mode 100644 index 0000000..76e7a4c --- /dev/null +++ b/tests/enum_external_deserialize.rs @@ -0,0 +1,153 @@ +#[macro_use] +extern crate serde_derive; +extern crate toml; + +#[derive(Debug, Deserialize, PartialEq)] +enum TheEnum { + Plain, + Tuple(i64, bool), + NewType(String), + Struct { value: i64 }, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Val { + val: TheEnum, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Multi { + enums: Vec, +} + +mod enum_unit { + use super::*; + + #[test] + fn from_str() { + assert_eq!(TheEnum::Plain, toml::from_str("\"Plain\"").unwrap()); + } + + #[test] + fn from_inline_table() { + assert_eq!(TheEnum::Plain, toml::from_str("{ Plain = {} }").unwrap()); + assert_eq!( + Val { + val: TheEnum::Plain + }, + toml::from_str("val = { Plain = {} }").unwrap() + ); + } + + #[test] + fn from_dotted_table() { + assert_eq!(TheEnum::Plain, toml::from_str("[Plain]\n").unwrap()); + } +} + +mod enum_tuple { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::Tuple(-123, true), + toml::from_str("{ Tuple = { 0 = -123, 1 = true } }").unwrap() + ); + assert_eq!( + Val { + val: TheEnum::Tuple(-123, true) + }, + toml::from_str("val = { Tuple = { 0 = -123, 1 = true } }").unwrap() + ); + } + + #[test] + fn from_dotted_table() { + assert_eq!( + TheEnum::Tuple(-123, true), + toml::from_str( + r#"[Tuple] + 0 = -123 + 1 = true + "# + ) + .unwrap() + ); + } +} + +mod enum_newtype { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::NewType("value".to_string()), + toml::from_str(r#"{ NewType = "value" }"#).unwrap() + ); + assert_eq!( + Val { + val: TheEnum::NewType("value".to_string()), + }, + toml::from_str(r#"val = { NewType = "value" }"#).unwrap() + ); + } +} + +mod enum_struct { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::Struct { value: -123 }, + toml::from_str("{ Struct = { value = -123 } }").unwrap() + ); + assert_eq!( + Val { + val: TheEnum::Struct { value: -123 } + }, + toml::from_str("val = { Struct = { value = -123 } }").unwrap() + ); + } + + #[test] + fn from_dotted_table() { + assert_eq!( + TheEnum::Struct { value: -123 }, + toml::from_str( + r#"[Struct] + value = -123 + "# + ) + .unwrap() + ); + } +} + +mod enum_array { + use super::*; + + #[test] + fn from_inline_tables() { + let toml_str = r#" + enums = [ + { Plain = {} }, + { Tuple = { 0 = -123, 1 = true } }, + { NewType = "value" }, + { Struct = { value = -123 } } + ]"#; + assert_eq!( + Multi { + enums: vec![ + TheEnum::Plain, + TheEnum::Tuple(-123, true), + TheEnum::NewType("value".to_string()), + TheEnum::Struct { value: -123 }, + ] + }, + toml::from_str(toml_str).unwrap() + ); + } +} -- cgit v1.2.3 From 2c2d62981279721c87128f988148c876c1caf18c Mon Sep 17 00:00:00 2001 From: Azriel Hoh Date: Mon, 12 Nov 2018 09:00:47 +1300 Subject: Added ignored tests for deserializing enums from dotted table. Issue #225 --- tests/enum_external_deserialize.rs | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'tests') diff --git a/tests/enum_external_deserialize.rs b/tests/enum_external_deserialize.rs index 76e7a4c..3309ac6 100644 --- a/tests/enum_external_deserialize.rs +++ b/tests/enum_external_deserialize.rs @@ -93,6 +93,26 @@ mod enum_newtype { toml::from_str(r#"val = { NewType = "value" }"#).unwrap() ); } + + #[test] + #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"] + fn from_dotted_table() { + assert_eq!( + TheEnum::NewType("value".to_string()), + toml::from_str(r#"NewType = "value""#).unwrap() + ); + assert_eq!( + Val { + val: TheEnum::NewType("value".to_string()), + }, + toml::from_str( + r#"[val] + NewType = "value" + "# + ) + .unwrap() + ); + } } mod enum_struct { @@ -150,4 +170,32 @@ mod enum_array { toml::from_str(toml_str).unwrap() ); } + + #[test] + #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"] + fn from_dotted_table() { + let toml_str = r#"[[enums]] + Plain = {} + + [[enums]] + Tuple = { 0 = -123, 1 = true } + + [[enums]] + NewType = "value" + + [[enums]] + Struct = { value = -123 } + "#; + assert_eq!( + Multi { + enums: vec![ + TheEnum::Plain, + TheEnum::Tuple(-123, true), + TheEnum::NewType("value".to_string()), + TheEnum::Struct { value: -123 }, + ] + }, + toml::from_str(toml_str).unwrap() + ); + } } -- cgit v1.2.3 From 2907bd1953b15c81d4e7bfd1b060a9c9d947c2e4 Mon Sep 17 00:00:00 2001 From: Azriel Hoh Date: Mon, 12 Nov 2018 10:09:30 +1300 Subject: Error when deserializing struct if encountering unknown fields. Issue #225 --- src/de.rs | 41 ++++++++++++++++++++++++++++++++++++++ tests/enum_external_deserialize.rs | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'tests') diff --git a/src/de.rs b/src/de.rs index da30699..c7e8b34 100644 --- a/src/de.rs +++ b/src/de.rs @@ -178,6 +178,16 @@ enum ErrorKind { /// Dotted key attempted to extend something that is not a table. DottedKeyInvalidType, + /// An unexpected key was encountered. + /// + /// Used when deserializing a struct with a limited set of fields. + UnexpectedKeys { + /// The unexpected keys. + keys: Vec, + /// Keys that may be specified. + available: &'static [&'static str], + }, + #[doc(hidden)] __Nonexhaustive, } @@ -547,6 +557,28 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> { } } + match &self.value.e { + E::InlineTable(values) | E::DottedTable(values) => { + let extra_fields = values.iter() + .filter_map(|(key, _val)| { + if !fields.contains(&&(**key)) { + Some(key.clone()) + } else { + None + } + }) + .collect::>>(); + + if !extra_fields.is_empty() { + return Err(Error::from_kind(ErrorKind::UnexpectedKeys { + keys: extra_fields.iter().map(|k| k.to_string()).collect::>(), + available: fields, + })); + } + } + _ => {} + } + if name == spanned::NAME && fields == &[spanned::START, spanned::END, spanned::VALUE] { let start = self.value.start; let end = self.value.end; @@ -1653,6 +1685,14 @@ impl fmt::Display for Error { ErrorKind::DottedKeyInvalidType => { "dotted key attempted to extend non-table type".fmt(f)? } + ErrorKind::UnexpectedKeys { ref keys, available } => { + write!( + f, + "unexpected keys in table: `{:?}`, available keys: `{:?}`", + keys, + available + )? + } ErrorKind::__Nonexhaustive => panic!(), } @@ -1700,6 +1740,7 @@ impl error::Error for Error { ErrorKind::ExpectedTupleIndex { .. } => "expected table key", ErrorKind::ExpectedEmptyTable => "expected empty table", ErrorKind::DottedKeyInvalidType => "dotted key invalid type", + ErrorKind::UnexpectedKeys { .. } => "unexpected keys in table", ErrorKind::__Nonexhaustive => panic!(), } } diff --git a/tests/enum_external_deserialize.rs b/tests/enum_external_deserialize.rs index 3309ac6..e35f06a 100644 --- a/tests/enum_external_deserialize.rs +++ b/tests/enum_external_deserialize.rs @@ -20,6 +20,46 @@ struct Multi { enums: Vec, } +#[test] +fn invalid_variant_returns_error_with_good_message_string() { + let error = toml::from_str::("\"NonExistent\"") + .expect_err("Expected deserialization to fail."); + + assert_eq!( + error.to_string(), + "unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`" + ); +} + +#[test] +fn invalid_variant_returns_error_with_good_message_inline_table() { + let error = toml::from_str::("{ NonExistent = {} }") + .expect_err("Expected deserialization to fail."); + assert_eq!( + error.to_string(), + "unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`" + ); +} + +#[test] +fn extra_field_returns_expected_empty_table_error() { + let error = toml::from_str::("{ Plain = { extra_field = 404 } }") + .expect_err("Expected deserialization to fail."); + + assert_eq!(error.to_string(), "expected empty table"); +} + +#[test] +fn extra_field_returns_expected_empty_table_error_struct_variant() { + let error = toml::from_str::("{ Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }") + .expect_err("Expected deserialization to fail."); + + assert_eq!( + error.to_string(), + r#"unexpected keys in table: `["extra_0", "extra_1"]`, available keys: `["value"]`"# + ); +} + mod enum_unit { use super::*; -- cgit v1.2.3 From df7ec3a4b66433118f09b12d5f32a10368a57852 Mon Sep 17 00:00:00 2001 From: Azriel Hoh Date: Sat, 17 Nov 2018 13:47:23 +1300 Subject: Maintain backward compatibility with Rust 1.15, take 3. --- src/de.rs | 3 ++- tests/enum_external_deserialize.rs | 11 ++++------- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'tests') diff --git a/src/de.rs b/src/de.rs index 9d5a417..9b58606 100644 --- a/src/de.rs +++ b/src/de.rs @@ -568,7 +568,8 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> { match &self.value.e { &E::InlineTable(ref values) | &E::DottedTable(ref values) => { let extra_fields = values.iter() - .filter_map(|(ref key, ref _val)| { + .filter_map(|key_value| { + let (ref key, ref _val) = *key_value; if !fields.contains(&&(**key)) { Some(key.clone()) } else { diff --git a/tests/enum_external_deserialize.rs b/tests/enum_external_deserialize.rs index e35f06a..3c38580 100644 --- a/tests/enum_external_deserialize.rs +++ b/tests/enum_external_deserialize.rs @@ -22,8 +22,7 @@ struct Multi { #[test] fn invalid_variant_returns_error_with_good_message_string() { - let error = toml::from_str::("\"NonExistent\"") - .expect_err("Expected deserialization to fail."); + let error = toml::from_str::("\"NonExistent\"").unwrap_err(); assert_eq!( error.to_string(), @@ -33,8 +32,7 @@ fn invalid_variant_returns_error_with_good_message_string() { #[test] fn invalid_variant_returns_error_with_good_message_inline_table() { - let error = toml::from_str::("{ NonExistent = {} }") - .expect_err("Expected deserialization to fail."); + let error = toml::from_str::("{ NonExistent = {} }").unwrap_err(); assert_eq!( error.to_string(), "unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct`" @@ -43,8 +41,7 @@ fn invalid_variant_returns_error_with_good_message_inline_table() { #[test] fn extra_field_returns_expected_empty_table_error() { - let error = toml::from_str::("{ Plain = { extra_field = 404 } }") - .expect_err("Expected deserialization to fail."); + let error = toml::from_str::("{ Plain = { extra_field = 404 } }").unwrap_err(); assert_eq!(error.to_string(), "expected empty table"); } @@ -52,7 +49,7 @@ fn extra_field_returns_expected_empty_table_error() { #[test] fn extra_field_returns_expected_empty_table_error_struct_variant() { let error = toml::from_str::("{ Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }") - .expect_err("Expected deserialization to fail."); + .unwrap_err(); assert_eq!( error.to_string(), -- cgit v1.2.3