code-moniker 0.4.0

Standalone CLI / linter for the code-moniker symbol graph: file and directory probes, project-wide architecture rules.
Documentation
//! Contract harness for executable samples under `samples/catalog/` and
//! `samples/learn/`. Every scenario document must replay exactly to its
//! `cm:expect` block, every configured rule must fire at least once, and a
//! sample that demonstrates nothing is rejected. `CM_SCENARIO_BLESS=1` rewrites
//! the expect blocks from the observed violations instead of asserting.

use std::path::{Path, PathBuf};

use code_moniker_check::scenario::Scenario;

const SCHEME: &str = "code+moniker://";

fn samples_dirs() -> [PathBuf; 2] {
	let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../samples");
	[root.join("catalog"), root.join("learn")]
}

fn bless_requested() -> bool {
	std::env::var_os("CM_SCENARIO_BLESS").is_some_and(|value| value == "1")
}

#[test]
fn samples_match_their_expectations() {
	let mut checked = 0;
	for dir in samples_dirs() {
		for entry in std::fs::read_dir(&dir).unwrap_or_else(|error| {
			panic!("samples directory {}: {error}", dir.display());
		}) {
			let path = entry.expect("samples entry").path();
			if !path
				.file_name()
				.and_then(|name| name.to_str())
				.is_some_and(|name| name.ends_with(".cm.md"))
			{
				continue;
			}
			check_sample(&path);
			checked += 1;
		}
	}
	assert!(
		checked >= 2 * samples_dirs().len(),
		"expected executable scenario samples in samples/catalog and samples/learn"
	);
}

fn check_sample(path: &Path) {
	let document = std::fs::read_to_string(path).expect("read sample");
	let scenario =
		Scenario::parse(&document).unwrap_or_else(|error| panic!("{}: {error}", path.display()));
	let run = scenario.run(Path::new("."), SCHEME).expect("run scenario");
	if bless_requested() {
		std::fs::write(path, scenario.bless(&document, &run.actual)).expect("bless sample");
		return;
	}
	assert!(
		run.is_match(),
		"{} does not replay to its expectations:\n{}",
		path.display(),
		run.mismatch_summary()
	);
	assert!(
		run.silent_rules.is_empty(),
		"{}: rules never fired (demonstrate them or add a `! <rule-id> <reason>` line): {}",
		path.display(),
		run.silent_rules.join(", ")
	);
	assert!(
		run.stale_undemonstrated.is_empty(),
		"{}: rules marked undemonstrated actually fire: {}",
		path.display(),
		run.stale_undemonstrated.join(", ")
	);
	assert!(
		!run.actual.is_empty(),
		"{} demonstrates no violation",
		path.display()
	);
}