pmat 3.16.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
#![cfg_attr(coverage_nightly, coverage(off))]

#[cfg(test)]
mod tests_part2 {
    use crate::cli::handlers::comprehensive_analysis_handler::output::{
        format_complexity_section, format_dead_code_section, format_satd_section,
    };
    use crate::cli::handlers::comprehensive_analysis_handler::types::ComprehensiveAnalysisConfig;
    use crate::cli::ComprehensiveOutputFormat;
    use crate::services::facades::complexity_facade::{
        ComplexityAnalysisResult, ComplexityViolation,
    };
    use crate::services::facades::dead_code_facade::{
        DeadCodeAnalysisResult, DeadCodeItem, DeadCodeType,
    };
    use crate::services::facades::satd_facade::{SatdAnalysisResult, SatdSeverity, SatdViolation};
    use std::path::PathBuf;

    fn make_default_config() -> ComprehensiveAnalysisConfig {
        ComprehensiveAnalysisConfig {
            project_path: PathBuf::from("/test/project"),
            file: None,
            files: Vec::new(),
            format: ComprehensiveOutputFormat::Json,
            include_duplicates: false,
            include_dead_code: true,
            include_defects: false,
            include_complexity: true,
            include_tdg: false,
            confidence_threshold: 0.7,
            min_lines: 50,
            include: None,
            exclude: None,
            output: None,
            perf: false,
            executive_summary: true,
            top_files: 10,
        }
    }

    #[test]
    fn test_format_complexity_section() {
        let complexity = ComplexityAnalysisResult {
            total_files: 25,
            violations: vec![ComplexityViolation {
                file_path: "src/main.rs".to_string(),
                function_name: "complex_fn".to_string(),
                line_number: 10,
                complexity: 30,
                complexity_type: "cyclomatic".to_string(),
            }],
            average_complexity: 12.5,
            max_complexity: 30,
            summary: "Test summary".to_string(),
        };
        let mut output = String::new();
        format_complexity_section(&mut output, &complexity).unwrap();
        assert!(output.contains("## Complexity Analysis"));
        assert!(output.contains("**Files Analyzed**: 25"));
        assert!(output.contains("**Average Complexity**: 12.5"));
        assert!(output.contains("**Max Complexity**: 30"));
        assert!(output.contains("**Violations**: 1"));
        assert!(output.contains("### Top Complexity Violations"));
        assert!(output.contains("complex_fn"));
    }

    #[test]
    fn test_format_complexity_section_no_violations() {
        let complexity = ComplexityAnalysisResult {
            total_files: 10,
            violations: vec![],
            average_complexity: 5.0,
            max_complexity: 10,
            summary: "Clean".to_string(),
        };
        let mut output = String::new();
        format_complexity_section(&mut output, &complexity).unwrap();
        assert!(output.contains("**Violations**: 0"));
        assert!(!output.contains("### Top Complexity Violations"));
    }

    #[test]
    fn test_format_dead_code_section() {
        let dead_code = DeadCodeAnalysisResult {
            total_files: 15,
            dead_items: vec![DeadCodeItem {
                file_path: "src/old.rs".to_string(),
                item_name: "old_function".to_string(),
                item_type: DeadCodeType::Function,
                line_number: 50,
                reason: "Never referenced".to_string(),
            }],
            dead_percentage: 3.5,
            summary: "Found dead code".to_string(),
        };
        let mut output = String::new();
        format_dead_code_section(&mut output, &dead_code).unwrap();
        assert!(output.contains("## Dead Code Analysis"));
        assert!(output.contains("**Files Analyzed**: 15"));
        assert!(output.contains("**Dead Items**: 1"));
        assert!(output.contains("**Dead Code %**: 3.5%"));
        assert!(output.contains("old_function"));
    }

    #[test]
    fn test_format_dead_code_section_empty() {
        let dead_code = DeadCodeAnalysisResult {
            total_files: 10,
            dead_items: vec![],
            dead_percentage: 0.0,
            summary: "No dead code".to_string(),
        };
        let mut output = String::new();
        format_dead_code_section(&mut output, &dead_code).unwrap();
        assert!(output.contains("**Dead Items**: 0"));
        assert!(!output.contains("### Dead Code Items"));
    }

    #[test]
    fn test_format_satd_section() {
        let satd = SatdAnalysisResult {
            total_files: 8,
            violations: vec![SatdViolation {
                file_path: "src/hack.rs".to_string(),
                line_number: 15,
                violation_type: "HACK".to_string(),
                message: "Temporary workaround".to_string(),
                severity: SatdSeverity::High,
            }],
            summary: "Found SATD".to_string(),
        };
        let mut output = String::new();
        format_satd_section(&mut output, &satd).unwrap();
        assert!(output.contains("## Technical Debt (SATD) Analysis"));
        assert!(output.contains("**Files Analyzed**: 8"));
        assert!(output.contains("**Violations**: 1"));
        assert!(output.contains("HACK"));
        assert!(output.contains("High"));
    }

    #[test]
    fn test_format_satd_section_empty() {
        let satd = SatdAnalysisResult {
            total_files: 5,
            violations: vec![],
            summary: "No SATD".to_string(),
        };
        let mut output = String::new();
        format_satd_section(&mut output, &satd).unwrap();
        assert!(output.contains("**Violations**: 0"));
        assert!(!output.contains("### SATD Violations"));
    }

    #[test]
    fn test_format_complexity_section_limits_to_five() {
        let violations: Vec<ComplexityViolation> = (0..10)
            .map(|i| ComplexityViolation {
                file_path: format!("src/file{i}.rs"),
                function_name: format!("function{i}"),
                line_number: i,
                complexity: 25 + i as u32,
                complexity_type: "cyclomatic".to_string(),
            })
            .collect();
        let complexity = ComplexityAnalysisResult {
            total_files: 10,
            violations,
            average_complexity: 30.0,
            max_complexity: 34,
            summary: "Many violations".to_string(),
        };
        let mut output = String::new();
        format_complexity_section(&mut output, &complexity).unwrap();
        assert!(output.contains("5. "));
        assert!(!output.contains("6. "));
    }

    #[test]
    fn test_format_dead_code_section_limits_to_five() {
        let dead_items: Vec<DeadCodeItem> = (0..10)
            .map(|i| DeadCodeItem {
                file_path: format!("src/file{i}.rs"),
                item_name: format!("item{i}"),
                item_type: DeadCodeType::Function,
                line_number: i,
                reason: "Unused".to_string(),
            })
            .collect();
        let dead_code = DeadCodeAnalysisResult {
            total_files: 10,
            dead_items,
            dead_percentage: 10.0,
            summary: "Many dead items".to_string(),
        };
        let mut output = String::new();
        format_dead_code_section(&mut output, &dead_code).unwrap();
        assert!(output.contains("5. "));
        assert!(!output.contains("6. "));
    }

    #[test]
    fn test_format_satd_section_limits_to_five() {
        let violations: Vec<SatdViolation> = (0..10)
            .map(|i| SatdViolation {
                file_path: format!("src/file{i}.rs"),
                line_number: i,
                violation_type: "TODO".to_string(),
                message: format!("Message {i}"),
                severity: SatdSeverity::Low,
            })
            .collect();
        let satd = SatdAnalysisResult {
            total_files: 10,
            violations,
            summary: "Many SATD items".to_string(),
        };
        let mut output = String::new();
        format_satd_section(&mut output, &satd).unwrap();
        assert!(output.contains("5. "));
        assert!(!output.contains("6. "));
    }

    #[test]
    fn test_dead_code_type_variants_in_output() {
        let dead_items = vec![
            DeadCodeItem {
                file_path: "test.rs".to_string(),
                item_name: "unused_fn".to_string(),
                item_type: DeadCodeType::Function,
                line_number: 1,
                reason: "test".to_string(),
            },
            DeadCodeItem {
                file_path: "test.rs".to_string(),
                item_name: "UnusedClass".to_string(),
                item_type: DeadCodeType::Class,
                line_number: 10,
                reason: "test".to_string(),
            },
            DeadCodeItem {
                file_path: "test.rs".to_string(),
                item_name: "unused_var".to_string(),
                item_type: DeadCodeType::Variable,
                line_number: 20,
                reason: "test".to_string(),
            },
            DeadCodeItem {
                file_path: "test.rs".to_string(),
                item_name: "unused_import".to_string(),
                item_type: DeadCodeType::Import,
                line_number: 30,
                reason: "test".to_string(),
            },
            DeadCodeItem {
                file_path: "test.rs".to_string(),
                item_name: "unreachable".to_string(),
                item_type: DeadCodeType::UnreachableCode,
                line_number: 40,
                reason: "test".to_string(),
            },
        ];
        let dead_code = DeadCodeAnalysisResult {
            total_files: 1,
            dead_items,
            dead_percentage: 5.0,
            summary: "Test".to_string(),
        };
        let mut output = String::new();
        format_dead_code_section(&mut output, &dead_code).unwrap();
        assert!(output.contains("Function"));
        assert!(output.contains("Class"));
        assert!(output.contains("Variable"));
        assert!(output.contains("Import"));
        assert!(output.contains("UnreachableCode"));
    }

    #[test]
    fn test_satd_severity_variants_in_output() {
        let violations = vec![
            SatdViolation {
                file_path: "test.rs".to_string(),
                line_number: 1,
                violation_type: "FIXME".to_string(),
                message: "Critical".to_string(),
                severity: SatdSeverity::Critical,
            },
            SatdViolation {
                file_path: "test.rs".to_string(),
                line_number: 2,
                violation_type: "TODO".to_string(),
                message: "High".to_string(),
                severity: SatdSeverity::High,
            },
            SatdViolation {
                file_path: "test.rs".to_string(),
                line_number: 3,
                violation_type: "NOTE".to_string(),
                message: "Medium".to_string(),
                severity: SatdSeverity::Medium,
            },
            SatdViolation {
                file_path: "test.rs".to_string(),
                line_number: 4,
                violation_type: "XXX".to_string(),
                message: "Low".to_string(),
                severity: SatdSeverity::Low,
            },
        ];
        let satd = SatdAnalysisResult {
            total_files: 1,
            violations,
            summary: "Test".to_string(),
        };
        let mut output = String::new();
        format_satd_section(&mut output, &satd).unwrap();
        assert!(output.contains("Critical"));
        assert!(output.contains("High"));
        assert!(output.contains("Medium"));
        assert!(output.contains("Low"));
    }

    #[test]
    fn test_create_default_config_fields() {
        let config = make_default_config();
        assert_eq!(config.project_path.to_str().unwrap(), "/test/project");
        assert!(config.include_dead_code);
        assert!(config.include_complexity);
        assert!(!config.include_duplicates);
        assert!(!config.include_defects);
        assert!(!config.include_tdg);
        assert_eq!(config.top_files, 10);
    }
}