use std::io::Write;
#[allow(dead_code)]
#[path = "../src/formats.rs"]
mod formats;
#[allow(dead_code)]
#[path = "../src/magics.rs"]
mod magics;
const LUAR: u32 = 0x4C55_4152;
const PERL: u32 = 0x5045_524C;
const VIML: u32 = 0x5649_4D4C;
const USER_FILE: &str = "\
# a producer this build has never heard of
LUAR = luars bytecode cache (LUAR)
0x5045_524C = perlrs script cache (PERL)
VIML = vimlrs script cache, renamed by its user
";
fn registry() -> &'static [(u32, &'static str)] {
static ONCE: std::sync::Once = std::sync::Once::new();
ONCE.call_once(|| {
let mut path = std::env::temp_dir();
path.push(format!("zdbview_magics_{}", std::process::id()));
let mut f = std::fs::File::create(&path).expect("write the registry file");
f.write_all(USER_FILE.as_bytes()).expect("write");
drop(f);
assert!(magics::install(magics::registry_for(&path)), "installed");
let _ = std::fs::remove_file(&path);
});
magics::all()
}
fn stamped(magic: u32) -> Vec<u8> {
let mut bytes = vec![0u8; 32];
bytes.extend_from_slice(&magic.to_le_bytes());
bytes.extend_from_slice(&[0u8; 64]);
bytes
}
#[test]
fn a_tag_this_build_never_shipped_is_detected_and_named() {
assert!(
!formats::BUILTIN_MAGICS.iter().any(|(m, _)| *m == LUAR),
"LUAR must not be a built-in, or this proves nothing"
);
assert!(registry().iter().any(|(m, _)| *m == LUAR));
assert_eq!(
formats::magic_in(&stamped(LUAR)),
Some("luars bytecode cache (LUAR)")
);
assert_eq!(
formats::magic_in(&stamped(PERL)),
Some("perlrs script cache (PERL)")
);
assert!(formats::try_decode(&stamped(LUAR)).is_none());
}
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
#[archive(check_bytes)]
struct ForeignHeader {
magic: u32,
format_version: u32,
producer_version: String,
pointer_width: u32,
built_at_secs: u64,
}
#[derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
#[archive(check_bytes)]
struct ForeignShard {
header: ForeignHeader,
entries: std::collections::HashMap<String, Vec<u8>>,
}
fn foreign_shard_bytes() -> Vec<u8> {
let mut entries = std::collections::HashMap::new();
entries.insert("/tmp/init.lua".to_string(), b"compiled chunk".to_vec());
let shard = ForeignShard {
header: ForeignHeader {
magic: LUAR,
format_version: 1,
producer_version: "0.1.0".into(),
pointer_width: 8,
built_at_secs: 7,
},
entries,
};
rkyv::to_bytes::<_, 1024>(&shard).unwrap().to_vec()
}
#[test]
fn a_conforming_producer_needs_nothing_from_this_repo() {
registry();
let bytes = foreign_shard_bytes();
assert_eq!(
formats::magic_in(&bytes),
Some("luars bytecode cache (LUAR)"),
"a real archive from an unknown producer, named by the registry"
);
assert!(formats::try_decode(&bytes).is_none());
let archived = rkyv::check_archived_root::<ForeignShard>(&bytes).expect("validates");
assert_eq!(u32::from(archived.header.magic), LUAR);
assert_eq!(u32::from(archived.header.format_version), 1);
}
#[test]
fn a_user_tag_survives_the_scan_cache_round_trip() {
registry();
let name = formats::magic_in(&stamped(LUAR)).expect("detected");
assert_eq!(
formats::magic_label(name),
Some("luars bytecode cache (LUAR)")
);
assert_eq!(formats::magic_label("a format nobody registered"), None);
}
#[test]
fn a_user_entry_renames_a_builtin_tag() {
registry();
assert_eq!(
formats::magic_in(&stamped(VIML)),
Some("vimlrs script cache, renamed by its user")
);
assert_eq!(registry().iter().filter(|(m, _)| *m == VIML).count(), 1);
}
#[test]
fn registering_a_tag_does_not_disturb_the_built_ins() {
let reg = registry();
for (magic, name) in formats::BUILTIN_MAGICS {
let got = magics::name_of(*magic).expect("every built-in is still registered");
if *magic == VIML {
continue; }
assert_eq!(got, *name, "built-in {magic:#010x} kept its name");
}
assert_eq!(reg.len(), formats::BUILTIN_MAGICS.len() + 2);
}
static ENV: std::sync::Mutex<()> = std::sync::Mutex::new(());
#[test]
fn the_registry_file_is_the_documented_path() {
let _guard = ENV.lock().unwrap_or_else(|e| e.into_inner());
let prior = std::env::var_os("XDG_CONFIG_HOME");
let home = std::env::temp_dir().join("zdbview_home_probe");
std::env::set_var("XDG_CONFIG_HOME", &home);
let got = magics::registry_path();
match prior {
Some(p) => std::env::set_var("XDG_CONFIG_HOME", p),
None => std::env::remove_var("XDG_CONFIG_HOME"),
}
assert_eq!(got, Some(home.join("zdbview").join("magics")));
}
#[test]
fn without_xdg_the_registry_falls_back_under_home() {
let _guard = ENV.lock().unwrap_or_else(|e| e.into_inner());
let prior_xdg = std::env::var_os("XDG_CONFIG_HOME");
let prior_home = std::env::var_os("HOME");
let home = std::env::temp_dir().join("zdbview_home_fallback");
std::env::remove_var("XDG_CONFIG_HOME");
std::env::set_var("HOME", &home);
let got = magics::registry_path();
match prior_xdg {
Some(p) => std::env::set_var("XDG_CONFIG_HOME", p),
None => std::env::remove_var("XDG_CONFIG_HOME"),
}
match prior_home {
Some(p) => std::env::set_var("HOME", p),
None => std::env::remove_var("HOME"),
}
assert_eq!(
got,
Some(home.join(".config").join("zdbview").join("magics")),
"the path README and the man page name when XDG_CONFIG_HOME is unset"
);
}
#[test]
fn the_shipped_binary_honours_a_hand_written_registry_file() {
let dir = std::env::temp_dir().join(format!("zdbview_cfg_{}", std::process::id()));
let zdb = dir.join("zdbview");
std::fs::create_dir_all(&zdb).expect("config dir");
std::fs::write(zdb.join("magics"), USER_FILE).expect("registry file");
let run = |config: &std::path::Path| -> String {
let out = std::process::Command::new(env!("CARGO_BIN_EXE_zdbview"))
.arg("--formats")
.env("XDG_CONFIG_HOME", config)
.output()
.expect("run zdbview --formats");
assert!(out.status.success(), "--formats exits 0");
let text = String::from_utf8_lossy(&out.stdout).to_string();
strip_ansi(&text)
};
let listed = run(&dir);
assert!(
listed.contains("LUAR 0x4c554152 luars bytecode cache (LUAR) (registered)"),
"a tag the binary does not ship, listed from the user's file:\n{listed}"
);
assert!(
listed.contains("PERL 0x5045524c perlrs script cache (PERL) (registered)"),
"a tag written as hex, listed by its characters:\n{listed}"
);
assert!(
listed.contains("VIML 0x56494d4c vimlrs script cache, renamed by its user"),
"a shipped tag the user renamed:\n{listed}"
);
let empty = dir.join("empty");
std::fs::create_dir_all(&empty).expect("empty config dir");
let bare = run(&empty);
assert!(!bare.contains("LUAR"), "nothing registers itself:\n{bare}");
assert!(!bare.contains("(registered)"), "no strays:\n{bare}");
assert!(
bare.contains("VIML 0x56494d4c vimlrs script cache (VIML)"),
"the built-in name, unrenamed:\n{bare}"
);
let _ = std::fs::remove_dir_all(&dir);
}
fn strip_ansi(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let mut chars = s.chars();
while let Some(c) = chars.next() {
if c == '\u{1b}' {
for c in chars.by_ref() {
if c.is_ascii_alphabetic() {
break;
}
}
} else {
out.push(c);
}
}
out
}