use super::{
cache_location, resolve_cache_root, source_digest, CacheEnvironment, CacheRootError, HostPlatform,
};
use std::ffi::OsString;
use std::path::{Component, Path, PathBuf};
#[cfg(unix)]
#[test]
fn absolute_unix_override_wins() {
let unix_environment = CacheEnvironment {
override_root: Some(OsString::from("/private/cache")),
..CacheEnvironment::default()
};
for platform in [HostPlatform::XdgUnix, HostPlatform::Macos] {
assert_eq!(
resolve_cache_root(&unix_environment, platform).expect("absolute override"),
PathBuf::from("/private/cache"),
);
}
}
#[test]
fn absolute_windows_override_wins() {
let windows_environment = CacheEnvironment {
override_root: Some(OsString::from("C:\\private\\cache")),
..CacheEnvironment::default()
};
assert_eq!(
resolve_cache_root(&windows_environment, HostPlatform::Windows)
.expect("Windows override"),
PathBuf::from("C:\\private\\cache"),
);
}
#[test]
fn relative_override_is_rejected() {
let environment = CacheEnvironment {
override_root: Some(OsString::from("relative/cache")),
..CacheEnvironment::default()
};
assert_eq!(
resolve_cache_root(&environment, HostPlatform::XdgUnix),
Err(CacheRootError::InvalidOverride),
);
}
#[cfg(unix)]
#[test]
fn xdg_resolution_follows_base_directory_spec() {
let absolute = CacheEnvironment {
xdg_cache_home: Some(OsString::from("/xdg/cache")),
home: Some(OsString::from("/home/user")),
..CacheEnvironment::default()
};
assert_eq!(
resolve_cache_root(&absolute, HostPlatform::XdgUnix).expect("XDG root"),
PathBuf::from("/xdg/cache"),
);
let relative = CacheEnvironment {
xdg_cache_home: Some(OsString::from("relative")),
home: Some(OsString::from("/home/user")),
..CacheEnvironment::default()
};
assert_eq!(
resolve_cache_root(&relative, HostPlatform::XdgUnix).expect("HOME fallback"),
PathBuf::from("/home/user/.cache"),
);
}
#[cfg(unix)]
#[test]
fn macos_native_root_is_derived() {
let environment = CacheEnvironment {
home: Some(OsString::from("/Users/alice")),
local_app_data: Some(OsString::from("C:\\Users\\alice\\AppData\\Local")),
..CacheEnvironment::default()
};
assert_eq!(
resolve_cache_root(&environment, HostPlatform::Macos).expect("macOS root"),
PathBuf::from("/Users/alice/Library/Caches"),
);
}
#[test]
fn windows_native_root_is_derived() {
let environment = CacheEnvironment {
home: Some(OsString::from("/Users/alice")),
local_app_data: Some(OsString::from("C:\\Users\\alice\\AppData\\Local")),
..CacheEnvironment::default()
};
assert_eq!(
resolve_cache_root(&environment, HostPlatform::Windows).expect("Windows root"),
PathBuf::from("C:\\Users\\alice\\AppData\\Local"),
);
}
#[test]
fn missing_native_root_is_unavailable() {
assert_eq!(
resolve_cache_root(&CacheEnvironment::default(), HostPlatform::XdgUnix),
Err(CacheRootError::Unavailable),
);
}
fn normal_name(component: Component<'_>) -> String {
if let Component::Normal(name) = component {
return name.to_str().expect("UTF-8 artifact component").to_string();
}
panic!("artifact layout contains a non-name component: {component:?}");
}
#[test]
fn source_bytes_select_content_addressed_path() {
let first = source_digest(b"alpha\n").expect("digest");
let repeated = source_digest(b"alpha\n").expect("digest");
let changed = source_digest(b"alpha").expect("digest");
assert_eq!(first, repeated);
assert_ne!(first, changed);
let root: PathBuf = PathBuf::from("/cache");
let location = cache_location(&root, first);
let below: &Path = location.artifact_path.strip_prefix(&root).expect("artifact under root");
let mut names: Vec<String> = Vec::new();
for component in below.components() {
names.push(normal_name(component));
}
assert_eq!(names.len(), 5, "application, version, platform, digest and filename: {names:?}");
assert_eq!(names[0], "forbidden-strings");
assert_eq!(names[1], format!("v{}", env!("CARGO_PKG_VERSION")));
assert_eq!(names[2], format!("{}-{}", std::env::consts::OS, std::env::consts::ARCH));
assert_eq!(names[4], "rules.bin");
let digest_component: &str = names[3].as_str();
assert_eq!(digest_component.len(), 64);
for character in digest_component.chars() {
assert!(character.is_ascii_digit() || ('a'..='f').contains(&character), "lowercase hex digest: {digest_component}");
}
}