pub use crate::output::unified::{
calculate_architectural_dependency_factor, calculate_instability, classify_coupling_pattern,
CouplingClassification,
};
pub const LOW_CONFIDENCE_THRESHOLD: f64 = 0.5;
pub fn is_low_confidence(completeness_confidence: f64) -> bool {
completeness_confidence < LOW_CONFIDENCE_THRESHOLD
}
pub fn generate_confidence_note(completeness_confidence: f64) -> Option<String> {
if completeness_confidence < LOW_CONFIDENCE_THRESHOLD {
Some(format!(
"Low confidence ({:.0}%) - metrics may be incomplete",
completeness_confidence * 100.0
))
} else {
None
}
}
#[derive(Debug, Clone, Default)]
pub struct ArchitecturalSummary {
pub stable_count: usize,
pub concern_count: usize,
pub top_stable: Vec<ArchitecturalItem>,
pub top_concerns: Vec<ArchitecturalItem>,
}
#[derive(Debug, Clone)]
pub struct ArchitecturalItem {
pub file: String,
pub classification: CouplingClassification,
pub instability: f64,
pub production_callers: usize,
pub test_callers: usize,
}
impl ArchitecturalSummary {
pub fn new() -> Self {
Self::default()
}
pub fn add_item(&mut self, item: ArchitecturalItem) {
if item.classification.is_stable_by_design() {
self.stable_count += 1;
if self.top_stable.len() < 10 {
self.top_stable.push(item);
}
} else if item.classification.is_architectural_concern() {
self.concern_count += 1;
if self.top_concerns.len() < 10 {
self.top_concerns.push(item);
}
}
}
pub fn has_stable_items(&self) -> bool {
self.stable_count > 0
}
pub fn has_concerns(&self) -> bool {
self.concern_count > 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_low_confidence_threshold() {
assert!(is_low_confidence(0.0));
assert!(is_low_confidence(0.49));
assert!(!is_low_confidence(0.5));
assert!(!is_low_confidence(0.9));
assert!(!is_low_confidence(1.0));
}
#[test]
fn test_generate_confidence_note() {
assert!(generate_confidence_note(0.3).is_some());
assert!(generate_confidence_note(0.3).unwrap().contains("30%"));
assert!(generate_confidence_note(0.6).is_none());
}
#[test]
fn test_architectural_summary_add_stable() {
let mut summary = ArchitecturalSummary::new();
summary.add_item(ArchitecturalItem {
file: "src/core.rs".to_string(),
classification: CouplingClassification::WellTestedCore,
instability: 0.2,
production_callers: 5,
test_callers: 85,
});
assert_eq!(summary.stable_count, 1);
assert_eq!(summary.concern_count, 0);
assert_eq!(summary.top_stable.len(), 1);
assert!(summary.has_stable_items());
assert!(!summary.has_concerns());
}
#[test]
fn test_architectural_summary_add_concern() {
let mut summary = ArchitecturalSummary::new();
summary.add_item(ArchitecturalItem {
file: "src/unstable.rs".to_string(),
classification: CouplingClassification::UnstableHighCoupling,
instability: 0.8,
production_callers: 15,
test_callers: 2,
});
assert_eq!(summary.stable_count, 0);
assert_eq!(summary.concern_count, 1);
assert_eq!(summary.top_concerns.len(), 1);
assert!(!summary.has_stable_items());
assert!(summary.has_concerns());
}
#[test]
fn test_architectural_summary_limits_to_10() {
let mut summary = ArchitecturalSummary::new();
for i in 0..15 {
summary.add_item(ArchitecturalItem {
file: format!("src/core_{}.rs", i),
classification: CouplingClassification::StableCore,
instability: 0.2,
production_callers: 6,
test_callers: 2,
});
}
assert_eq!(summary.stable_count, 15);
assert_eq!(summary.top_stable.len(), 10);
}
}