debtmap 0.16.3

Code complexity and technical debt analyzer
Documentation
use debtmap::complexity::cyclomatic::{
    calculate_cyclomatic, calculate_cyclomatic_for_function, combine_cyclomatic,
};
use syn::{parse_quote, Block};

#[test]
fn test_calculate_cyclomatic_simple_block() {
    let block: Block = parse_quote! {{
        let x = 5;
        let y = 10;
        x + y
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 1,
        "Simple block should have cyclomatic complexity of 1"
    );
}

#[test]
fn test_calculate_cyclomatic_single_if() {
    let block: Block = parse_quote! {{
        if x > 0 {
            println!("positive");
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 2, "Single if statement adds 1 to complexity");
}

#[test]
fn test_calculate_cyclomatic_if_else() {
    let block: Block = parse_quote! {{
        if x > 0 {
            println!("positive");
        } else {
            println!("non-positive");
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 2,
        "If-else adds 1 to complexity (for the decision point)"
    );
}

#[test]
fn test_calculate_cyclomatic_nested_if() {
    let block: Block = parse_quote! {{
        if x > 0 {
            if y > 0 {
                println!("both positive");
            }
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 3,
        "Nested if statements each add 1 to complexity"
    );
}

#[test]
fn test_calculate_cyclomatic_match_expression() {
    let block: Block = parse_quote! {{
        match value {
            1 => println!("one"),
            2 => println!("two"),
            3 => println!("three"),
            _ => println!("other"),
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 4,
        "Match with 4 arms adds 3 to complexity (n-1)"
    );
}

#[test]
fn test_calculate_cyclomatic_match_with_guards() {
    let block: Block = parse_quote! {{
        match value {
            x if x > 10 => println!("large"),
            x if x > 5 => println!("medium"),
            x if x > 0 => println!("small"),
            _ => println!("non-positive"),
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 4,
        "Match with 4 arms (including guards) adds 3 to complexity"
    );
}

#[test]
fn test_calculate_cyclomatic_while_loop() {
    let block: Block = parse_quote! {{
        while x < 10 {
            x += 1;
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 2, "While loop adds 1 to complexity");
}

#[test]
fn test_calculate_cyclomatic_for_loop() {
    let block: Block = parse_quote! {{
        for i in 0..10 {
            println!("{}", i);
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 2, "For loop adds 1 to complexity");
}

#[test]
fn test_calculate_cyclomatic_loop() {
    let block: Block = parse_quote! {{
        loop {
            if done {
                break;
            }
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 3, "Loop adds 1 and nested if adds 1");
}

#[test]
fn test_calculate_cyclomatic_logical_and() {
    let block: Block = parse_quote! {{
        if x > 0 && y > 0 {
            println!("both positive");
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 3,
        "If with logical AND adds 2 to base (one for if, one for &&)"
    );
}

#[test]
fn test_calculate_cyclomatic_logical_or() {
    let block: Block = parse_quote! {{
        if x > 0 || y > 0 {
            println!("at least one positive");
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 3,
        "If with logical OR adds 2 to base (one for if, one for ||)"
    );
}

#[test]
fn test_calculate_cyclomatic_multiple_logical_operators() {
    let block: Block = parse_quote! {{
        if (x > 0 && y > 0) || z < 0 {
            println!("complex condition");
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 4,
        "If with multiple logical operators adds 3 to base (one for if, one for &&, one for ||)"
    );
}

#[test]
fn test_calculate_cyclomatic_try_expression() {
    let block: Block = parse_quote! {{
        let result = operation()?;
        result
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 2, "Try expression adds 1 to complexity");
}

#[test]
fn test_calculate_cyclomatic_multiple_try() {
    let block: Block = parse_quote! {{
        let a = operation1()?;
        let b = operation2()?;
        let c = operation3()?;
        a + b + c
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 4, "Each try expression adds 1 to complexity");
}

#[test]
fn test_calculate_cyclomatic_nested_match() {
    let block: Block = parse_quote! {{
        match outer {
            Some(inner) => {
                match inner {
                    1 => println!("one"),
                    2 => println!("two"),
                    _ => println!("other"),
                }
            }
            None => println!("none"),
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 4,
        "Outer match adds 1, inner match adds 2 (3 arms - 1)"
    );
}

#[test]
fn test_calculate_cyclomatic_complex_control_flow() {
    let block: Block = parse_quote! {{
        for i in 0..10 {
            if i % 2 == 0 {
                continue;
            }
            match i {
                1 | 3 | 5 => println!("small odd"),
                7 | 9 => println!("large odd"),
                _ => {}
            }
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 5,
        "For loop adds 1, if adds 1, match with 3 arms adds 2"
    );
}

#[test]
fn test_calculate_cyclomatic_for_function_no_params() {
    let base_complexity = 5;
    let param_count = 0;
    let result = calculate_cyclomatic_for_function(base_complexity, param_count);
    assert_eq!(
        result, 5,
        "Function with no parameters doesn't add to complexity"
    );
}

#[test]
fn test_calculate_cyclomatic_for_function_single_param() {
    let base_complexity = 5;
    let param_count = 1;
    let result = calculate_cyclomatic_for_function(base_complexity, param_count);
    assert_eq!(
        result, 5,
        "Function with one parameter doesn't add to complexity"
    );
}

#[test]
fn test_calculate_cyclomatic_for_function_multiple_params() {
    let base_complexity = 5;
    let param_count = 3;
    let result = calculate_cyclomatic_for_function(base_complexity, param_count);
    assert_eq!(result, 7, "Function with 3 parameters adds 2 to complexity");
}

#[test]
fn test_calculate_cyclomatic_for_function_many_params() {
    let base_complexity = 5;
    let param_count = 10;
    let result = calculate_cyclomatic_for_function(base_complexity, param_count);
    assert_eq!(
        result, 14,
        "Function with 10 parameters adds 9 to complexity"
    );
}

#[test]
fn test_combine_cyclomatic_empty() {
    let branches = vec![];
    assert_eq!(
        combine_cyclomatic(branches),
        1,
        "Empty branches should return base complexity of 1"
    );
}

#[test]
fn test_combine_cyclomatic_single_branch() {
    let branches = vec![2];
    assert_eq!(
        combine_cyclomatic(branches),
        3,
        "Single branch adds to base complexity"
    );
}

#[test]
fn test_combine_cyclomatic_multiple_branches() {
    let branches = vec![2, 3, 4];
    assert_eq!(
        combine_cyclomatic(branches),
        10,
        "Multiple branches sum up plus 1"
    );
}

#[test]
fn test_combine_cyclomatic_with_ones() {
    let branches = vec![1, 1, 1, 1];
    assert_eq!(
        combine_cyclomatic(branches),
        5,
        "Four branches of complexity 1 sum to 5"
    );
}

#[test]
fn test_calculate_cyclomatic_else_if_chain() {
    let block: Block = parse_quote! {{
        if x > 10 {
            println!("greater than 10");
        } else if x > 5 {
            println!("greater than 5");
        } else if x > 0 {
            println!("greater than 0");
        } else {
            println!("non-positive");
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(
        complexity, 4,
        "Else-if chain: 1 base + 3 conditions (if, else-if, else-if)"
    );
}

#[test]
fn test_calculate_cyclomatic_early_return() {
    let block: Block = parse_quote! {{
        if error {
            return Err("error");
        }
        if warning {
            return Ok(0);
        }
        Ok(42)
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 3, "Each if statement adds 1 to complexity");
}

#[test]
fn test_calculate_cyclomatic_break_continue() {
    let block: Block = parse_quote! {{
        for i in 0..10 {
            if i == 5 {
                break;
            }
            if i % 2 == 0 {
                continue;
            }
            println!("{}", i);
        }
    }};

    let complexity = calculate_cyclomatic(&block);
    assert_eq!(complexity, 4, "For loop adds 1, each if statement adds 1");
}