use std::{
env,
fs,
};
use serial_test::serial;
fn clear_key_env() {
unsafe {
env::remove_var("AGE_KEY");
env::remove_var("DOTENVAGE_AGE_KEY");
env::remove_var("AGE_KEY_NAME");
env::remove_var("XDG_STATE_HOME");
}
}
#[test]
#[serial]
fn age_key_name_from_env() {
clear_key_env();
let tmpdir = tempfile::tempdir().unwrap();
let state_dir = tmpdir.path().join("state");
let key_dir = state_dir.join("myproject").join("myapp");
fs::create_dir_all(&key_dir).unwrap();
let manager = dotenvage::SecretManager::generate().unwrap();
let key_path = key_dir.join("test.key");
manager.save_key(&key_path).unwrap();
unsafe {
env::set_var("XDG_STATE_HOME", state_dir.to_str().unwrap());
env::set_var("AGE_KEY_NAME", "myproject/myapp/test");
}
let loaded_manager = dotenvage::SecretManager::load_key().unwrap();
let plaintext = "test-secret-123";
let encrypted = manager.encrypt_value(plaintext).unwrap();
let decrypted = loaded_manager.decrypt_value(&encrypted).unwrap();
assert_eq!(plaintext, decrypted);
let expected_path = state_dir.join("myproject/myapp/test.key");
assert_eq!(
dotenvage::SecretManager::key_path_from_env_or_default(),
expected_path
);
}
#[test]
#[serial]
fn age_key_name_default_to_cargo_pkg_name() {
clear_key_env();
let tmpdir = tempfile::tempdir().unwrap();
let state_dir = tmpdir.path().join("state");
unsafe {
env::set_var("XDG_STATE_HOME", state_dir.to_str().unwrap());
}
let path = dotenvage::SecretManager::key_path_from_env_or_default();
let expected = state_dir.join("dotenvage").join("dotenvage.key");
assert_eq!(path, expected);
}
#[test]
#[serial]
fn age_key_name_with_env_loader() {
clear_key_env();
let tmpdir = tempfile::tempdir().unwrap();
let state_dir = tmpdir.path().join("state");
let key_dir = state_dir.join("testapp");
fs::create_dir_all(&key_dir).unwrap();
let manager = dotenvage::SecretManager::generate().unwrap();
let key_path = key_dir.join("dotenvage.key");
manager.save_key(&key_path).unwrap();
let env_file = tmpdir.path().join(".env");
let encrypted_value = manager.encrypt_value("supersecret").unwrap();
fs::write(
&env_file,
format!("AGE_KEY_NAME=testapp\nAPI_KEY={}", encrypted_value),
)
.unwrap();
unsafe {
env::set_var("XDG_STATE_HOME", state_dir.to_str().unwrap());
}
let loader = dotenvage::EnvLoader::with_manager(manager);
let vars = loader.load_env_file(&env_file).unwrap();
assert_eq!(vars.get("AGE_KEY_NAME"), Some(&"testapp".to_string()));
assert_eq!(vars.get("API_KEY"), Some(&"supersecret".to_string()));
}
#[test]
#[serial]
fn age_key_name_priority_order() {
clear_key_env();
let tmpdir = tempfile::tempdir().unwrap();
let state_dir = tmpdir.path().join("state");
let manager1 = dotenvage::SecretManager::generate().unwrap();
let manager2 = dotenvage::SecretManager::generate().unwrap();
let key1_dir = state_dir.join("project1");
fs::create_dir_all(&key1_dir).unwrap();
let key1_path = key1_dir.join("dotenvage.key");
manager1.save_key(&key1_path).unwrap();
let key1_content = fs::read_to_string(&key1_path).unwrap();
unsafe {
env::set_var("AGE_KEY", key1_content.trim());
env::set_var("AGE_KEY_NAME", "project2"); env::set_var("XDG_STATE_HOME", state_dir.to_str().unwrap());
}
let loaded = dotenvage::SecretManager::load_key().unwrap();
let plaintext = "test-123";
let encrypted = manager1.encrypt_value(plaintext).unwrap();
let decrypted = loaded.decrypt_value(&encrypted).unwrap();
assert_eq!(plaintext, decrypted);
assert!(
loaded
.decrypt_value(&manager2.encrypt_value(plaintext).unwrap())
.is_err()
|| loaded
.decrypt_value(&manager2.encrypt_value(plaintext).unwrap())
.unwrap()
!= plaintext
);
}
#[test]
#[serial]
fn age_key_name_empty_string_uses_default() {
clear_key_env();
let tmpdir = tempfile::tempdir().unwrap();
let state_dir = tmpdir.path().join("state");
unsafe {
env::set_var("XDG_STATE_HOME", state_dir.to_str().unwrap());
env::set_var("AGE_KEY_NAME", " "); }
let path = dotenvage::SecretManager::key_path_from_env_or_default();
let expected = state_dir.join("dotenvage").join("dotenvage.key");
assert_eq!(path, expected);
}