App-Test-Generator
view release on metacpan or search on metacpan
t/Analyzer-Complexity.t view on Meta::CPAN
done_testing();
};
# ==================================================================
# analyze -- early_returns detection
# --------------------------------------------------
# The first return does not count as early.
# Each additional return beyond the first increments
# early_returns and cyclomatic_score.
# ==================================================================
subtest 'analyze: early_returns detection' => sub {
# Zero returns -- no early returns
my $report = _analyze_body('sub foo { my $x = 1; }');
is($report->{early_returns}, 0, 'no return: zero early returns');
# Exactly one return -- not early
$report = _analyze_body('sub foo { return 1; }');
is($report->{early_returns}, 0, 'single return: zero early returns');
# Two returns -- one early
$report = _analyze_body('sub foo { return undef unless $x; return 1; }');
is($report->{early_returns}, 1, 'two returns: one early return');
is($report->{cyclomatic_score},
$CYCLOMATIC_BASE + 1 + 1, # unless + one early return
'two returns: score incremented for early return');
# Three returns -- two early
$report = _analyze_body(
'sub foo { return 0 if $a; return undef if $b; return 1; }'
);
is($report->{early_returns}, 2, 'three returns: two early returns');
done_testing();
};
# ==================================================================
# analyze -- exception_paths detection
# --------------------------------------------------
# die, croak, confess, try, catch, eval each increment
# exception_paths and cyclomatic_score
# ==================================================================
subtest 'analyze: exception_paths detection' => sub {
# die
my $report = _analyze_body('die "error" unless $x;');
is($report->{exception_paths}, 1, 'die: one exception path');
is($report->{cyclomatic_score}, $CYCLOMATIC_BASE + 1 + 1,
'die + unless: correct score');
# croak
$report = _analyze_body('croak "bad input" unless defined $x;');
is($report->{exception_paths}, 1, 'croak: one exception path');
# confess
$report = _analyze_body('confess "deep error";');
is($report->{exception_paths}, 1, 'confess: one exception path');
# eval block
$report = _analyze_body('eval { do_something(); };');
is($report->{exception_paths}, 1, 'eval: one exception path');
# try/catch (e.g. Try::Tiny style)
$report = _analyze_body('try { do_something(); } catch { handle($_); };');
is($report->{exception_paths}, 2, 'try + catch: two exception paths');
# Multiple exception keywords are additive
$report = _analyze_body('eval { die "err"; }');
is($report->{exception_paths}, 2, 'eval + die: two exception paths');
done_testing();
};
# ==================================================================
# analyze -- nesting_depth detection
# --------------------------------------------------
# Maximum brace depth is tracked by naive counting.
# Note: braces in strings/regexes are also counted
# (documented limitation).
# ==================================================================
subtest 'analyze: nesting_depth detection' => sub {
# No braces -- depth is 0
my $report = _analyze_body('return 1;');
is($report->{nesting_depth}, 0, 'no braces: depth 0');
# Single level -- depth is 1
$report = _analyze_body('{ my $x = 1; }');
is($report->{nesting_depth}, 1, 'single brace pair: depth 1');
# Two levels -- depth is 2
$report = _analyze_body('{ if($x) { return 1; } }');
is($report->{nesting_depth}, 2, 'nested pair: depth 2');
# Three levels -- depth is 3
$report = _analyze_body('{ for(@a) { if($b) { do_thing(); } } }');
is($report->{nesting_depth}, 3, 'three-level nesting: depth 3');
# Sequential (not nested) pairs -- depth is still 1
$report = _analyze_body('{ my $x = 1; } { my $y = 2; }');
is($report->{nesting_depth}, 1,
'sequential pairs not nested: depth 1');
done_testing();
};
# ==================================================================
# analyze -- complexity_level classification
# --------------------------------------------------
# low: score <= LOW_THRESHOLD (3)
# moderate: score <= HIGH_THRESHOLD (7)
# high: score > HIGH_THRESHOLD (7)
# ==================================================================
subtest 'analyze: complexity_level classification' => sub {
# Score of 1 (base) -- low
my $report = _analyze_body('return 1;');
is($report->{complexity_level}, $LEVEL_LOW,
'score 1: low complexity');
# Score of 3 (base + 2 branches) -- still low (boundary)
$report = _analyze_body('if($a) { 1; } if($b) { 2; }');
is($report->{cyclomatic_score}, $CYCLOMATIC_BASE + 2,
'two ifs give score 3');
is($report->{complexity_level}, $LEVEL_LOW,
( run in 0.826 second using v1.01-cache-2.11-cpan-5fbc6bb55f2 )