#![allow(dead_code)]
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use assert_cmd::Command;
use serde_json::Value;
const HERMETIC_LANG: &str = "en_US.UTF-8";
pub fn hermetic_home() -> &'static Path {
static HOME: OnceLock<PathBuf> = OnceLock::new();
HOME.get_or_init(|| {
let stem = std::env::current_exe()
.ok()
.and_then(|exe| exe.file_stem().map(|s| s.to_string_lossy().into_owned()))
.unwrap_or_else(|| "test".to_string());
let dir = Path::new(env!("CARGO_TARGET_TMPDIR"))
.join("hermetic-home")
.join(format!("{stem}-{}", std::process::id()));
std::fs::create_dir_all(&dir).expect("create the hermetic home");
dir
})
}
fn real_cache_home() -> PathBuf {
std::env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.or_else(|| std::env::var_os("HOME").map(|h| PathBuf::from(h).join(".cache")))
.unwrap_or_else(|| hermetic_home().join("cache"))
}
pub trait Hermetic {
fn hermetic(self) -> Self;
}
macro_rules! impl_hermetic {
($command:ty) => {
impl Hermetic for $command {
fn hermetic(mut self) -> Self {
let home = hermetic_home();
self.env("HOME", home)
.env("USERPROFILE", home)
.env("APPDATA", home)
.env("LOCALAPPDATA", home)
.env("XDG_CONFIG_HOME", home.join("config"))
.env("XDG_DATA_HOME", home.join("data"))
.env("XDG_STATE_HOME", home.join("state"))
.env("XDG_CACHE_HOME", real_cache_home())
.env("LANG", HERMETIC_LANG)
.env("LC_ALL", HERMETIC_LANG)
.env_remove("LANGUAGE")
.env_remove("LC_MESSAGES");
self
}
}
};
}
impl_hermetic!(Command);
impl_hermetic!(std::process::Command);
pub fn hermetic<C: Hermetic>(command: C) -> C {
command.hermetic()
}
pub fn atomwrite() -> Command {
hermetic(Command::cargo_bin("atomwrite").expect("binary not found"))
}
pub fn parse_ndjson(output: &[u8]) -> Vec<Value> {
String::from_utf8_lossy(output)
.lines()
.filter(|l| !l.is_empty())
.map(|l| serde_json::from_str(l).expect("invalid NDJSON line"))
.collect()
}
pub fn create_test_file(dir: &Path, name: &str, content: &str) -> std::path::PathBuf {
let path = dir.join(name);
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).expect("create dirs");
}
std::fs::write(&path, content).expect("write test file");
path
}
pub fn manifest(ops: &[serde_json::Value]) -> String {
ops.iter()
.map(|op| serde_json::to_string(op).expect("serialize manifest op"))
.collect::<Vec<_>>()
.join("\n")
}
pub mod schema_check;