use super::core::GeneratedTestSuite;
use std::collections::{HashMap, HashSet};
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct BranchId {
pub function: String,
pub line: usize,
pub branch_type: BranchType,
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum BranchType {
IfThen,
IfElse,
WhileBody,
ForBody,
CaseArm(usize),
}
pub struct CoverageTracker {
lines_covered: HashSet<usize>,
branches_covered: HashSet<BranchId>,
total_lines: usize,
total_branches: usize,
#[allow(dead_code)]
function_coverage: HashMap<String, FunctionCoverage>,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
struct FunctionCoverage {
lines: HashSet<usize>,
branches: HashSet<BranchId>,
total_lines: usize,
total_branches: usize,
}
impl Default for CoverageTracker {
fn default() -> Self {
Self::new()
}
}
impl CoverageTracker {
pub fn new() -> Self {
Self {
lines_covered: HashSet::new(),
branches_covered: HashSet::new(),
total_lines: 0,
total_branches: 0,
function_coverage: HashMap::new(),
}
}
pub fn analyze(&mut self, suite: &GeneratedTestSuite) {
for test in &suite.unit_tests {
for _assertion in &test.assertions {
self.mark_covered(test.name.as_str());
}
}
for _prop_test in &suite.property_tests {
}
}
fn mark_covered(&mut self, _test_name: &str) {
self.lines_covered.insert(1);
}
pub fn coverage_percentage(&self) -> f64 {
if self.total_lines == 0 {
return 100.0; }
(self.lines_covered.len() as f64 / self.total_lines as f64) * 100.0
}
pub fn branch_coverage(&self) -> f64 {
if self.total_branches == 0 {
return 100.0; }
(self.branches_covered.len() as f64 / self.total_branches as f64) * 100.0
}
pub fn is_sufficient(&self, target: f64) -> bool {
self.coverage_percentage() >= target
}
pub fn uncovered_paths(&self) -> Vec<UncoveredPath> {
let mut uncovered = Vec::new();
for line in 1..=self.total_lines {
if !self.lines_covered.contains(&line) {
uncovered.push(UncoveredPath::Line(line));
}
}
uncovered
}
pub fn set_total_lines(&mut self, total: usize) {
self.total_lines = total;
}
pub fn set_total_branches(&mut self, total: usize) {
self.total_branches = total;
}
}
#[derive(Debug, Clone)]
pub enum UncoveredPath {
Line(usize),
Branch(BranchId),
Function(String),
}
#[derive(Debug, Clone)]
pub struct QualityReport {
pub fmt_passed: bool,
pub clippy_passed: bool,
pub coverage_percentage: f64,
pub mutation_score: f64,
pub meets_quality_gates: bool,
pub suggestions: Vec<String>,
}
impl QualityReport {
pub fn display(&self) -> String {
format!(
r"
Quality Report
==============
Formatting: {}
Clippy: {}
Coverage: {:.1}%
Mutation Score: {:.1}%
Quality Gates: {}
{}
",
if self.fmt_passed {
"✅ PASS"
} else {
"❌ FAIL"
},
if self.clippy_passed {
"✅ PASS"
} else {
"❌ FAIL"
},
self.coverage_percentage,
self.mutation_score,
if self.meets_quality_gates {
"✅ PASS"
} else {
"❌ FAIL"
},
self.suggestions.join("\n")
)
}
}