pmat 3.11.0

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

use super::*;

use std::fs;
use std::path::Path;
use tempfile::TempDir;

#[tokio::test]
async fn test_analyze_file_complexity_rust_simple_funcs() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("simple.rs");
    fs::write(&test_file, "fn hello() {\n    println!(\"hello\");\n}\n\nfn goodbye() {\n    println!(\"goodbye\");\n}\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert_eq!(metrics.function_count, 2);
    assert_eq!(metrics.high_complexity_functions, 0);
    assert!(metrics.avg_complexity >= 1.0);
    assert!(!metrics.function_names.is_empty());
}

#[tokio::test]
async fn test_analyze_file_complexity_rust_high_complexity() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("complex.rs");
    fs::write(
        &test_file,
        concat!(
            "fn very_complex(x: i32, y: i32) -> i32 {\n",
            "    if x > 0 {\n",
            "        if x > 10 {\n",
            "            if y > 0 {\n",
            "                match x {\n",
            "                    1 => { if y > 5 { return 1; } else { return 2; } }\n",
            "                    2 => { if y > 3 { return 3; } else { return 4; } }\n",
            "                    3 => return 5,\n",
            "                    4 => return 6,\n",
            "                    5 => return 7,\n",
            "                    _ => return 8,\n",
            "                }\n",
            "            } else { return -1; }\n",
            "        }\n",
            "    }\n",
            "    0\n",
            "}\n\n",
            "fn simple() -> i32 { 42 }\n",
        ),
    )
    .unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert_eq!(metrics.function_count, 2);
    assert!(metrics.avg_complexity > 1.0);
    assert!(metrics.function_names.contains(&"very_complex".to_string()));
    assert!(metrics.function_names.contains(&"simple".to_string()));
}

#[tokio::test]
async fn test_analyze_file_complexity_rust_no_functions() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("no_funcs.rs");
    fs::write(
        &test_file,
        "const FOO: i32 = 42;\nconst BAR: &str = \"hello\";\n",
    )
    .unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert_eq!(metrics.function_count, 0);
    assert_eq!(metrics.high_complexity_functions, 0);
    assert_eq!(metrics.avg_complexity, 0.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_rust_parse_error() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("bad.rs");
    fs::write(
        &test_file,
        "this is not valid rust code {{{}}}}}\nfn broken(\n",
    )
    .unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count == 0 || metrics.avg_complexity >= 0.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_python_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("test.py");
    fs::write(&test_file, concat!(
        "def hello():\n    print('hello')\n\n",
        "def complex_func(x):\n    if x > 0:\n        for i in range(x):\n            if i % 2 == 0:\n                print(i)\n    return x\n\n",
        "class MyClass:\n    def method(self):\n        pass\n"
    )).unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
    assert!(metrics.avg_complexity >= 1.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_js_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("app.js");
    fs::write(&test_file, concat!(
        "function greet(name) {\n    if (name) {\n        console.log('Hello ' + name);\n    }\n}\n\n",
        "const process = (data) => {\n    for (let i = 0; i < data.length; i++) {\n        console.log(data[i]);\n    }\n};\n\n",
        "function helper() { return 42; }\n"
    )).unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
    assert!(metrics.avg_complexity >= 1.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_ts_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("app.ts");
    fs::write(&test_file, "function greet(name: string): void {\n    console.log('Hello ' + name);\n}\n\nconst add = (a: number, b: number): number => {\n    return a + b;\n};\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 1);
}

#[tokio::test]
async fn test_analyze_file_complexity_ruby_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("app.rb");
    fs::write(&test_file, "def hello\n  puts 'hello'\nend\n\ndef process(data)\n  data.each do |item|\n    puts item\n  end\nend\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
    assert!(metrics.avg_complexity >= 1.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_go_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("main.go");
    fs::write(&test_file, "package main\n\nfunc main() {\n    fmt.Println(\"hello\")\n}\n\nfunc helper(x int) int {\n    if x > 0 {\n        return x * 2\n    }\n    return 0\n}\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
    assert!(metrics.avg_complexity >= 1.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_cs_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("Program.cs");
    fs::write(&test_file, "public class Program {\n    public static void Main(string[] args) {\n        Console.WriteLine(\"Hello\");\n    }\n\n    public static int Process(int x) {\n        if (x > 0) { return x * 2; }\n        return 0;\n    }\n}\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
}

#[tokio::test]
async fn test_analyze_file_complexity_kt_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("Main.kt");
    fs::write(&test_file, "fun main() {\n    println(\"Hello\")\n}\n\nfun process(x: Int): Int {\n    return if (x > 0) x * 2 else 0\n}\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
}

#[tokio::test]
async fn test_analyze_file_complexity_nonexistent_file() {
    let analyzer = SimpleDeepContext;
    let path = Path::new("/tmp/definitely_does_not_exist_abc123.rs");
    let metrics = analyzer.analyze_file_complexity(path).await.unwrap();
    assert_eq!(metrics.function_count, 0);
    assert_eq!(metrics.avg_complexity, 0.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_no_extension() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("Makefile");
    fs::write(&test_file, "all:\n\techo hello\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.avg_complexity >= 0.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_java_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("Main.java");
    fs::write(&test_file, "public class Main {\n    public static void main(String[] args) {\n        System.out.println(\"Hello\");\n    }\n\n    public int process(int x) {\n        if (x > 0) { return x * 2; }\n        return 0;\n    }\n}\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
}

#[tokio::test]
async fn test_analyze_file_complexity_c_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("main.c");
    fs::write(&test_file, "int main() {\n    printf(\"hello\\n\");\n    return 0;\n}\n\nint helper(int x) {\n    if (x > 0) { return x * 2; }\n    return 0;\n}\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
    assert!(metrics.avg_complexity >= 1.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_cpp_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("main.cpp");
    fs::write(&test_file, "#include <iostream>\n\nint main() {\n    std::cout << \"Hello\" << std::endl;\n    return 0;\n}\n\nvoid process(int x) {\n    if (x > 0) {\n        for (int i = 0; i < x; i++) { std::cout << i; }\n    }\n}\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
}

#[tokio::test]
async fn test_analyze_file_complexity_wat_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("module.wat");
    fs::write(&test_file, "(module\n  (func $add (param $a i32) (param $b i32) (result i32)\n    local.get $a\n    local.get $b\n    i32.add))\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.avg_complexity >= 0.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_wasm_binary() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("module.wasm");
    fs::write(&test_file, &[0x00, 0x61, 0x73, 0x6D]).unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.avg_complexity >= 0.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_empty_rust_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("empty.rs");
    fs::write(&test_file, "").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert_eq!(metrics.function_count, 0);
    assert_eq!(metrics.high_complexity_functions, 0);
    assert_eq!(metrics.avg_complexity, 0.0);
}

#[tokio::test]
async fn test_analyze_file_complexity_ruchy_file() {
    let analyzer = SimpleDeepContext;
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("app.ruchy");
    fs::write(&test_file, "def hello\n  puts 'hello'\nend\n\ndef process(data)\n  data.each do |item|\n    puts item\n  end\nend\n").unwrap();

    let metrics = analyzer.analyze_file_complexity(&test_file).await.unwrap();
    assert!(metrics.function_count >= 2);
}

#[tokio::test]
async fn test_analyze_multi_language_project() {
    let temp_dir = TempDir::new().unwrap();
    let src_dir = temp_dir.path().join("src");
    fs::create_dir_all(&src_dir).unwrap();

    fs::write(
        src_dir.join("lib.rs"),
        "fn compute(x: i32) -> i32 {\n    if x > 0 { x * 2 } else { -x }\n}\n",
    )
    .unwrap();
    fs::write(
        src_dir.join("utils.py"),
        "def calculate(x):\n    if x > 0:\n        return x * 2\n    return -x\n",
    )
    .unwrap();

    let analyzer = SimpleDeepContext::new();
    let config = SimpleAnalysisConfig {
        project_path: temp_dir.path().to_path_buf(),
        include_features: vec![],
        include_patterns: vec![],
        exclude_patterns: vec![],
        enable_verbose: false,
    };

    let report = analyzer.analyze(config).await.unwrap();
    assert_eq!(report.file_count, 2);
    assert!(report.complexity_metrics.total_functions >= 2);
    assert!(report.file_complexity_details.len() == 2);
}