code-moniker-check 0.7.1

Rules engine for code-moniker: DSL, rule config/profiles, evaluation over the symbol graph, and suppression.
Documentation
use std::fs;
use std::path::Path;

use code_moniker_check::RuleVerdict;
use code_moniker_check::workspace::{
	WorkspaceCheckRunner, WorkspaceCheckRunnerOptions, WorkspaceEvaluationMode,
};
use code_moniker_workspace::registry::{LocalWorkspaceOptions, LocalWorkspaceRegistry};
use code_moniker_workspace::snapshot::{WorkspaceRequest, WorkspaceTransition};
use code_moniker_workspace::source::LocalResourceCache;

const SCHEME: &str = "code+moniker://";
const RULE_ID: &str = "workspace.symbol.target-has-callers";

fn write(root: &Path, path: &str, source: &str) {
	let target = root.join(path);
	fs::create_dir_all(target.parent().expect("fixture parent")).expect("fixture directory");
	fs::write(target, source).expect("fixture source");
}

#[test]
fn snapshot_runner_evaluates_t2_against_current_linkage() {
	let fixture = tempfile::tempdir().expect("workspace fixture");
	write(fixture.path(), "src/target.rs", "pub fn target() {}\n");
	write(
		fixture.path(),
		"src/lib.rs",
		"mod target;\npub fn build() { target::target(); }\n",
	);
	let rules = fixture.path().join(".code-moniker.toml");
	fs::write(
		&rules,
		r#"
default_rules = false

[workspace]
min_linkage_coverage = 100

[[workspace.symbol.where]]
id = "target-has-callers"
severity = "warn"
expr = "(shape = 'callable' AND name =~ ^target) => count(in_refs) >= 1"
"#,
	)
	.expect("rules");
	let cache = LocalResourceCache::default();
	let mut registry = LocalWorkspaceRegistry::local_with_cache(
		LocalWorkspaceOptions::new(vec![fixture.path().to_path_buf()], None),
		cache.clone(),
	);
	let transition = registry
		.commands()
		.refresh(WorkspaceRequest::new("workspace-linkage-seed"));
	assert!(matches!(transition, WorkspaceTransition::Ready { .. }));
	let initial = registry.queries().snapshot().expect("initial snapshot");
	assert!(initial.linkage.resolved_refs > 0);
	let mut runner = WorkspaceCheckRunner::new(
		WorkspaceCheckRunnerOptions::new(rules.clone(), None, SCHEME),
		cache,
	);
	let passing = runner
		.run_check(&initial.index, &initial.linkage)
		.expect("passing linkage check");
	let report = passing
		.reports
		.iter()
		.find(|report| report.rule_id == RULE_ID)
		.expect("linkage rule report");
	assert_eq!(report.verdict, Some(RuleVerdict::Pass));
	assert_eq!(
		report.coverage.as_ref().map(|coverage| coverage.percent),
		Some(100)
	);
	assert!(
		passing
			.diagnostics
			.iter()
			.all(|diagnostic| diagnostic.rule_id != RULE_ID)
	);

	let lib = fixture.path().join("src/lib.rs");
	fs::write(&lib, "mod target;\npub fn build() {}\n").expect("remove target reference");
	let transition = registry.commands().refresh_paths(
		WorkspaceRequest::new("workspace-linkage-remove-reference"),
		vec![lib],
	);
	assert!(matches!(transition, WorkspaceTransition::Ready { .. }));
	let changed = registry.queries().snapshot().expect("changed snapshot");
	let failing = runner
		.run_check(&changed.index, &changed.linkage)
		.expect("failing linkage check");
	assert_eq!(failing.evaluation.mode, WorkspaceEvaluationMode::Full);
	assert!(
		failing
			.diagnostics
			.iter()
			.any(|diagnostic| diagnostic.rule_id == RULE_ID)
	);
	assert_eq!(
		failing
			.reports
			.iter()
			.find(|report| report.rule_id == RULE_ID)
			.and_then(|report| report.verdict),
		Some(RuleVerdict::Fail)
	);
}

#[test]
fn excluded_reference_sources_do_not_feed_linkage_metrics() {
	let fixture = tempfile::tempdir().expect("workspace fixture");
	write(fixture.path(), "src/target.rs", "pub fn target() {}\n");
	write(
		fixture.path(),
		"src/generated.rs",
		"pub fn generated() { crate::target::target(); }\n",
	);
	write(
		fixture.path(),
		"src/lib.rs",
		"mod target;\nmod generated;\npub fn build() {}\n",
	);
	let rules = fixture.path().join(".code-moniker.toml");
	fs::write(
		&rules,
		r#"
default_rules = false

[exclude]
uris = ["**/generated.rs"]

[[workspace.symbol.where]]
id = "target-has-callers"
severity = "warn"
expr = "(shape = 'callable' AND name =~ ^target) => count(in_refs) >= 1"
"#,
	)
	.expect("rules");
	let cache = LocalResourceCache::default();
	let mut registry = LocalWorkspaceRegistry::local_with_cache(
		LocalWorkspaceOptions::new(vec![fixture.path().to_path_buf()], None),
		cache.clone(),
	);
	assert!(matches!(
		registry
			.commands()
			.refresh(WorkspaceRequest::new("workspace-linkage-excluded-source")),
		WorkspaceTransition::Ready { .. }
	));
	let snapshot = registry.queries().snapshot().expect("snapshot");
	let mut runner =
		WorkspaceCheckRunner::new(WorkspaceCheckRunnerOptions::new(rules, None, SCHEME), cache);

	let diagnostics = runner
		.run_check(&snapshot.index, &snapshot.linkage)
		.expect("linkage check");
	assert!(
		diagnostics
			.diagnostics
			.iter()
			.any(|diagnostic| diagnostic.rule_id == RULE_ID),
		"the only caller is excluded from the review surface"
	);
}

#[test]
fn suppression_realigns_linkage_report_verdict() {
	let fixture = tempfile::tempdir().expect("workspace fixture");
	write(
		fixture.path(),
		"src/target.rs",
		"// code-moniker: ignore-file[target-has-callers]\npub fn target() {}\n",
	);
	write(
		fixture.path(),
		"src/lib.rs",
		"mod target;\npub fn build() {}\n",
	);
	let rules = fixture.path().join(".code-moniker.toml");
	fs::write(
		&rules,
		r#"
default_rules = false

[[workspace.symbol.where]]
id = "target-has-callers"
severity = "warn"
expr = "(shape = 'callable' AND name =~ ^target) => count(in_refs) >= 1"
"#,
	)
	.expect("rules");
	let cache = LocalResourceCache::default();
	let mut registry = LocalWorkspaceRegistry::local_with_cache(
		LocalWorkspaceOptions::new(vec![fixture.path().to_path_buf()], None),
		cache.clone(),
	);
	assert!(matches!(
		registry
			.commands()
			.refresh(WorkspaceRequest::new("workspace-linkage-suppressed")),
		WorkspaceTransition::Ready { .. }
	));
	let snapshot = registry.queries().snapshot().expect("snapshot");
	let mut runner =
		WorkspaceCheckRunner::new(WorkspaceCheckRunnerOptions::new(rules, None, SCHEME), cache);

	let diagnostics = runner
		.run_check(&snapshot.index, &snapshot.linkage)
		.expect("linkage check");
	assert!(
		diagnostics
			.diagnostics
			.iter()
			.all(|diagnostic| diagnostic.rule_id != RULE_ID)
	);
	let report = diagnostics
		.reports
		.iter()
		.find(|report| report.rule_id == RULE_ID)
		.expect("linkage report");
	assert_eq!(report.violations, 0);
	assert_eq!(report.verdict, Some(RuleVerdict::Pass));
}