use std::path::{Path, PathBuf};
use secunit_core::schemas::Schema;
use serde_json::Value;
fn examples_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.join("docs/examples")
.canonicalize()
.expect("docs/examples must exist relative to the secunit-core crate")
}
fn read_yaml(path: &Path) -> Value {
let text = std::fs::read_to_string(path).unwrap_or_else(|e| panic!("read {path:?}: {e}"));
serde_yaml::from_str(&text).unwrap_or_else(|e| panic!("parse YAML {path:?}: {e}"))
}
fn read_json(path: &Path) -> Value {
let text = std::fs::read_to_string(path).unwrap_or_else(|e| panic!("read {path:?}: {e}"));
serde_json::from_str(&text).unwrap_or_else(|e| panic!("parse JSON {path:?}: {e}"))
}
fn assert_valid(schema: Schema, path: &Path, value: &Value) {
let errs = schema.validate(value);
assert!(
errs.is_empty(),
"{path:?} failed {schema:?} schema:\n {}",
errs.join("\n ")
);
}
#[test]
fn controls_validate() {
let root = examples_root().join("controls");
let mut count = 0;
for entry in std::fs::read_dir(&root).unwrap() {
let path = entry.unwrap().path();
if path.extension().and_then(|s| s.to_str()) != Some("yaml") {
continue;
}
assert_valid(Schema::Control, &path, &read_yaml(&path));
count += 1;
}
assert!(count > 0, "no control examples found under {root:?}");
}
#[test]
fn inventory_validates() {
let path = examples_root().join("inventory.yaml");
assert_valid(Schema::Inventory, &path, &read_yaml(&path));
}
#[test]
fn schedule_validates() {
let path = examples_root().join("schedule.yaml");
assert_valid(Schema::Schedule, &path, &read_yaml(&path));
}
#[test]
fn state_validates() {
let path = examples_root().join("state.json");
assert_valid(Schema::State, &path, &read_json(&path));
}
#[test]
fn manifests_validate() {
let root = examples_root().join("evidence");
let mut count = 0;
for entry in walkdir::WalkDir::new(&root) {
let entry = entry.unwrap();
if entry.file_name() == "manifest.json" {
assert_valid(Schema::Manifest, entry.path(), &read_json(entry.path()));
count += 1;
}
}
assert!(count > 0, "no manifest examples found under {root:?}");
}
#[test]
fn risk_index_validates() {
let path = examples_root().join("risks/index.json");
assert_valid(Schema::RiskIndex, &path, &read_json(&path));
}
#[test]
fn risk_event_logs_validate() {
let root = examples_root().join("risks");
let mut lines = 0;
for entry in walkdir::WalkDir::new(&root) {
let entry = entry.unwrap();
if entry.file_name() != "events.jsonl" {
continue;
}
let text = std::fs::read_to_string(entry.path())
.unwrap_or_else(|e| panic!("read {:?}: {e}", entry.path()));
for line in text.lines().filter(|l| !l.trim().is_empty()) {
let value: Value = serde_json::from_str(line)
.unwrap_or_else(|e| panic!("parse event in {:?}: {e}", entry.path()));
assert_valid(Schema::RiskEvent, entry.path(), &value);
lines += 1;
}
}
assert!(lines > 0, "no risk event examples found under {root:?}");
}