use std::path::PathBuf;
const APP_DIR_NAME: &str = "hyperdb";
const PERSISTENT_DB_FILENAME: &str = "workspace.hyper";
pub const ENV_PERSISTENT_DB: &str = "HYPERDB_PERSISTENT_DB";
#[must_use]
pub fn default_persistent_db_path() -> Option<PathBuf> {
Some(
dirs::data_dir()?
.join(APP_DIR_NAME)
.join(PERSISTENT_DB_FILENAME),
)
}
#[must_use]
pub fn resolve_persistent_db_path(cli_value: Option<&str>) -> Option<PathBuf> {
if let Some(p) = cli_value {
return Some(PathBuf::from(p));
}
if let Some(p) = std::env::var_os(ENV_PERSISTENT_DB) {
return Some(PathBuf::from(p));
}
default_persistent_db_path()
}
#[cfg(test)]
mod tests {
use super::*;
static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
fn with_env_lock<R>(f: impl FnOnce() -> R) -> R {
let _guard = ENV_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
f()
}
unsafe fn set_env(key: &str, value: &str) {
unsafe { std::env::set_var(key, value) }
}
unsafe fn remove_env(key: &str) {
unsafe { std::env::remove_var(key) }
}
#[test]
fn default_persistent_db_path_returns_some_on_supported_platforms() {
let p = default_persistent_db_path().expect("platform data_dir resolves");
assert!(p.ends_with("hyperdb/workspace.hyper") || p.ends_with("hyperdb\\workspace.hyper"));
}
#[cfg(target_os = "macos")]
#[test]
fn default_persistent_db_path_uses_app_support_on_macos() {
let p = default_persistent_db_path().unwrap();
let s = p.to_string_lossy();
assert!(
s.contains("Library/Application Support/hyperdb/"),
"expected macOS Application Support path, got {s}"
);
}
#[cfg(target_os = "linux")]
#[test]
fn default_persistent_db_path_uses_xdg_share_on_linux() {
let p = default_persistent_db_path().unwrap();
let s = p.to_string_lossy();
assert!(
s.contains(".local/share/hyperdb/") || s.contains("share/hyperdb/"),
"expected XDG share path, got {s}"
);
}
#[cfg(windows)]
#[test]
fn default_persistent_db_path_uses_appdata_on_windows() {
let p = default_persistent_db_path().unwrap();
let s = p.to_string_lossy();
assert!(
s.contains("hyperdb"),
"expected APPDATA path containing hyperdb, got {s}"
);
}
#[test]
fn resolve_persistent_db_path_cli_takes_precedence() {
with_env_lock(|| {
unsafe { set_env(ENV_PERSISTENT_DB, "/from/env.hyper") };
let p = resolve_persistent_db_path(Some("/from/cli.hyper"))
.expect("CLI path always resolves");
assert_eq!(p, PathBuf::from("/from/cli.hyper"));
unsafe { remove_env(ENV_PERSISTENT_DB) };
});
}
#[test]
fn resolve_persistent_db_path_env_used_when_no_cli() {
with_env_lock(|| {
unsafe { set_env(ENV_PERSISTENT_DB, "/from/env.hyper") };
let p = resolve_persistent_db_path(None).expect("env path resolves");
assert_eq!(p, PathBuf::from("/from/env.hyper"));
unsafe { remove_env(ENV_PERSISTENT_DB) };
});
}
#[test]
fn resolve_persistent_db_path_falls_back_to_default() {
with_env_lock(|| {
unsafe { remove_env(ENV_PERSISTENT_DB) };
let p = resolve_persistent_db_path(None).expect("default resolves");
assert!(p.to_string_lossy().contains("hyperdb"));
});
}
}