238 lines
6.4 KiB
Rust
238 lines
6.4 KiB
Rust
use crate::error::Error;
|
|
use estring::EString;
|
|
use std::convert::TryFrom;
|
|
|
|
pub fn get_or_set_default<R>(env_name: &str, default: R) -> Result<R, Error>
|
|
where
|
|
R: TryFrom<EString> + std::fmt::Display,
|
|
{
|
|
get::<R>(env_name).or_else(|err| match err {
|
|
Error::NotPresent => sset(env_name, &default).parse().map_err(Error::from),
|
|
_ => Err(err),
|
|
})
|
|
}
|
|
|
|
pub fn get<R>(env_name: &str) -> Result<R, Error>
|
|
where
|
|
R: TryFrom<EString>,
|
|
{
|
|
sget(env_name).and_then(|v| v.parse().map_err(Error::from))
|
|
}
|
|
|
|
pub fn sget(env_name: &str) -> Result<EString, Error> {
|
|
std::env::var(env_name)
|
|
.map_err(Error::from)
|
|
.map(EString::from)
|
|
}
|
|
|
|
pub fn sset<V>(env_name: &str, value: V) -> EString
|
|
where
|
|
V: std::fmt::Display,
|
|
{
|
|
let val = value.to_string();
|
|
std::env::set_var(env_name, &val);
|
|
val.into()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
struct TestCase<const N: u8>;
|
|
|
|
impl<const N: u8> std::fmt::Display for TestCase<N> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "test_case_{}", N)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn should_add_env_variable_to_process() {
|
|
let en = TestCase::<0>.to_string();
|
|
sset(&en, "hello");
|
|
match std::env::var(&en) {
|
|
Ok(var) => assert_eq!(&var, "hello"),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn should_return_variable() {
|
|
let en = TestCase::<1>.to_string();
|
|
std::env::set_var(&en, "hello");
|
|
match get::<&str>(&en) {
|
|
Ok(res) => assert_eq!(res, "hello"),
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_throw_no_present_error() {
|
|
let en = TestCase::<2>.to_string();
|
|
match get::<&str>(&en) {
|
|
Err(Error::NotPresent) => {}
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_set_default_if_var_is_no_present() {
|
|
let en = TestCase::<3>.to_string();
|
|
let orig = "hello";
|
|
match get_or_set_default(&en, orig) {
|
|
Ok(res) => {
|
|
assert_eq!(res, orig);
|
|
assert_eq!(std::env::var(&en).unwrap(), orig);
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[cfg(feature = "number")]
|
|
mod numbers {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn should_return_parsed_num() {
|
|
let en = TestCase::<4>.to_string();
|
|
std::env::set_var(&en, "-10");
|
|
match get::<i32>(&en) {
|
|
Ok(res) => assert_eq!(res, -10),
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_throw_parse_error() {
|
|
let en = TestCase::<5>.to_string();
|
|
std::env::set_var(&en, "-10");
|
|
match get::<u32>(&en) {
|
|
Err(Error::Parse(orig)) => {
|
|
assert_eq!(orig, String::from("-10"))
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_set_default_num_if_var_is_no_present() {
|
|
let en = TestCase::<6>.to_string();
|
|
let orig = 10;
|
|
match get_or_set_default(&en, orig) {
|
|
Ok(res) => {
|
|
assert_eq!(res, orig);
|
|
assert_eq!(std::env::var(&en).unwrap(), "10");
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "bool")]
|
|
mod boolean {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn should_parse_bool_variable() {
|
|
let en = TestCase::<7>.to_string();
|
|
|
|
[
|
|
("1", true),
|
|
("y", true),
|
|
("yes", true),
|
|
("true", true),
|
|
("t", true),
|
|
("on", true),
|
|
("false", false),
|
|
("f", false),
|
|
("0", false),
|
|
]
|
|
.iter()
|
|
.for_each(|(val, expected)| {
|
|
let mut en = en.clone();
|
|
en.push_str(val.as_ref());
|
|
|
|
std::env::set_var(&en, val);
|
|
match get::<bool>(&en) {
|
|
Ok(res) => assert_eq!(res, *expected),
|
|
_ => unreachable!(),
|
|
};
|
|
})
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "vec")]
|
|
mod vector {
|
|
use super::*;
|
|
use crate::estr::{CommaVec, SemiVec, SepVec};
|
|
|
|
#[test]
|
|
fn should_return_var_as_vector() {
|
|
let en = TestCase::<8>.to_string();
|
|
|
|
std::env::set_var(&en, "1,2,3,4,5");
|
|
match get::<CommaVec<i32>>(&en) {
|
|
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_trim_identations_before_parsing() {
|
|
let en = TestCase::<9>.to_string();
|
|
|
|
let input = "
|
|
1 , 2, 3,
|
|
4,5";
|
|
|
|
std::env::set_var(&en, input);
|
|
match get::<CommaVec<i32>>(&en) {
|
|
Ok(res) => assert_eq!(*res, vec![1, 2, 3, 4, 5]),
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_return_vector_of_vectors() {
|
|
let en = TestCase::<10>.to_string();
|
|
|
|
std::env::set_var(&en, "1,2; 3,4,5; 6,7");
|
|
match get::<SemiVec<CommaVec<i32>>>(&en) {
|
|
Ok(res) => assert_eq!(
|
|
res,
|
|
SemiVec::from(vec![
|
|
CommaVec::from(vec![1, 2]),
|
|
CommaVec::from(vec![3, 4, 5]),
|
|
CommaVec::from(vec![6, 7])
|
|
])
|
|
),
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_throw_parse_vec_error() {
|
|
let en = TestCase::<11>.to_string();
|
|
std::env::set_var(&en, "1,2,3,4,5");
|
|
match get::<SepVec<i32, '+'>>(&en) {
|
|
Err(Error::Parse(orig)) => {
|
|
assert_eq!(orig, String::from("1,2,3,4,5"))
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn should_set_default_vector_if_var_is_no_present() {
|
|
let en = TestCase::<12>.to_string();
|
|
let orig = CommaVec::from(vec![1, 2, 3, 4]);
|
|
match get_or_set_default(&en, orig.clone()) {
|
|
Ok(res) => {
|
|
assert_eq!(res, orig);
|
|
assert_eq!(std::env::var(&en).unwrap(), "1,2,3,4");
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
}
|
|
}
|
|
}
|