pmat 3.14.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)

        if let AnalyzeCommands::AssemblyScript {
            wasm_complexity,
            memory_analysis,
            security,
            ..
        } = cmd
        {
            assert!(wasm_complexity);
            assert!(memory_analysis);
            assert!(security);
        } else {
            panic!("Expected AssemblyScript command");
        }
    }

    #[test]
    fn test_webassembly_command_construction() {
        let cmd = AnalyzeCommands::WebAssembly {
            project_path: PathBuf::from("."),
            format: WasmOutputFormat::Json,
            include_binary: true,
            include_text: true,
            memory_analysis: true,
            security: true,
            complexity: true,
            output: None,
            perf: true,
            top_files: 5,
        };

        if let AnalyzeCommands::WebAssembly {
            include_binary,
            include_text,
            memory_analysis,
            security,
            complexity,
            ..
        } = cmd
        {
            assert!(include_binary);
            assert!(include_text);
            assert!(memory_analysis);
            assert!(security);
            assert!(complexity);
        } else {
            panic!("Expected WebAssembly command");
        }
    }

    #[test]
    fn test_clippy_command_construction() {
        let cmd = AnalyzeCommands::Clippy {
            project_path: PathBuf::from("."),
            confidence: "high".to_string(),
            dry_run: true,
            fix_codes: vec!["E0001".to_string(), "E0002".to_string()],
            output: None,
            perf: false,
        };

        if let AnalyzeCommands::Clippy {
            confidence,
            dry_run,
            fix_codes,
            ..
        } = cmd
        {
            assert_eq!(confidence, "high");
            assert!(dry_run);
            assert_eq!(fix_codes.len(), 2);
        } else {
            panic!("Expected Clippy command");
        }
    }

    #[test]
    fn test_defects_command_with_all_params() {
        let cmd = AnalyzeCommands::Defects {
            path: Some(PathBuf::from(".")),
            file: None,
            severity: Some("high".to_string()),
            format: DefectsOutputFormat::Json,
            output: Some(PathBuf::from("output.json")),
        };

        if let AnalyzeCommands::Defects {
            path,
            severity,
            format,
            output,
            ..
        } = cmd
        {
            assert_eq!(path, Some(PathBuf::from(".")));
            assert_eq!(severity, Some("high".to_string()));
            assert!(matches!(format, DefectsOutputFormat::Json));
            assert!(output.is_some());
        } else {
            panic!("Expected Defects command");
        }
    }

    // Semantic Analysis Tests (covering lines 1554-1696)

    #[test]
    fn test_cluster_method_variants() {
        let methods = [
            crate::cli::commands::ClusterMethod::Kmeans,
            crate::cli::commands::ClusterMethod::Hierarchical,
            crate::cli::commands::ClusterMethod::Dbscan,
        ];

        let method_strs = ["kmeans", "hierarchical", "dbscan"];

        for (method, expected) in methods.iter().zip(method_strs.iter()) {
            let method_str = match method {
                crate::cli::commands::ClusterMethod::Kmeans => "kmeans",
                crate::cli::commands::ClusterMethod::Hierarchical => "hierarchical",
                crate::cli::commands::ClusterMethod::Dbscan => "dbscan",
            };
            assert_eq!(method_str, *expected);
        }
    }

    #[test]
    fn test_cluster_command_construction() {
        let cmd = AnalyzeCommands::Cluster {
            method: crate::cli::commands::ClusterMethod::Kmeans,
            k: 5,
            language: Some("rust".to_string()),
            format: crate::cli::OutputFormat::Json,
        };

        if let AnalyzeCommands::Cluster {
            method,
            k,
            language,
            ..
        } = cmd
        {
            assert!(matches!(
                method,
                crate::cli::commands::ClusterMethod::Kmeans
            ));
            assert_eq!(k, 5);
            assert_eq!(language, Some("rust".to_string()));
        } else {
            panic!("Expected Cluster command");
        }
    }

    #[test]
    fn test_topics_command_construction() {
        let cmd = AnalyzeCommands::Topics {
            num_topics: 10,
            language: Some("python".to_string()),
            format: crate::cli::OutputFormat::Text,
        };

        if let AnalyzeCommands::Topics {
            num_topics,
            language,
            ..
        } = cmd
        {
            assert_eq!(num_topics, 10);
            assert_eq!(language, Some("python".to_string()));
        } else {
            panic!("Expected Topics command");
        }
    }

    // Coverage Improve Command Test (covering lines 238-261)

    #[test]
    fn test_coverage_improve_command_construction() {
        use crate::cli::handlers::coverage_improve_handler::CoverageImproveOutputFormat;

        let cmd = AnalyzeCommands::CoverageImprove {
            project_path: PathBuf::from("."),
            target: 85.0,
            max_iterations: 10,
            fast: true,
            mutation_threshold: 80.0,
            focus: vec!["src/".to_string()],
            exclude: vec!["tests/".to_string()],
            output: None,
            format: CoverageImproveOutputFormat::Summary,
        };

        if let AnalyzeCommands::CoverageImprove {
            target,
            max_iterations,
            fast,
            mutation_threshold,
            ..
        } = cmd
        {
            assert!((target - 85.0).abs() < f64::EPSILON);
            assert_eq!(max_iterations, 10);
            assert!(fast);
            assert!((mutation_threshold - 80.0).abs() < f64::EPSILON);
        } else {
            panic!("Expected CoverageImprove command");
        }
    }

    // Route Complexity Command Tests (deprecated path handling)

    #[test]
    fn test_complexity_command_deprecated_path_detection() {
        // Test that we can detect when deprecated project_path is used
        let has_deprecated = true; // Simulating deprecated path usage

        if has_deprecated {
            // This would trigger the deprecation warning in route_complexity_command
            // eprintln!("WARNING: --project-path is deprecated. Use --path instead.");
            assert!(true, "Deprecation warning should be shown");
        }
    }

    // SATD Config Construction Tests (covering lines 496-516)

    #[test]
    fn test_satd_config_construction() {
        use super::super::satd_handler::SatdAnalysisConfig;

        let config = SatdAnalysisConfig {
            path: PathBuf::from("."),
            format: SatdOutputFormat::Summary,
            severity: Some(SatdSeverity::High),
            critical_only: true,
            include_tests: false,
            strict: true,
            evolution: true,
            days: 60,
            metrics: true,
            output: None,
            top_files: 15,
            fail_on_violation: true,
            timeout: 120,
            include: vec!["src/**".to_string()],
            exclude: vec!["vendor/**".to_string()],
        };

        assert_eq!(config.path, PathBuf::from("."));
        assert!(config.critical_only);
        assert!(config.strict);
        assert!(config.evolution);
        assert_eq!(config.days, 60);
        assert!(config.metrics);
        assert_eq!(config.top_files, 15);
        assert!(config.fail_on_violation);
        assert_eq!(config.timeout, 120);
    }

    // TDG Config Construction Tests (covering lines 599-612)

    #[test]
    fn test_tdg_config_construction() {
        use super::super::new_tdg_handler::TdgAnalysisConfig;

        let config = TdgAnalysisConfig {
            path: PathBuf::from("/test/path"),
            threshold: Some(2.0),
            top_files: Some(20),
            format: TdgOutputFormat::Json,
            include_components: true,
            output: Some(PathBuf::from("output.json")),
            critical_only: true,
            verbose: true,
        };

        assert_eq!(config.path, PathBuf::from("/test/path"));
        assert_eq!(config.threshold, Some(2.0));
        assert_eq!(config.top_files, Some(20));
        assert!(config.include_components);
        assert!(config.critical_only);
        assert!(config.verbose);
    }

    // Duplicate Analysis Config Tests (covering lines 783-796)

    #[test]
    fn test_duplicate_analysis_config_construction() {
        use super::super::duplication_analysis::DuplicateAnalysisConfig;

        let config = DuplicateAnalysisConfig {
            project_path: PathBuf::from("."),
            detection_type: DuplicateType::Semantic,
            threshold: 0.90,
            min_lines: 10,
            max_tokens: 256,
            format: DuplicateOutputFormat::Json,
            perf: true,
            include: Some("**/*.rs".to_string()),
            exclude: Some("**/target/**".to_string()),
            output: None,
            top_files: 25,
        };

        assert_eq!(config.project_path, PathBuf::from("."));
        assert!(matches!(config.detection_type, DuplicateType::Semantic));
        assert!((config.threshold - 0.90).abs() < f64::EPSILON);
        assert_eq!(config.min_lines, 10);
        assert_eq!(config.max_tokens, 256);
        assert!(config.perf);
        assert_eq!(config.top_files, 25);
    }

    // Defect Prediction Config Tests (covering lines 819-836)

    #[test]
    fn test_defect_prediction_config_construction() {
        use super::super::defect_prediction_handler::DefectPredictionConfig;

        let config = DefectPredictionConfig {
            project_path: PathBuf::from("."),
            confidence_threshold: 0.6,
            min_lines: 15,
            include_low_confidence: true,
            format: DefectPredictionOutputFormat::Markdown,
            high_risk_only: false,
            include_recommendations: true,
            include: Some("src/**".to_string()),
            exclude: Some("tests/**".to_string()),
            output: Some(PathBuf::from("report.md")),
            perf: true,
            top_files: 5,
        };

        assert_eq!(config.project_path, PathBuf::from("."));
        assert!((config.confidence_threshold - 0.6).abs() < f32::EPSILON);
        assert_eq!(config.min_lines, 15);
        assert!(config.include_low_confidence);
        assert!(!config.high_risk_only);
        assert!(config.include_recommendations);
        assert!(config.perf);
    }

    // Provability Config Tests (covering lines 855-868)

    #[test]
    fn test_provability_config_construction() {
        use super::super::provability_handler::ProvabilityConfig;

        let config = ProvabilityConfig {
            project_path: PathBuf::from("/project"),
            functions: vec!["fn_a".to_string(), "fn_b".to_string()],
            analysis_depth: 15,
            format: ProvabilityOutputFormat::Detailed,
            high_confidence_only: true,
            include_evidence: true,
            output: None,
            top_files: 10,
        };

        assert_eq!(config.project_path, PathBuf::from("/project"));
        assert_eq!(config.functions.len(), 2);
        assert_eq!(config.analysis_depth, 15);
        assert!(config.high_confidence_only);
        assert!(config.include_evidence);
    }

    // Incremental Coverage Config Tests (covering lines 1003-1020)

    #[test]
    fn test_incremental_coverage_config_construction() {
        use super::super::incremental_coverage_handler::IncrementalCoverageConfig;

        let config = IncrementalCoverageConfig {
            project_path: PathBuf::from("."),
            base_branch: Some("main".to_string()),
            target_branch: Some("develop".to_string()),
            format: crate::cli::IncrementalCoverageOutputFormat::Json,
            coverage_threshold: 90.0,
            changed_files_only: false,
            detailed: true,
            output: Some(PathBuf::from("coverage.json")),
            perf: true,
            cache_dir: Some(PathBuf::from(".cache")),
            force_refresh: true,
            top_files: 100,
        };

        assert_eq!(config.base_branch, Some("main".to_string()));
        assert_eq!(config.target_branch, Some("develop".to_string()));
        assert!((config.coverage_threshold - 90.0).abs() < f64::EPSILON);
        assert!(!config.changed_files_only);
        assert!(config.detailed);
        assert!(config.force_refresh);
        assert_eq!(config.top_files, 100);
    }
}