use std::path::PathBuf;
use std::process::Command;
use retex_kpath::{FileFormat, Kpathsea, Options};
fn kpsewhich(args: &[&str]) -> Option<String> {
let out = Command::new("kpsewhich")
.args(["-progname=lualatex", "-engine=luahbtex"])
.args(args)
.output()
.ok()?;
Some(String::from_utf8_lossy(&out.stdout).trim().to_owned())
}
fn available() -> bool {
let ok = Command::new("kpsewhich").arg("--version").output().is_ok();
if !ok {
eprintln!("kpsewhich not installed; skipping differential test");
}
ok
}
#[test]
fn finds_same_files_as_kpsewhich() {
if !available() {
return;
}
let mut kpse = Kpathsea::new(Options::lualatex()).expect("kpathsea init");
let cases: &[(&str, FileFormat, &str)] = &[
("lualatex.ini", FileFormat::Tex, "tex"),
("latex.ltx", FileFormat::Tex, "tex"),
("luatexconfig.tex", FileFormat::Tex, "tex"),
("article.cls", FileFormat::Tex, "tex"),
("size10.clo", FileFormat::Tex, "tex"),
("tulmr.fd", FileFormat::Tex, "tex"),
("hyphen.cfg", FileFormat::Tex, "tex"),
("language.dat", FileFormat::Tex, "tex"),
("language.dat.lua", FileFormat::Tex, "tex"),
("hyph-en-us.pat.txt", FileFormat::Tex, "tex"),
("tikz.sty", FileFormat::Tex, "tex"),
("pgfcore.code.tex", FileFormat::Tex, "tex"),
("ltluatex", FileFormat::Lua, "lua"),
("ltluatex.lua", FileFormat::Lua, "lua"),
("lualatexquotejobname.lua", FileFormat::Lua, "lua"),
("luaotfload-main", FileFormat::Lua, "lua"),
(
"lmroman10-regular.otf",
FileFormat::OpenType,
"opentype fonts",
),
("lmroman10-regular", FileFormat::OpenType, "opentype fonts"),
(
"latinmodern-math.otf",
FileFormat::OpenType,
"opentype fonts",
),
("cmr10", FileFormat::Tfm, "tfm"),
("pdftex.map", FileFormat::Map, "map"),
("lualatex", FileFormat::Fmt, "fmt"),
("does-not-exist-xyz", FileFormat::Tex, "tex"),
];
for (name, fmt, kfmt) in cases {
let expected = kpsewhich(&[&format!("-format={kfmt}"), name]).unwrap();
let got = kpse
.find_file(name, *fmt)
.map(|p| p.to_string_lossy().into_owned())
.unwrap_or_default();
assert_eq!(
PathBuf::from(&got),
PathBuf::from(&expected),
"lookup of {name} ({kfmt})"
);
}
}
#[test]
fn same_variable_values_as_kpsewhich() {
if !available() {
return;
}
let kpse = Kpathsea::new(Options::lualatex()).expect("kpathsea init");
for var in [
"TEXMF",
"TEXINPUTS",
"LUAINPUTS",
"TEXMFVAR",
"TEXMFDBS",
"max_print_line",
] {
let expected = kpsewhich(&["-var-value", var]).unwrap();
assert_eq!(
kpse.var_value(var).unwrap_or_default(),
expected,
"variable {var}"
);
}
}
struct TexInputs(String);
impl retex_kpath::Env for TexInputs {
fn var(&self, name: &str) -> Option<String> {
if name.starts_with("TEXINPUTS") {
return (name == "TEXINPUTS").then(|| self.0.clone());
}
std::env::var(name).ok()
}
}
#[test]
fn extra_colon_in_environment_adds_cnf_path() {
if !available() {
return;
}
let dir = std::env::temp_dir().join(format!("retex-kpath-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("retex-extra-colon.tex"), "").unwrap();
let env = TexInputs(format!("{}:", dir.display()));
let mut kpse = Kpathsea::with_env(Options::lualatex(), Box::new(env)).unwrap();
let mut found = |n| kpse.find_file(n, FileFormat::Tex);
assert_eq!(
found("retex-extra-colon.tex"),
Some(dir.join("retex-extra-colon.tex"))
);
let expected = kpsewhich(&["-format=tex", "article.cls"]).unwrap();
assert_eq!(found("article.cls"), Some(PathBuf::from(expected)));
let _ = std::fs::remove_dir_all(&dir);
}