use std::fs;
use std::path::{Path, PathBuf};
use ronin_core::{parse_bytes, print};
fn collect_fixtures(dir: &Path, out: &mut Vec<PathBuf>) {
let entries = fs::read_dir(dir)
.unwrap_or_else(|e| panic!("failed to read corpus dir {}: {e}", dir.display()));
for entry in entries {
let entry = entry.expect("dir entry");
let path = entry.path();
if path.is_dir() {
collect_fixtures(&path, out);
} else if path.extension().and_then(|e| e.to_str()) == Some("ron") {
out.push(path);
}
}
}
fn corpus_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("corpus")
}
fn all_fixtures() -> Vec<PathBuf> {
let mut out = Vec::new();
collect_fixtures(&corpus_dir(), &mut out);
out.sort();
out
}
#[test]
fn corpus_round_trips_byte_for_byte() {
let fixtures = all_fixtures();
assert!(
!fixtures.is_empty(),
"corpus must not be empty (looked in {})",
corpus_dir().display()
);
let mut checked = 0usize;
for path in &fixtures {
let bytes = fs::read(path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()));
let doc = parse_bytes(&bytes).unwrap_or_else(|e| {
panic!(
"fixture {} is not valid UTF-8 (outside round-trip domain): {e}",
path.display()
)
});
let printed = print(&doc);
assert_eq!(
printed.as_bytes(),
bytes.as_slice(),
"round-trip mismatch for {}",
path.display()
);
checked += 1;
}
assert_eq!(checked, fixtures.len());
}
#[test]
fn corpus_meets_composition_floor() {
let fixtures = all_fixtures();
assert!(
fixtures.len() >= 30,
"corpus must have ≥ 30 fixtures, found {}",
fixtures.len()
);
let malformed = fixtures
.iter()
.filter(|p| p.components().any(|c| c.as_os_str() == "malformed"))
.count();
assert!(
malformed >= 3,
"corpus must have ≥ 3 malformed fixtures, found {malformed}"
);
let large = fixtures
.iter()
.filter_map(|p| fs::metadata(p).ok())
.any(|m| m.len() >= 1_000_000);
assert!(large, "corpus must contain ≥ 1 file ≥ 1 MB");
}
#[test]
fn malformed_fixtures_recover_and_round_trip() {
let dir = corpus_dir().join("malformed");
let mut fixtures = Vec::new();
collect_fixtures(&dir, &mut fixtures);
assert!(fixtures.len() >= 3, "need ≥ 3 malformed fixtures");
for path in fixtures {
let bytes = fs::read(&path).unwrap();
let doc = parse_bytes(&bytes).expect("malformed-but-UTF-8 still parses to a tree");
assert_eq!(
print(&doc).as_bytes(),
bytes.as_slice(),
"malformed round-trip mismatch for {}",
path.display()
);
assert!(
!doc.diagnostics().is_empty(),
"expected diagnostics for malformed fixture {}",
path.display()
);
for d in doc.diagnostics() {
assert!(d.range().end() <= doc.source_len());
}
}
}
#[test]
fn large_fixture_round_trips() {
let large = all_fixtures()
.into_iter()
.find(|p| {
fs::metadata(p)
.map(|m| m.len() >= 1_000_000)
.unwrap_or(false)
})
.expect("a ≥ 1 MB fixture exists");
let bytes = fs::read(&large).unwrap();
assert!(bytes.len() >= 1_000_000);
let doc = parse_bytes(&bytes).unwrap();
assert_eq!(
print(&doc).as_bytes(),
bytes.as_slice(),
"large fixture must round-trip"
);
}