Error when deserializing struct if encountering unknown fields.
Issue #225
This commit is contained in:
parent
7862f04d08
commit
1656e2e51d
41
src/de.rs
41
src/de.rs
|
@ -178,6 +178,16 @@ enum ErrorKind {
|
||||||
/// Dotted key attempted to extend something that is not a table.
|
/// Dotted key attempted to extend something that is not a table.
|
||||||
DottedKeyInvalidType,
|
DottedKeyInvalidType,
|
||||||
|
|
||||||
|
/// An unexpected key was encountered.
|
||||||
|
///
|
||||||
|
/// Used when deserializing a struct with a limited set of fields.
|
||||||
|
UnexpectedKeys {
|
||||||
|
/// The unexpected keys.
|
||||||
|
keys: Vec<String>,
|
||||||
|
/// Keys that may be specified.
|
||||||
|
available: &'static [&'static str],
|
||||||
|
},
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
__Nonexhaustive,
|
__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::<Vec<Cow<'de, str>>>();
|
||||||
|
|
||||||
|
if !extra_fields.is_empty() {
|
||||||
|
return Err(Error::from_kind(ErrorKind::UnexpectedKeys {
|
||||||
|
keys: extra_fields.iter().map(|k| k.to_string()).collect::<Vec<_>>(),
|
||||||
|
available: fields,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
if name == spanned::NAME && fields == &[spanned::START, spanned::END, spanned::VALUE] {
|
if name == spanned::NAME && fields == &[spanned::START, spanned::END, spanned::VALUE] {
|
||||||
let start = self.value.start;
|
let start = self.value.start;
|
||||||
let end = self.value.end;
|
let end = self.value.end;
|
||||||
|
@ -1653,6 +1685,14 @@ impl fmt::Display for Error {
|
||||||
ErrorKind::DottedKeyInvalidType => {
|
ErrorKind::DottedKeyInvalidType => {
|
||||||
"dotted key attempted to extend non-table type".fmt(f)?
|
"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!(),
|
ErrorKind::__Nonexhaustive => panic!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1700,6 +1740,7 @@ impl error::Error for Error {
|
||||||
ErrorKind::ExpectedTupleIndex { .. } => "expected table key",
|
ErrorKind::ExpectedTupleIndex { .. } => "expected table key",
|
||||||
ErrorKind::ExpectedEmptyTable => "expected empty table",
|
ErrorKind::ExpectedEmptyTable => "expected empty table",
|
||||||
ErrorKind::DottedKeyInvalidType => "dotted key invalid type",
|
ErrorKind::DottedKeyInvalidType => "dotted key invalid type",
|
||||||
|
ErrorKind::UnexpectedKeys { .. } => "unexpected keys in table",
|
||||||
ErrorKind::__Nonexhaustive => panic!(),
|
ErrorKind::__Nonexhaustive => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,46 @@ struct Multi {
|
||||||
enums: Vec<TheEnum>,
|
enums: Vec<TheEnum>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_variant_returns_error_with_good_message_string() {
|
||||||
|
let error = toml::from_str::<TheEnum>("\"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::<TheEnum>("{ 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::<TheEnum>("{ 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::<TheEnum>("{ 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 {
|
mod enum_unit {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue