use std::path::Path;
use repopilot::rules::eval::fixtures::evaluate_rule_fixtures;
use repopilot::rules::eval::{RuleEvaluationReport, RuleEvaluationRuleReport};
const SECURITY_RULES_WITH_013_FIXTURES: &[&str] = &[
"security.env-file-committed",
"security.secret-candidate",
"security.private-key-candidate",
];
const IMPORT_GRAPH_RULES_WITH_013_FIXTURES: &[&str] = &[
"architecture.circular-dependency",
"architecture.excessive-fan-out",
"architecture.high-instability-hub",
];
const RUNTIME_RULES_WITH_013_FIXTURES: &[&str] = &[
"language.rust.panic-risk",
"language.go.panic-exit-risk",
"language.python.exception-risk",
"language.javascript.runtime-exit-risk",
"language.managed.fatal-exception-risk",
];
#[test]
fn given_security_rule_fixtures_when_eval_rules_runs_then_quality_gates_pass() {
let fixture_root = rule_fixture_root();
for rule_id in SECURITY_RULES_WITH_013_FIXTURES {
let report = evaluate_rule(rule_id, &fixture_root);
assert_single_rule_report(rule_id, &report);
let rule_report = first_rule_report(rule_id, &report);
assert_rule_fixture_coverage_is_clean(rule_id, rule_report);
}
}
#[test]
fn given_import_graph_rule_fixtures_when_eval_rules_runs_then_quality_gates_pass() {
let fixture_root = rule_fixture_root();
for rule_id in IMPORT_GRAPH_RULES_WITH_013_FIXTURES {
let report = evaluate_rule(rule_id, &fixture_root);
assert_single_rule_report(rule_id, &report);
let rule_report = first_rule_report(rule_id, &report);
assert_rule_fixture_coverage_is_clean(rule_id, rule_report);
}
}
#[test]
fn given_runtime_rule_fixtures_when_eval_rules_runs_then_quality_gates_pass() {
let fixture_root = rule_fixture_root();
for rule_id in RUNTIME_RULES_WITH_013_FIXTURES {
let report = evaluate_rule(rule_id, &fixture_root);
assert_single_rule_report(rule_id, &report);
let rule_report = first_rule_report(rule_id, &report);
assert_rule_fixture_coverage_is_clean(rule_id, rule_report);
}
}
fn rule_fixture_root() -> std::path::PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/rules")
}
fn evaluate_rule(rule_id: &str, fixture_root: &Path) -> RuleEvaluationReport {
evaluate_rule_fixtures(Some(rule_id), Some(fixture_root))
.unwrap_or_else(|error| panic!("failed to evaluate fixtures for {rule_id}: {error}"))
}
fn assert_single_rule_report(rule_id: &str, report: &RuleEvaluationReport) {
assert_eq!(
report.rules_evaluated, 1,
"expected exactly one evaluated rule for {rule_id}: {report:#?}"
);
}
fn first_rule_report<'a>(
rule_id: &str,
report: &'a RuleEvaluationReport,
) -> &'a RuleEvaluationRuleReport {
report
.rules
.first()
.unwrap_or_else(|| panic!("missing rule report for {rule_id}"))
}
fn assert_rule_fixture_coverage_is_clean(rule_id: &str, rule_report: &RuleEvaluationRuleReport) {
assert!(
rule_report.fixtures_total >= 2,
"expected true-positive and false-positive fixtures for {rule_id}: {rule_report:#?}"
);
assert!(
rule_report.has_true_positive_fixture,
"expected true-positive fixture for {rule_id}: {rule_report:#?}"
);
assert!(
rule_report.has_false_positive_fixture,
"expected false-positive fixture for {rule_id}: {rule_report:#?}"
);
assert_eq!(
rule_report.missing_findings, 0,
"fixture is missing expected findings for {rule_id}: {rule_report:#?}"
);
assert_eq!(
rule_report.unexpected_findings, 0,
"fixture has unexpected findings for {rule_id}: {rule_report:#?}"
);
assert_eq!(
rule_report.contract_violations, 0,
"fixture produced finding contract violations for {rule_id}: {rule_report:#?}"
);
assert_eq!(
rule_report.stable_id_failures, 0,
"fixture produced unstable/duplicate finding IDs for {rule_id}: {rule_report:#?}"
);
assert_eq!(
rule_report.quality_gate_failures, 0,
"fixture failed the rule quality gate for {rule_id}: {rule_report:#?}"
);
}