fn root_from(
security_root: Option<std::path::PathBuf>,
roteiro_home: Option<std::path::PathBuf>,
home: Option<std::path::PathBuf>,
) -> std::path::PathBuf {
if let Some(dir) = security_root {
return dir;
}
if let Some(dir) = roteiro_home {
return dir.join("security");
}
home.unwrap_or_else(|| std::path::PathBuf::from("."))
.join(".roteiro")
.join("security")
}
#[must_use]
pub fn asset_root() -> std::path::PathBuf {
root_from(
std::env::var_os("ROTEIRO_SECURITY_ASSETS").map(std::path::PathBuf::from),
std::env::var_os("ROTEIRO_HOME").map(std::path::PathBuf::from),
std::env::var_os("HOME")
.or_else(|| std::env::var_os("USERPROFILE"))
.map(std::path::PathBuf::from),
)
}
pub const ASSET_ROOT_VARS: &[&str] = &[
"ROTEIRO_SECURITY_ASSETS",
"ROTEIRO_HOME",
"HOME",
"USERPROFILE",
];
#[cfg(test)]
mod asset_paths_tests {
use super::root_from;
use std::path::PathBuf;
#[test]
fn the_cache_root_prefers_the_explicit_override_then_roteiro_home() {
assert_eq!(
root_from(
Some("/explicit".into()),
Some("/home/.roteiro".into()),
None
),
PathBuf::from("/explicit")
);
assert_eq!(
root_from(None, Some("/home/.roteiro".into()), None),
PathBuf::from("/home/.roteiro/security")
);
assert_eq!(
root_from(None, None, Some("/home/me".into())),
PathBuf::from("/home/me/.roteiro/security")
);
}
#[test]
fn the_declared_variables_are_exactly_the_ones_that_are_read() {
let source = include_str!("asset_paths.rs");
let read: Vec<&str> = source
.match_indices("var_os(\"")
.map(|(at, marker)| {
let rest = &source[at + marker.len()..];
rest.split_once('"')
.expect("a var_os literal is closed on the same line")
.0
})
.collect();
assert!(
!read.is_empty(),
"no var_os call was found to check against"
);
for var in &read {
assert!(
super::ASSET_ROOT_VARS.contains(var),
"asset_root reads {var}, but ASSET_ROOT_VARS does not declare it"
);
}
for var in super::ASSET_ROOT_VARS {
assert!(
read.contains(var),
"ASSET_ROOT_VARS declares {var}, but nothing here reads it"
);
}
}
}