Skip to content

Commit fd203fb

Browse files
authored
feat: Improve errors from try_deserialize (#695)
Enables user code to handle missing and invalid fields after calling try_deserialize instead of having to match and search in the string returned in `ConfigError::Message`. Personally I deem the `String::leak` call safe for my usage, as I would expect to terminate my program on configuration errors anyhow, however we could certainly also change the `expected` field to be a `Cow<str>` or similar to handle both `&'static str` and `String` elegantly. Part of #532
2 parents a227d43 + 753165a commit fd203fb

File tree

10 files changed

+19
-15
lines changed

10 files changed

+19
-15
lines changed

src/error.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ impl fmt::Display for ConfigError {
230230
ConfigError::Foreign(ref cause) => write!(f, "{cause}"),
231231

232232
ConfigError::NotFound(ref key) => {
233-
write!(f, "configuration property {key:?} not found")
233+
write!(f, "missing configuration field {key:?}")
234234
}
235235

236236
ConfigError::Type {
@@ -289,6 +289,10 @@ impl de::Error for ConfigError {
289289
fn custom<T: fmt::Display>(msg: T) -> Self {
290290
Self::Message(msg.to_string())
291291
}
292+
293+
fn missing_field(field: &'static str) -> Self {
294+
Self::NotFound(field.into())
295+
}
292296
}
293297

294298
impl ser::Error for ConfigError {

tests/testsuite/errors.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn test_path_index_bounds() {
2222
assert!(res.is_err());
2323
assert_data_eq!(
2424
res.unwrap_err().to_string(),
25-
str![[r#"configuration property "arr[2]" not found"#]]
25+
str![[r#"missing configuration field "arr[2]""#]]
2626
);
2727
}
2828

@@ -45,7 +45,7 @@ fn test_path_index_negative_bounds() {
4545
assert!(res.is_err());
4646
assert_data_eq!(
4747
res.unwrap_err().to_string(),
48-
str![[r#"configuration property "arr[-1]" not found"#]]
48+
str![[r#"missing configuration field "arr[-1]""#]]
4949
);
5050
}
5151

@@ -158,7 +158,7 @@ fn test_get_missing_field() {
158158
let res = c.get::<InnerSettings>("inner");
159159
assert_data_eq!(
160160
res.unwrap_err().to_string(),
161-
str!["missing field `value2` for key `inner`"]
161+
str![[r#"missing configuration field "value2" for key `inner`"#]]
162162
);
163163
}
164164

@@ -184,7 +184,7 @@ fn test_get_missing_field_file() {
184184
let res = c.get::<InnerSettings>("inner");
185185
assert_data_eq!(
186186
res.unwrap_err().to_string(),
187-
str!["missing field `value2` for key `inner`"]
187+
str![[r#"missing configuration field "value2" for key `inner`"#]]
188188
);
189189
}
190190

@@ -436,7 +436,7 @@ fn test_deserialize_missing_field() {
436436
let res = c.try_deserialize::<Settings>();
437437
assert_data_eq!(
438438
res.unwrap_err().to_string(),
439-
str!["missing field `value2` for key `inner`"]
439+
str![[r#"missing configuration field "inner.value2""#]]
440440
);
441441
}
442442

@@ -468,6 +468,6 @@ fn test_deserialize_missing_field_file() {
468468
let res = c.try_deserialize::<Settings>();
469469
assert_data_eq!(
470470
res.unwrap_err().to_string(),
471-
str!["missing field `value2` for key `inner`"]
471+
str![[r#"missing configuration field "inner.value2""#]]
472472
);
473473
}

tests/testsuite/file_corn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ fn test_override_uppercase_value_for_struct() {
185185
);
186186
}
187187
Err(e) => {
188-
if e.to_string().contains("missing field `FOO`") {
188+
if matches!(e, config::ConfigError::NotFound(_)) {
189189
assert_eq!(
190190
lower_settings.foo,
191191
"I HAVE BEEN OVERRIDDEN_WITH_UPPER_CASE".to_owned()

tests/testsuite/file_ini.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ rating = 4.5
128128
);
129129
}
130130
Err(e) => {
131-
if e.to_string().contains("missing field `FOO`") {
131+
if matches!(e, config::ConfigError::NotFound(_)) {
132132
assert_eq!(
133133
lower_settings.foo,
134134
"I HAVE BEEN OVERRIDDEN_WITH_UPPER_CASE".to_owned()

tests/testsuite/file_json.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ fn test_override_uppercase_value_for_struct() {
178178
);
179179
}
180180
Err(e) => {
181-
if e.to_string().contains("missing field `FOO`") {
181+
if matches!(e, config::ConfigError::NotFound(_)) {
182182
println!("triggered error {e:?}");
183183
assert_eq!(
184184
lower_settings.foo,

tests/testsuite/file_json5.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ fn test_override_uppercase_value_for_struct() {
187187
);
188188
}
189189
Err(e) => {
190-
if e.to_string().contains("missing field `FOO`") {
190+
if matches!(e, config::ConfigError::NotFound(_)) {
191191
assert_eq!(
192192
lower_settings.foo,
193193
"I HAVE BEEN OVERRIDDEN_WITH_UPPER_CASE".to_owned()

tests/testsuite/file_ron.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ fn test_override_uppercase_value_for_struct() {
179179
);
180180
}
181181
Err(e) => {
182-
if e.to_string().contains("missing field `FOO`") {
182+
if matches!(e, config::ConfigError::NotFound(_)) {
183183
assert_eq!(
184184
lower_settings.foo,
185185
"I HAVE BEEN OVERRIDDEN_WITH_UPPER_CASE".to_owned()

tests/testsuite/file_toml.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ down = 1
266266
);
267267
}
268268
Err(e) => {
269-
if e.to_string().contains("missing field `FOO`") {
269+
if matches!(e, config::ConfigError::NotFound(_)) {
270270
assert_eq!(
271271
lower_settings.foo,
272272
"I HAVE BEEN OVERRIDDEN_WITH_UPPER_CASE".to_owned()

tests/testsuite/file_yaml.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ bar: I am bar
210210
);
211211
}
212212
Err(e) => {
213-
if e.to_string().contains("missing field `FOO`") {
213+
if matches!(e, config::ConfigError::NotFound(_)) {
214214
println!("triggered error {e:?}");
215215
assert_eq!(
216216
lower_settings.foo,

tests/testsuite/get.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn test_not_found() {
1818
assert!(res.is_err());
1919
assert_data_eq!(
2020
res.unwrap_err().to_string(),
21-
str![[r#"configuration property "not_found" not found"#]]
21+
str![[r#"missing configuration field "not_found""#]]
2222
);
2323
}
2424

0 commit comments

Comments
 (0)