use std::{net::SocketAddr, path::PathBuf, str::FromStr};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("invalid bind address: {0}")]
InvalidAddress(String),
#[error("invalid session-cookie-secure policy: {0:?} (expected one of: auto, always, never)")]
InvalidCookiePolicy(String),
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, clap::ValueEnum)]
pub enum SessionCookieSecurePolicy {
#[default]
Auto,
Always,
Never,
}
impl FromStr for SessionCookieSecurePolicy {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"auto" => Ok(Self::Auto),
"always" => Ok(Self::Always),
"never" => Ok(Self::Never),
_ => Err(Error::InvalidCookiePolicy(s.to_owned())),
}
}
}
impl std::fmt::Display for SessionCookieSecurePolicy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Auto => write!(f, "auto"),
Self::Always => write!(f, "always"),
Self::Never => write!(f, "never"),
}
}
}
#[derive(Debug, Clone)]
pub struct Config {
pub dns_addrs: Vec<SocketAddr>,
pub admin_addr: SocketAddr,
pub db_path: PathBuf,
pub session_cookie_secure: SessionCookieSecurePolicy,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cookie_policy_default_is_auto() {
assert_eq!(
SessionCookieSecurePolicy::default(),
SessionCookieSecurePolicy::Auto
);
}
#[test]
fn cookie_policy_from_str_auto() {
assert_eq!(
"auto".parse::<SessionCookieSecurePolicy>().unwrap(),
SessionCookieSecurePolicy::Auto
);
}
#[test]
fn cookie_policy_from_str_always() {
assert_eq!(
"always".parse::<SessionCookieSecurePolicy>().unwrap(),
SessionCookieSecurePolicy::Always
);
}
#[test]
fn cookie_policy_from_str_never() {
assert_eq!(
"never".parse::<SessionCookieSecurePolicy>().unwrap(),
SessionCookieSecurePolicy::Never
);
}
#[test]
fn cookie_policy_from_str_case_insensitive() {
assert_eq!(
"AUTO".parse::<SessionCookieSecurePolicy>().unwrap(),
SessionCookieSecurePolicy::Auto
);
assert_eq!(
"Always".parse::<SessionCookieSecurePolicy>().unwrap(),
SessionCookieSecurePolicy::Always
);
}
#[test]
fn cookie_policy_from_str_invalid() {
let err = "invalid".parse::<SessionCookieSecurePolicy>().unwrap_err();
assert!(matches!(err, Error::InvalidCookiePolicy(_)));
assert!(err.to_string().contains("invalid"));
}
#[test]
fn cookie_policy_display() {
assert_eq!(SessionCookieSecurePolicy::Auto.to_string(), "auto");
assert_eq!(SessionCookieSecurePolicy::Always.to_string(), "always");
assert_eq!(SessionCookieSecurePolicy::Never.to_string(), "never");
}
#[test]
fn error_invalid_address_is_display() {
let e = Error::InvalidAddress("not-an-address".into());
assert!(e.to_string().contains("not-an-address"));
}
#[test]
fn error_invalid_cookie_policy_is_display() {
let e = Error::InvalidCookiePolicy("bogus".into());
assert!(e.to_string().contains("bogus"));
}
}