#![cfg_attr(coverage_nightly, coverage(off))]
use serde::{Deserialize, Serialize};
use std::time::SystemTime;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Metrics {
pub complexity: u32,
pub cognitive: u32,
pub satd_count: u32,
pub coverage: f64,
pub lines: u32,
pub functions: u32,
pub timestamp: SystemTime,
}
impl Default for Metrics {
fn default() -> Self {
Self {
complexity: 0,
cognitive: 0,
satd_count: 0,
coverage: 0.0,
lines: 0,
functions: 0,
timestamp: SystemTime::now(),
}
}
}
impl Metrics {
#[must_use]
pub fn quality_score(&self) -> f64 {
let mut score = 1.0;
if self.complexity > 20 {
score -= 0.3;
} else if self.complexity > 10 {
score -= 0.1;
}
if self.cognitive > 15 {
score -= 0.2;
} else if self.cognitive > 10 {
score -= 0.1;
}
if self.satd_count > 0 {
score -= (f64::from(self.satd_count) * 0.05).min(0.3);
}
if self.coverage < 0.6 {
score -= 0.2;
} else if self.coverage < 0.8 {
score -= 0.1;
}
score.max(0.0)
}
#[must_use]
pub fn meets_thresholds(&self, thresholds: &QualityThresholds) -> bool {
self.complexity <= thresholds.max_complexity
&& self.cognitive <= thresholds.max_cognitive
&& self.satd_count <= thresholds.max_satd
&& self.coverage >= thresholds.min_coverage
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QualityThresholds {
pub max_complexity: u32,
pub max_cognitive: u32,
pub max_satd: u32,
pub min_coverage: f64,
}
impl Default for QualityThresholds {
fn default() -> Self {
Self {
max_complexity: 20,
max_cognitive: 15,
max_satd: 0,
min_coverage: 0.8,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProjectMetrics {
pub total_files: usize,
pub total_functions: usize,
pub avg_complexity: f64,
pub avg_cognitive: f64,
pub total_satd: u32,
pub avg_coverage: f64,
pub violations: Vec<Violation>,
pub quality_score: f64,
pub timestamp: SystemTime,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Violation {
pub file: String,
pub violation_type: ViolationType,
pub severity: Severity,
pub value: f64,
pub threshold: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum ViolationType {
Complexity,
Cognitive,
Satd,
Coverage,
DeadCode,
UnusedImport,
Formatting,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Severity {
Low,
Medium,
High,
Critical,
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quality_score_calculation() {
let metrics = Metrics {
complexity: 5,
cognitive: 8,
satd_count: 0,
coverage: 0.85,
lines: 100,
functions: 5,
timestamp: SystemTime::now(),
};
assert!(metrics.quality_score() > 0.9);
}
#[test]
fn test_quality_score_with_violations() {
let metrics = Metrics {
complexity: 25,
cognitive: 20,
satd_count: 5,
coverage: 0.5,
lines: 200,
functions: 10,
timestamp: SystemTime::now(),
};
assert!(metrics.quality_score() < 0.5);
}
#[test]
fn test_meets_thresholds() {
let metrics = Metrics {
complexity: 10,
cognitive: 10,
satd_count: 0,
coverage: 0.8,
lines: 100,
functions: 5,
timestamp: SystemTime::now(),
};
let thresholds = QualityThresholds::default();
assert!(metrics.meets_thresholds(&thresholds));
}
}