#![cfg_attr(coverage_nightly, coverage(off))]
use super::{Analyzer, ProjectAnalyzer};
use anyhow::Result;
use async_trait::async_trait;
use std::path::Path;
pub struct DefectAnalyzer;
impl Default for DefectAnalyzer {
fn default() -> Self {
Self::new()
}
}
impl DefectAnalyzer {
#[must_use]
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl Analyzer for DefectAnalyzer {
type Input = super::ProjectInput;
type Output = DefectReport;
type Config = super::ProjectConfig;
async fn analyze(&self, input: Self::Input, _config: Self::Config) -> Result<Self::Output> {
let total_files_analyzed = self.count_analyzed_files(&input.project_path)?;
Ok(DefectReport {
defects: Vec::new(), categories_analyzed: vec![
crate::models::defect_report::DefectCategory::Complexity,
crate::models::defect_report::DefectCategory::TechnicalDebt,
],
total_files_analyzed,
})
}
fn name(&self) -> &'static str {
"defect"
}
}
impl DefectAnalyzer {
fn count_analyzed_files(&self, path: &Path) -> Result<usize> {
let mut count = 0;
if path.is_dir() {
for entry in std::fs::read_dir(path)? {
let entry = entry?;
let file_path = entry.path();
if file_path.is_file() {
if let Some(extension) = file_path.extension() {
if let Some(ext_str) = extension.to_str() {
if matches!(
ext_str,
"rs" | "ts" | "js" | "py" | "c" | "cpp" | "h" | "hpp"
) {
count += 1;
}
}
}
} else if file_path.is_dir() {
count += self.count_analyzed_files(&file_path)?;
}
}
} else if path.is_file() {
count = 1;
}
Ok(count)
}
}
impl ProjectAnalyzer for DefectAnalyzer {}
#[derive(Debug, Clone)]
pub struct DefectReport {
pub defects: Vec<crate::models::defect_report::Defect>,
pub categories_analyzed: Vec<crate::models::defect_report::DefectCategory>,
pub total_files_analyzed: usize,
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}