pmat 3.15.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
#![cfg_attr(coverage_nightly, coverage(off))]
// Unified Context with Advanced Annotations - Extreme TDD Implementation
use crate::services::context::{AstItem, ProjectContext, ProjectSummary};
use anyhow::Result;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use tracing::{info, warn};

/// Advanced context builder that integrates all analysis types
pub struct AdvancedUnifiedContextBuilder {
    project_path: PathBuf,
    output: String,
    pub enable_big_o: bool,
    pub enable_entropy: bool,
    pub enable_provability: bool,
    pub enable_graph_metrics: bool,
    pub enable_tdg: bool,
    pub enable_dead_code: bool,
    pub enable_satd: bool,
}

// Core builder methods: new, build_complete_context, get_basic_context,
// add_project_header, add_project_structure, add_key_components
include!("unified_context_advanced_builder.rs");

// Analysis rendering and stub execution methods: add_big_o_analysis,
// add_entropy_analysis, add_provability_analysis, add_graph_metrics,
// add_tdg_analysis, add_dead_code_analysis, add_satd_analysis,
// add_quality_insights, add_recommendations, and all run_*() stubs
include!("unified_context_advanced_analysis.rs");

// Data structures for analysis results

struct EntropyData {
    pattern_entropy: f64,
    duplication_percentage: f64,
    structural_entropy: f64,
    actionable_items: Vec<String>,
}

struct ProvabilityData {
    invariants: Vec<String>,
    preconditions: Vec<String>,
    postconditions: Vec<String>,
    verified: bool,
}

struct GraphMetricsData {
    betweenness: f64,
    closeness: f64,
    degree: f64,
    node_count: usize,
    edge_count: usize,
    density: f64,
    critical_paths: Vec<String>,
}

struct TdgData {
    overall_score: f64,
    file_scores: HashMap<String, f64>,
    hotspots: Vec<TdgHotspot>,
    priorities: Vec<String>,
}

struct TdgHotspot {
    location: String,
    score: f64,
}

struct DeadCodeData {
    unreachable_functions: Vec<String>,
    unused_variables: Vec<String>,
    unused_imports: Vec<String>,
}

impl DeadCodeData {
    fn total_dead_items(&self) -> usize {
        self.unreachable_functions.len() + self.unused_variables.len() + self.unused_imports.len()
    }
}

struct SatdData {
    todos: Vec<SatdComment>,
    fixmes: Vec<SatdComment>,
    hacks: Vec<SatdComment>,
    design_debt: usize,
    code_debt: usize,
    test_debt: usize,
    doc_debt: usize,
}

impl SatdData {
    fn total_satd_count(&self) -> usize {
        self.todos.len() + self.fixmes.len() + self.hacks.len()
    }
}

struct SatdComment {
    location: String,
    comment: String,
}

// Tests
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
    use super::*;
    use std::fs;
    use tempfile::TempDir;

    #[tokio::test]
    async fn test_unified_context_includes_all_sections() {
        let temp_dir = TempDir::new().unwrap();
        let test_file = temp_dir.path().join("test.rs");
        fs::write(&test_file, "fn main() { println!(\"test\"); }").unwrap();

        let mut builder = AdvancedUnifiedContextBuilder::new(temp_dir.path());
        let result = builder.build_complete_context().await.unwrap();

        // Verify all sections are present
        assert!(result.contains("# Project Context"));
        assert!(result.contains("## Project Structure"));
        assert!(result.contains("## Key Components"));
        assert!(result.contains("## Big-O Complexity Analysis"));
        assert!(result.contains("## Entropy Analysis"));
        assert!(result.contains("## Provability Analysis"));
        assert!(result.contains("## Graph Metrics"));
        assert!(result.contains("## Technical Debt Gradient"));
        assert!(result.contains("## Dead Code Analysis"));
        assert!(result.contains("## Self-Admitted Technical Debt"));
        assert!(result.contains("## Quality Insights"));
        assert!(result.contains("## Recommendations"));
    }

    #[tokio::test]
    async fn test_context_with_disabled_features() {
        let temp_dir = TempDir::new().unwrap();

        let mut builder = AdvancedUnifiedContextBuilder::new(temp_dir.path());
        builder.enable_provability = false;
        builder.enable_graph_metrics = false;

        let result = builder.build_complete_context().await.unwrap();

        // These should be present
        assert!(result.contains("## Big-O Complexity Analysis"));
        assert!(result.contains("## Entropy Analysis"));

        // These should not be present
        assert!(!result.contains("## Provability Analysis"));
        assert!(!result.contains("## Graph Metrics"));
    }

    #[test]
    fn test_dead_code_total_calculation() {
        let dead_code = DeadCodeData {
            unreachable_functions: vec!["func1".to_string(), "func2".to_string()],
            unused_variables: vec!["var1".to_string()],
            unused_imports: vec!["import1".to_string(), "import2".to_string()],
        };

        assert_eq!(dead_code.total_dead_items(), 5);
    }

    #[test]
    fn test_satd_total_calculation() {
        let satd = SatdData {
            todos: vec![
                SatdComment {
                    location: "file1".to_string(),
                    comment: "TODO: fix".to_string(),
                },
                SatdComment {
                    location: "file2".to_string(),
                    comment: "TODO: improve".to_string(),
                },
            ],
            fixmes: vec![SatdComment {
                location: "file3".to_string(),
                comment: "FIXME: bug".to_string(),
            }],
            hacks: vec![],
            design_debt: 0,
            code_debt: 0,
            test_debt: 0,
            doc_debt: 0,
        };

        assert_eq!(satd.total_satd_count(), 3);
    }
}