use super::*;
use crate::models::Finding;
use crate::pipeline::letter_grade::Grade;
fn finding(effort: Effort, confidence: f32) -> Finding {
Finding::new("src/lib.rs", "test", "desc", "", confidence, effort)
}
#[test]
fn grade_critical_high_effort_yields_block() {
let findings = vec![finding(Effort::High, 0.9)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Block,
"High-effort finding must floor to BLOCK"
);
}
#[test]
fn grade_high_effort_beats_request_changes() {
let findings = vec![finding(Effort::High, 0.85)];
let verdict = derive_verdict(Verdict::RequestChanges, &findings);
assert_eq!(verdict, Verdict::Block);
}
#[test]
fn grade_two_medium_yields_request_changes() {
let findings = vec![finding(Effort::Medium, 0.8), finding(Effort::Medium, 0.75)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(verdict, Verdict::RequestChanges);
}
#[test]
fn grade_three_medium_yields_request_changes() {
let findings = vec![
finding(Effort::Medium, 0.7),
finding(Effort::Medium, 0.7),
finding(Effort::Medium, 0.7),
];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::RequestChanges);
}
#[test]
fn grade_one_medium_yields_approve_star() {
let findings = vec![finding(Effort::Medium, 0.75)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::ApproveWithReservations);
}
#[test]
fn grade_no_findings_yields_approve() {
let verdict = derive_verdict(Verdict::Approve, &[]);
assert_eq!(verdict, Verdict::Approve);
}
#[test]
fn grade_only_low_yields_approve() {
let findings = vec![finding(Effort::Low, 0.9), finding(Effort::Low, 0.7)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::Approve);
}
#[test]
fn grade_unknown_is_preserved() {
let findings = vec![finding(Effort::Low, 0.9)];
let verdict = derive_verdict(Verdict::Unknown, &findings);
assert_eq!(verdict, Verdict::Unknown, "UNKNOWN must be preserved");
}
#[test]
fn grade_unknown_preserved_with_no_findings() {
let verdict = derive_verdict(Verdict::Unknown, &[]);
assert_eq!(verdict, Verdict::Unknown);
}
#[test]
fn grade_floor_overrides_model_approve() {
let findings = vec![finding(Effort::High, 0.95)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(
verdict,
Verdict::Block,
"severity floor must override model-proposed APPROVE"
);
}
#[test]
fn grade_model_block_kept_when_no_critical_finding() {
let findings = vec![finding(Effort::Medium, 0.9)];
let verdict = derive_verdict(Verdict::Block, &findings);
assert_eq!(
verdict,
Verdict::Block,
"model BLOCK must not be downgraded by floor"
);
}
#[test]
fn grade_model_request_changes_preserved_over_lower_floor() {
let findings = vec![finding(Effort::Low, 0.9)];
let verdict = derive_verdict(Verdict::RequestChanges, &findings);
assert_eq!(verdict, Verdict::RequestChanges);
}
#[test]
fn grade_low_confidence_all_medium_yields_approve() {
let findings = vec![finding(Effort::Medium, 0.6), finding(Effort::Medium, 0.55)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"all-low-confidence advisory batch must not fire APPROVE*"
);
}
#[test]
fn grade_confidence_at_threshold_collapses() {
let findings = vec![finding(Effort::Medium, 0.65)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Approve,
"confidence at threshold must collapse"
);
}
#[test]
fn grade_high_confidence_medium_beats_low_confidence_check() {
let findings = vec![finding(Effort::Medium, 0.66)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::ApproveWithReservations);
}
#[test]
fn grade_mixed_confidence_two_medium_not_collapsed() {
let findings = vec![finding(Effort::Medium, 0.8), finding(Effort::Medium, 0.5)];
let verdict = derive_verdict(Verdict::Approve, &findings);
assert_eq!(verdict, Verdict::RequestChanges);
}
#[test]
fn grade_compile_break_high_effort_flows_to_block() {
let findings = vec![finding(Effort::High, 0.95)];
let verdict = derive_verdict(Verdict::ApproveWithReservations, &findings);
assert_eq!(
verdict,
Verdict::Block,
"compile-break (High effort) must escalate to BLOCK"
);
}
#[test]
fn derive_verdict_with_grade_grade_a_no_findings_approve() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::A, &[]);
assert_eq!(v, Verdict::Approve);
assert_eq!(g, Grade::A);
}
#[test]
fn derive_verdict_with_grade_grade_f_no_findings_block() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::F, &[]);
assert_eq!(v, Verdict::Block);
assert_eq!(g, Grade::F);
}
#[test]
fn derive_verdict_with_grade_severity_overrides_grade_a() {
let findings = vec![finding(Effort::High, 0.9)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::A, &findings);
assert_eq!(v, Verdict::Block, "severity floor must override grade A");
assert_eq!(g, Grade::F, "grade must be clamped to F when verdict=BLOCK");
}
#[test]
fn derive_verdict_with_grade_b_minus_yields_approve() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::BMinus, &[]);
assert_eq!(v, Verdict::Approve);
assert_eq!(g, Grade::BMinus);
}
#[test]
fn derive_verdict_with_grade_c_plus_yields_approve_star() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::CPlus, &[]);
assert_eq!(v, Verdict::ApproveWithReservations);
assert_eq!(g, Grade::CPlus);
}
#[test]
fn derive_verdict_with_grade_c_minus_yields_approve_star() {
let (v, _g) = derive_verdict_with_grade(Verdict::Approve, Grade::CMinus, &[]);
assert_eq!(v, Verdict::ApproveWithReservations);
}
#[test]
fn derive_verdict_with_grade_d_plus_yields_request_changes() {
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::DPlus, &[]);
assert_eq!(v, Verdict::RequestChanges);
assert_eq!(g, Grade::DPlus);
}
#[test]
fn derive_verdict_with_grade_d_minus_yields_request_changes() {
let (v, _g) = derive_verdict_with_grade(Verdict::Approve, Grade::DMinus, &[]);
assert_eq!(v, Verdict::RequestChanges);
}
#[test]
fn derive_verdict_with_grade_model_escalates_above_grade() {
let (v, g) = derive_verdict_with_grade(Verdict::ApproveWithReservations, Grade::A, &[]);
assert_eq!(v, Verdict::ApproveWithReservations);
assert_eq!(g, Grade::CPlus);
}
#[test]
fn derive_verdict_with_grade_floor_stricter_than_grade() {
let findings = vec![finding(Effort::Medium, 0.8), finding(Effort::Medium, 0.8)];
let (v, g) = derive_verdict_with_grade(Verdict::Approve, Grade::CMinus, &findings);
assert_eq!(v, Verdict::RequestChanges);
assert_eq!(
g,
Grade::DPlus,
"grade must clamp to D+ (ceiling of REQUEST_CHANGES)"
);
}