use confroid::{ConfroidError, from_pairs};
use std::fmt;
use std::str::FromStr;
#[derive(Debug)]
struct ParseModeError(String);
impl fmt::Display for ParseModeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "unknown mode `{}`", self.0)
}
}
impl std::error::Error for ParseModeError {}
#[derive(confroid::ConfigValue, Debug, Clone, Copy, PartialEq, Eq)]
enum Mode {
Standalone,
Cluster,
}
impl FromStr for Mode {
type Err = ParseModeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"standalone" => Ok(Mode::Standalone),
"cluster" => Ok(Mode::Cluster),
other => Err(ParseModeError(other.to_string())),
}
}
}
impl fmt::Display for Mode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Mode::Standalone => "standalone",
Mode::Cluster => "cluster",
})
}
}
#[derive(confroid::Config, Debug)]
struct Config {
mode: Mode,
#[confroid(default = Mode::Standalone)]
fallback: Mode,
maybe: Option<Mode>,
tags: Vec<Mode>,
}
#[test]
fn reads_enum_fields() {
let config: Config = from_pairs([
("MODE", "cluster"),
("FALLBACK", "cluster"),
("MAYBE", "standalone"),
("TAGS__0", "standalone"),
("TAGS__1", "cluster"),
])
.unwrap();
assert_eq!(config.mode, Mode::Cluster);
assert_eq!(config.fallback, Mode::Cluster);
assert_eq!(config.maybe, Some(Mode::Standalone));
assert_eq!(config.tags, vec![Mode::Standalone, Mode::Cluster]);
}
#[test]
fn case_insensitive_via_from_str() {
let config: Config = from_pairs([("MODE", "CLUSTER"), ("TAGS__0", "Standalone")]).unwrap();
assert_eq!(config.mode, Mode::Cluster);
assert_eq!(config.tags, vec![Mode::Standalone]);
}
#[test]
fn default_applies_when_unset() {
let config: Config = from_pairs([("MODE", "standalone"), ("TAGS__0", "cluster")]).unwrap();
assert_eq!(config.fallback, Mode::Standalone);
assert_eq!(config.maybe, None);
}
#[test]
fn invalid_enum_value_errors() {
let err =
from_pairs::<Config, _, _, _>([("MODE", "bogus"), ("TAGS__0", "cluster")]).unwrap_err();
match err {
ConfroidError::EnvVarInvalid { field, value, .. } => {
assert_eq!(field, "mode");
assert_eq!(value, "bogus");
}
other => panic!("expected EnvVarInvalid, got {other:?}"),
}
}
#[test]
fn missing_required_enum_errors() {
let err = from_pairs::<Config, _, _, _>([("TAGS__0", "cluster")]).unwrap_err();
assert!(matches!(
err,
ConfroidError::EnvVarNotFound { var_name, field }
if var_name == "MODE" && field == "mode"
));
}