use std::path::{Path, PathBuf};
use std::process::Command;
const KNOWN_DIVERGENCES: &[&str] = &["tests/fixtures/violations/JSS-PARSE-000.tex"];
const NON_UTF8_FIXTURES: &[&str] = &[
"tests/fixtures/resolver_projects/latin1_root/root.tex",
"tests/fixtures/resolver_projects/latin1_included/intro.tex",
];
fn repo_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.parent()
.unwrap()
.to_path_buf()
}
fn find_tex_fixtures(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
find_tex_fixtures(&path, out);
} else if path
.extension()
.is_some_and(|e| e.eq_ignore_ascii_case("tex"))
{
out.push(path);
}
}
}
fn python_oracle_dump(python: &Path, fixture: &Path) -> String {
let output = Command::new(python)
.arg("-m")
.arg("tools.dump_tex_nodes")
.arg(fixture)
.current_dir(repo_root())
.output()
.expect("failed to run tools.dump_tex_nodes");
assert!(
output.status.success(),
"dump_tex_nodes failed on {}: {}",
fixture.display(),
String::from_utf8_lossy(&output.stderr)
);
String::from_utf8(output.stdout).expect("oracle output must be valid UTF-8")
}
#[test]
fn all_tex_fixtures_match_python_oracle() {
let root = repo_root();
let python = root.join(".venv/bin/python");
if !python.exists() {
eprintln!(
"SKIP: {} not found (Python venv not set up)",
python.display()
);
return;
}
let mut fixtures = Vec::new();
find_tex_fixtures(&root.join("tests/fixtures"), &mut fixtures);
fixtures.sort();
assert!(
!fixtures.is_empty(),
"expected to find .tex fixtures under tests/fixtures/"
);
let mut mismatches = Vec::new();
for fixture in &fixtures {
let relative = fixture
.strip_prefix(&root)
.unwrap()
.to_string_lossy()
.replace('\\', "/");
if KNOWN_DIVERGENCES.contains(&relative.as_str())
|| NON_UTF8_FIXTURES.contains(&relative.as_str())
{
continue;
}
let source = std::fs::read_to_string(fixture)
.unwrap_or_else(|e| panic!("failed to read {}: {e}", fixture.display()));
let expected = python_oracle_dump(&python, fixture);
let parsed = jsslint_core::tex::parse_tex_source(&source);
let actual = jsslint_core::tex::debug::dump(&parsed.nodes);
if actual != expected {
mismatches.push(relative);
}
}
assert!(
mismatches.is_empty(),
"{}/{} fixtures diverged from the Python oracle:\n{}",
mismatches.len(),
fixtures.len(),
mismatches.join("\n")
);
}