diff --git a/src/error.rs b/src/error.rs index 59ba964..d2c8ee3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,7 +4,7 @@ use std::{error::Error as StdError, fmt}; /// Types of errors that may result from failed attempts /// to deserialize a type from env vars -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Error { MissingValue(String), Custom(String), diff --git a/src/lib.rs b/src/lib.rs index fd59d0a..83181cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,9 +103,7 @@ impl> Iterator for Vars { type Item = (VarName, Val); fn next(&mut self) -> Option { - self.0 - .next() - .map(|(k, v)| (VarName(k.to_lowercase()), Val(k, v))) + self.0.next().map(|(k, v)| (VarName(k.clone()), Val(k, v))) } } @@ -306,10 +304,7 @@ where T: de::DeserializeOwned, Iter: IntoIterator, { - T::deserialize(Deserializer::new(iter.into_iter())).map_err(|error| match error { - Error::MissingValue(value) => Error::MissingValue(value.to_uppercase()), - _ => error, - }) + T::deserialize(Deserializer::new(iter.into_iter())) } /// A type which filters env vars with a prefix for use as serde field inputs @@ -343,9 +338,9 @@ impl<'a> Prefixed<'a> { } })) .map_err(|error| match error { - Error::MissingValue(value) => Error::MissingValue( - format!("{prefix}{value}", prefix = self.0, value = value).to_uppercase(), - ), + Error::MissingValue(value) => { + Error::MissingValue(format!("{prefix}{value}", prefix = self.0, value = value)) + } _ => error, }) } @@ -427,14 +422,14 @@ mod tests { #[test] fn deserialize_from_iter() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("true")), - (String::from("DOOM"), String::from("1, 2, 3 ")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("true")), + (String::from("doom"), String::from("1, 2, 3 ")), // Empty string should result in empty vector. - (String::from("BOOM"), String::from("")), - (String::from("SIZE"), String::from("small")), - (String::from("PROVIDED"), String::from("test")), - (String::from("NEWTYPE"), String::from("42")), + (String::from("boom"), String::from("")), + (String::from("size"), String::from("small")), + (String::from("provided"), String::from("test")), + (String::from("newtype"), String::from("42")), ]; match from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( @@ -459,40 +454,40 @@ mod tests { #[test] fn fails_with_missing_value() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("true")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("true")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("DOOM".into())), + Err(e) => assert_eq!(e, Error::MissingValue("doom".into())), } } #[test] fn prefixed_fails_with_missing_value() { let data = vec![ - (String::from("PREFIX_BAR"), String::from("test")), - (String::from("PREFIX_BAZ"), String::from("true")), + (String::from("PREFIX_bar"), String::from("test")), + (String::from("PREFIX_baz"), String::from("true")), ]; match prefixed("PREFIX_").from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("PREFIX_DOOM".into())), + Err(e) => assert_eq!(e, Error::MissingValue("PREFIX_doom".into())), } } #[test] fn fails_with_invalid_type() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("notabool")), - (String::from("DOOM"), String::from("1,2,3")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("notabool")), + (String::from("doom"), String::from("1,2,3")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), Err(e) => assert_eq!( e, - Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by BAZ")) + Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by baz")) ), } } @@ -500,13 +495,13 @@ mod tests { #[test] fn deserializes_from_prefixed_fieldnames() { let data = vec![ - (String::from("APP_BAR"), String::from("test")), - (String::from("APP_BAZ"), String::from("true")), - (String::from("APP_DOOM"), String::from("")), - (String::from("APP_BOOM"), String::from("4,5")), - (String::from("APP_SIZE"), String::from("small")), - (String::from("APP_PROVIDED"), String::from("test")), - (String::from("APP_NEWTYPE"), String::from("42")), + (String::from("APP_bar"), String::from("test")), + (String::from("APP_baz"), String::from("true")), + (String::from("APP_doom"), String::from("")), + (String::from("APP_boom"), String::from("4,5")), + (String::from("APP_size"), String::from("small")), + (String::from("APP_provided"), String::from("test")), + (String::from("APP_newtype"), String::from("42")), ]; match prefixed("APP_").from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( @@ -533,7 +528,7 @@ mod tests { let mut expected = HashMap::new(); expected.insert("foo".to_string(), "bar".to_string()); assert_eq!( - prefixed("PRE_").from_iter(vec![("PRE_FOO".to_string(), "bar".to_string())]), + prefixed("PRE_").from_iter(vec![("PRE_foo".to_string(), "bar".to_string())]), Ok(expected) ); } @@ -544,10 +539,39 @@ mod tests { expected.insert("foo".to_string(), 12); assert_eq!( prefixed("PRE_").from_iter(vec![ - ("FOO".to_string(), "asd".to_string()), - ("PRE_FOO".to_string(), "12".to_string()) + ("foo".to_string(), "asd".to_string()), + ("PRE_foo".to_string(), "12".to_string()) ]), Ok(expected) ); } + + #[test] + fn deserialize_with_rename_attributes() { + #[derive(Deserialize, Debug, PartialEq)] + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] + pub struct FooRename { + bar: String, + bar_snake: String, + #[serde(rename = "FooRename")] + foo: String, + } + + let data = vec![ + (String::from("BAR"), String::from("dummy string 1")), + (String::from("BAR_SNAKE"), String::from("dummy string 2")), + (String::from("FooRename"), String::from("dummy string 3")), + ]; + match from_iter::<_, FooRename>(data) { + Ok(actual) => assert_eq!( + actual, + FooRename { + bar: String::from("dummy string 1"), + bar_snake: String::from("dummy string 2"), + foo: String::from("dummy string 3"), + } + ), + Err(e) => panic!("{:#?}", e), + } + } }