mirror of
https://github.com/darwincereska/envkit.git
synced 2026-06-11 10:23:23 -05:00
feat: added file loader
This commit is contained in:
+153
-36
@@ -1,43 +1,160 @@
|
||||
#[cfg(test)]
|
||||
mod test_main {
|
||||
use envkit::*;
|
||||
use envkit::{EnvLoader, error::EnvError};
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
#[test]
|
||||
/// Tests that `get` successfully retrieves an existing environment variable.
|
||||
fn test_get() {
|
||||
let env = EnvLoader;
|
||||
|
||||
unsafe {
|
||||
std::env::set_var("TEST_VAR", "test_value");
|
||||
}
|
||||
|
||||
assert_eq!(env.get::<String>("TEST_VAR"), Ok("test_value".to_string()));
|
||||
fn unique_key(name: &str) -> String {
|
||||
let nanos = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("system time should be after the Unix epoch")
|
||||
.as_nanos();
|
||||
|
||||
format!("ENVKIT_TEST_{name}_{nanos}")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_reads_required_typed_values() {
|
||||
let env = EnvLoader::new();
|
||||
let name_key = unique_key("NAME");
|
||||
let port_key = unique_key("PORT");
|
||||
let debug_key = unique_key("DEBUG");
|
||||
let list_key = unique_key("PORTS");
|
||||
|
||||
unsafe {
|
||||
std::env::set_var(&name_key, "envkit");
|
||||
std::env::set_var(&port_key, "3000");
|
||||
std::env::set_var(&debug_key, "yes");
|
||||
std::env::set_var(&list_key, "3000, 3001, 3002");
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests that `get_or` returns the default value when the environment variable is missing.
|
||||
fn test_get_or() {
|
||||
let env = EnvLoader;
|
||||
|
||||
unsafe {
|
||||
std::env::remove_var("MISSING_VAR");
|
||||
std::env::set_var("TEST_VAR", "test_value");
|
||||
}
|
||||
|
||||
assert_eq!(env.get_or::<String>("MISSING_VAR", "default".to_string()), "default".to_string());
|
||||
assert_eq!(env.get_or::<String>("TEST_VAR", "default".to_string()), "test_value".to_string());
|
||||
assert_eq!(env.get::<String>(&name_key), Ok("envkit".to_string()));
|
||||
assert_eq!(env.get::<u16>(&port_key), Ok(3000));
|
||||
assert_eq!(env.get::<bool>(&debug_key), Ok(true));
|
||||
assert_eq!(env.get::<Vec<u16>>(&list_key), Ok(vec![3000, 3001, 3002]));
|
||||
|
||||
unsafe {
|
||||
std::env::remove_var(name_key);
|
||||
std::env::remove_var(port_key);
|
||||
std::env::remove_var(debug_key);
|
||||
std::env::remove_var(list_key);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_reports_missing_and_invalid_values() {
|
||||
let env = EnvLoader::new();
|
||||
let missing_key = unique_key("MISSING");
|
||||
let invalid_key = unique_key("INVALID");
|
||||
|
||||
unsafe {
|
||||
std::env::remove_var(&missing_key);
|
||||
std::env::set_var(&invalid_key, "not-a-port");
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Tests that `get_opt` returns `Some` when the environment variable exists.
|
||||
fn test_get_opt() {
|
||||
let env = EnvLoader;
|
||||
|
||||
unsafe {
|
||||
std::env::set_var("OPTIONAL_VAR", "optional_value");
|
||||
}
|
||||
assert_eq!(
|
||||
env.get::<String>(&missing_key),
|
||||
Err(EnvError::MissingVar(missing_key.clone()))
|
||||
);
|
||||
|
||||
assert_eq!(env.get_opt::<String>("OPTIONAL_VAR"), Some("optional_value".to_string()));
|
||||
assert_eq!(env.get_opt::<bool>("DEV"), None);
|
||||
assert!(matches!(
|
||||
env.get::<u16>(&invalid_key),
|
||||
Err(EnvError::Invalid { key, value, .. })
|
||||
if key == "u16" && value == "not-a-port"
|
||||
));
|
||||
|
||||
unsafe {
|
||||
std::env::remove_var(invalid_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_or_and_get_opt_handle_fallbacks() {
|
||||
let env = EnvLoader::new();
|
||||
let present_key = unique_key("PRESENT");
|
||||
let missing_key = unique_key("DEFAULT");
|
||||
let invalid_key = unique_key("BAD_BOOL");
|
||||
|
||||
unsafe {
|
||||
std::env::set_var(&present_key, "42");
|
||||
std::env::remove_var(&missing_key);
|
||||
std::env::set_var(&invalid_key, "maybe");
|
||||
}
|
||||
|
||||
assert_eq!(env.get_or::<u8>(&present_key, 7), 42);
|
||||
assert_eq!(env.get_or::<u8>(&missing_key, 7), 7);
|
||||
assert_eq!(env.get_or::<bool>(&invalid_key, false), false);
|
||||
|
||||
assert_eq!(env.get_opt::<u8>(&present_key), Some(42));
|
||||
assert_eq!(env.get_opt::<u8>(&missing_key), None);
|
||||
assert_eq!(env.get_opt::<bool>(&invalid_key), None);
|
||||
|
||||
unsafe {
|
||||
std::env::remove_var(present_key);
|
||||
std::env::remove_var(invalid_key);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prefixed_loader_reads_namespaced_variables() {
|
||||
let env = EnvLoader::new();
|
||||
let prefix = unique_key("APP_");
|
||||
let host_key = format!("{prefix}HOST");
|
||||
let enabled_key = format!("{prefix}ENABLED");
|
||||
|
||||
unsafe {
|
||||
std::env::set_var(&host_key, "127.0.0.1");
|
||||
std::env::set_var(&enabled_key, "1");
|
||||
}
|
||||
|
||||
let app = env.with_prefix(prefix);
|
||||
|
||||
assert_eq!(app.get::<String>("HOST"), Ok("127.0.0.1".to_string()));
|
||||
assert_eq!(app.get::<bool>("ENABLED"), Ok(true));
|
||||
assert_eq!(app.get_or::<u16>("PORT", 8080), 8080);
|
||||
|
||||
unsafe {
|
||||
std::env::remove_var(host_key);
|
||||
std::env::remove_var(enabled_key);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_file_sets_environment_variables() {
|
||||
let env = EnvLoader::new();
|
||||
let prefix = unique_key("FILE_");
|
||||
let port_key = format!("{prefix}PORT");
|
||||
let debug_key = format!("{prefix}DEBUG");
|
||||
let names_key = format!("{prefix}NAMES");
|
||||
let path = temp_env_file(&prefix, &port_key, &debug_key, &names_key);
|
||||
|
||||
env.load_file(path.to_str().expect("test path should be UTF-8"))
|
||||
.expect("env file should load");
|
||||
|
||||
assert_eq!(env.get::<u16>(&port_key), Ok(8080));
|
||||
assert_eq!(env.get::<bool>(&debug_key), Ok(true));
|
||||
assert_eq!(
|
||||
env.get::<Vec<String>>(&names_key),
|
||||
Ok(vec!["api".to_string(), "worker".to_string()])
|
||||
);
|
||||
|
||||
std::fs::remove_file(path).expect("test env file should be removable");
|
||||
unsafe {
|
||||
std::env::remove_var(port_key);
|
||||
std::env::remove_var(debug_key);
|
||||
std::env::remove_var(names_key);
|
||||
}
|
||||
}
|
||||
|
||||
fn temp_env_file(prefix: &str, port_key: &str, debug_key: &str, names_key: &str) -> PathBuf {
|
||||
let path = std::env::temp_dir().join(format!("{prefix}.env"));
|
||||
let contents = format!(
|
||||
r#"
|
||||
# comments and blank lines are ignored
|
||||
{port_key} = 8080
|
||||
{debug_key}= yes
|
||||
{names_key}= api, worker
|
||||
"#
|
||||
);
|
||||
|
||||
std::fs::write(&path, contents).expect("test env file should be writable");
|
||||
path
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user