From 0f23dc50e83e862459a011c9fca2a7af1481d27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Vandecr=C3=A8me?= Date: Wed, 20 Nov 2024 13:25:06 +0100 Subject: [PATCH] Improve error messages when deserializing enums --- src/de.rs | 14 ++++++++++---- tests/test.rs | 44 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/de.rs b/src/de.rs index 5b64138d8..53dddfa7b 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1873,7 +1873,14 @@ impl<'de, R: Read<'de>> de::Deserializer<'de> for &mut Deserializer { Some(b'{') => { check_recursion! { self.eat_char(); - let ret = visitor.visit_enum(VariantAccess::new(self)); + let ret = match tri!(self.parse_whitespace()) { + Some(b'}') => Err(self.fix_position(de::Error::invalid_value( + Unexpected::Other("empty map"), + &"enum variant", + ))), + Some(_) => visitor.visit_enum(VariantAccess::new(self)), + None => Err(self.error(ErrorCode::EofWhileParsingObject)), + }; } let value = tri!(ret); @@ -1882,12 +1889,11 @@ impl<'de, R: Read<'de>> de::Deserializer<'de> for &mut Deserializer { self.eat_char(); Ok(value) } - Some(_) => Err(self.error(ErrorCode::ExpectedSomeValue)), + Some(_) => Err(self.error(ErrorCode::ExpectedObjectCommaOrEnd)), None => Err(self.error(ErrorCode::EofWhileParsingObject)), } } - Some(b'"') => visitor.visit_enum(UnitVariantAccess::new(self)), - Some(_) => Err(self.peek_error(ErrorCode::ExpectedSomeValue)), + Some(_) => visitor.visit_enum(UnitVariantAccess::new(self)), None => Err(self.peek_error(ErrorCode::EofWhileParsingValue)), } } diff --git a/tests/test.rs b/tests/test.rs index d41a2336a..a6b277810 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -70,6 +70,12 @@ enum Animal { AntHive(Vec), } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +enum BoardGame { + Chess, + Checkers, +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] struct Inner { a: (), @@ -1304,12 +1310,15 @@ fn test_parse_option() { fn test_parse_enum_errors() { test_parse_err::( &[ - ("{}", "expected value at line 1 column 2"), - ("[]", "expected value at line 1 column 1"), + ("{}", "invalid value: empty map, expected enum variant at line 1 column 1"), + ("[]", "invalid type: sequence, expected variant identifier at line 1 column 0"), + ("true", "invalid type: boolean `true`, expected variant identifier at line 1 column 4"), ("\"unknown\"", "unknown variant `unknown`, expected one of `Dog`, `Frog`, `Cat`, `AntHive` at line 1 column 9"), ("{\"unknown\":null}", "unknown variant `unknown`, expected one of `Dog`, `Frog`, `Cat`, `AntHive` at line 1 column 10"), + ("{\"AntHive\": []", "EOF while parsing an object at line 1 column 14"), + ("{\"AntHive\": []\"", "expected `,` or `}` at line 1 column 14"), ("{\"Dog\":", "EOF while parsing a value at line 1 column 7"), ("{\"Dog\":}", "expected value at line 1 column 8"), ("{\"Dog\":{}}", "invalid type: map, expected unit at line 1 column 7"), @@ -1331,6 +1340,37 @@ fn test_parse_enum_errors() { ); } +#[test] +fn test_parse_value_less_enum_errors() { + test_parse_err::(&[ + ( + "1", + "invalid type: integer `1`, expected variant identifier at line 1 column 1", + ), + ( + "null", + "invalid type: null, expected variant identifier at line 1 column 4", + ), + ( + "true", + "invalid type: boolean `true`, expected variant identifier at line 1 column 4", + ), + ( + "[]", + "invalid type: sequence, expected variant identifier at line 1 column 0", + ), + ("{}", "invalid value: empty map, expected enum variant"), + ( + "{\"unknown\": \"unknown\"}", + "unknown variant `unknown`, expected `Chess` or `Checkers` at line 1 column 10", + ), + ( + "{\"Chess\": \"unknown\"}", + "invalid type: string \"unknown\", expected unit at line 1 column 19", + ), + ]); +} + #[test] fn test_parse_enum() { test_parse_ok(vec![