use rac_engine::commands::validate_directory;
use rac_engine::frontmatter::{file_cap_from, FileCap};
use rac_engine::parse;
use rac_engine::scaffold::create_artifact;
use rac_engine::validate::{has_errors, validate};
use std::path::{Path, PathBuf};
fn hostile_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../fixtures/hostile")
}
fn hostile_fixtures() -> Vec<PathBuf> {
let mut files: Vec<PathBuf> = std::fs::read_dir(hostile_dir())
.expect("rust/fixtures/hostile/ exists")
.filter_map(|e| e.ok().map(|e| e.path()))
.filter(|p| p.extension().map(|x| x == "md").unwrap_or(false))
.collect();
files.sort();
assert!(
files.len() >= 5,
"hostile fixture set unexpectedly small: {} files",
files.len()
);
files
}
fn scratch_root(tag: &str) -> PathBuf {
let base = std::env::var("CARGO_TARGET_TMPDIR").unwrap_or_else(|_| "/tmp".into());
let root = Path::new(&base).join(format!("hostile_{tag}_{}", std::process::id()));
let _ = std::fs::remove_dir_all(&root);
std::fs::create_dir_all(&root).unwrap();
root
}
#[test]
fn parse_and_validate_are_total_over_the_catalog() {
for path in hostile_fixtures() {
let name = path.file_name().unwrap().to_string_lossy().into_owned();
let path_str = path.to_string_lossy().into_owned();
let artifact = parse::parse_file(&path_str); let issues = validate(&artifact, None, None);
if name.starts_with("class-a-") {
let issue = issues
.iter()
.find(|i| i.code == "malformed-frontmatter")
.unwrap_or_else(|| panic!("{name}: expected malformed-frontmatter"));
assert_eq!(issue.severity, "error", "{name}: issue severity");
assert!(
issue
.message
.starts_with("frontmatter is not valid YAML: unhashable frontmatter key:"),
"{name}: issue message was {:?}",
issue.message
);
}
if name.starts_with("class-c-") || name.starts_with("class-d-") {
let warn = issues
.iter()
.find(|i| i.code == "non-utf8-content")
.unwrap_or_else(|| panic!("{name}: expected non-utf8-content"));
assert_eq!(warn.severity, "warning", "{name}: non-utf8 severity");
assert!(
!has_errors(&issues),
"{name}: lossy decode must stay non-fatal"
);
}
if name.starts_with("class-b-") {
assert!(!has_errors(&issues), "{name}: cap probe fixture is clean");
}
}
}
#[test]
fn directory_validation_walks_the_whole_catalog() {
let fixtures = hostile_fixtures();
let root = scratch_root("walk");
let corpus = root.join("corpus");
std::fs::create_dir_all(&corpus).unwrap();
for path in &fixtures {
std::fs::copy(path, corpus.join(path.file_name().unwrap())).unwrap();
}
let result = validate_directory(&corpus.to_string_lossy(), true); assert_eq!(
result.files.len(),
fixtures.len(),
"every hostile file gets a per-file verdict"
);
for file in &result.files {
assert!(
["valid", "invalid", "skipped"].contains(&file.status),
"{}: unexpected status {:?}",
file.path,
file.status
);
}
let _ = result.ok(); let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn new_mints_an_id_over_the_full_catalog() {
let root = scratch_root("new");
std::fs::create_dir_all(root.join(".decided")).unwrap();
std::fs::write(root.join(".decided/config.yaml"), "repository_key: RAC\n").unwrap();
let corpus = root.join("rac/hostile");
std::fs::create_dir_all(&corpus).unwrap();
for path in hostile_fixtures() {
std::fs::copy(&path, corpus.join(path.file_name().unwrap())).unwrap();
}
std::fs::create_dir_all(root.join("rac/decisions")).unwrap();
let out = root
.join("rac/decisions/minted.md")
.to_string_lossy()
.into_owned();
let created = create_artifact("decision", &out)
.unwrap_or_else(|e| panic!("create_artifact failed on the hostile catalog: {}", e.message()));
assert_eq!(created.artifact_type, "decision");
let written = std::fs::read_to_string(&out).unwrap();
assert!(written.starts_with("---\nschema_version: 1\nid: RAC-"));
let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn read_cap_crash_zones_stay_graceful() {
assert_eq!(
file_cap_from(Some("99999999999999999999")),
FileCap::OracleCrash("OverflowError: cannot fit 'int' into an index-sized integer")
);
assert_eq!(
file_cap_from(Some("9223372036854775806")),
FileCap::OracleCrash("OverflowError: byte string is too large")
);
assert_eq!(file_cap_from(Some("1024")), FileCap::Cap(1024));
let big_cap: u128 = (i64::MAX as u128) - 35;
for path in hostile_fixtures() {
let product =
rac_engine::markdown::parse_file_with_cap(&path.to_string_lossy(), big_cap);
assert_eq!(
product.source_path,
path.to_string_lossy(),
"cap read returns the parsed product"
);
}
}
#[test]
fn stdin_surrogate_decode_is_total() {
let raw = std::fs::read(hostile_dir().join("class-c-stdin-surrogate.md")).unwrap();
assert!(
String::from_utf8(raw.clone()).is_err(),
"fixture must carry invalid UTF-8"
);
let text = rac_engine::pycompat::decode_stdin_surrogateescape(&raw);
let artifact = parse::parse_text(&text, "-"); let _ = validate(&artifact, None, None); }