use marque_capco::capco_rules;
use marque_config::Config;
use marque_engine::{Engine, FixMode, FixedClock};
use std::time::{Duration, UNIX_EPOCH};
const FIXED_TS: u64 = 1_700_000_000;
fn test_engine() -> Engine {
Engine::with_clock(
Config::default(),
vec![Box::new(capco_rules())],
Box::new(FixedClock::new(UNIX_EPOCH + Duration::from_secs(FIXED_TS))),
)
}
#[test]
fn applied_fix_has_all_required_fields() {
let engine = test_engine();
let source = b"SECRET//NF\n";
let result = engine.fix(source, FixMode::Apply);
assert!(
!result.applied.is_empty(),
"should have at least one applied fix"
);
for fix in &result.applied {
let rule = fix.proposal.rule.as_str();
assert!(!rule.is_empty(), "rule ID must not be empty");
assert!(
rule.len() == 4
&& (rule.starts_with('E') || rule.starts_with('W') || rule.starts_with('C')),
"rule ID must match [EWC]NNN pattern, got: {rule}"
);
let source_str = match fix.proposal.source {
marque_rules::FixSource::BuiltinRule => "BuiltinRule",
marque_rules::FixSource::CorrectionsMap => "CorrectionsMap",
marque_rules::FixSource::MigrationTable => "MigrationTable",
};
assert!(
["BuiltinRule", "CorrectionsMap", "MigrationTable"].contains(&source_str),
"source must be a valid enum variant"
);
assert!(
fix.proposal.span.start < fix.proposal.span.end,
"span must be non-empty: {:?}",
fix.proposal.span
);
assert!(
!fix.proposal.replacement.is_empty(),
"replacement must not be empty"
);
assert!(
(0.0..=1.0).contains(&fix.proposal.confidence),
"confidence must be in [0.0, 1.0], got: {}",
fix.proposal.confidence
);
assert!(
fix.timestamp >= UNIX_EPOCH,
"timestamp must be after UNIX epoch"
);
}
}
#[test]
fn sub_threshold_proposals_never_in_applied() {
let engine = test_engine();
let source = b"SECRET//NOFORN//SI\n";
let result = engine.fix(source, FixMode::Apply);
for fix in &result.applied {
assert!(
fix.proposal.confidence >= 0.95,
"sub-threshold fix (confidence {}) must not appear in applied",
fix.proposal.confidence
);
}
assert!(
result
.remaining_diagnostics
.iter()
.any(|d| d.rule.as_str() == "E003"),
"E003 should remain as a suggestion in remaining_diagnostics"
);
}
#[test]
fn dry_run_applied_fixes_have_dry_run_flag() {
let engine = test_engine();
let source = b"SECRET//NF\n";
let result = engine.fix(source, FixMode::DryRun);
for fix in &result.applied {
assert!(
fix.dry_run,
"all DryRun applied fixes must have dry_run=true"
);
}
}
#[test]
fn applied_fix_timestamp_matches_clock() {
let expected_ts = UNIX_EPOCH + Duration::from_secs(FIXED_TS);
let engine = test_engine();
let source = b"SECRET//NF\n";
let result = engine.fix(source, FixMode::Apply);
for fix in &result.applied {
assert_eq!(
fix.timestamp, expected_ts,
"timestamp should match the injected FixedClock"
);
}
}