App-Test-Generator

 view release on metacpan or  search on metacpan

t/Analyzer-Complexity.t  view on Meta::CPAN

# ==================================================================
# analyze -- tolerates missing body key
# --------------------------------------------------
# analyze must not die when body key is absent or undef
# ==================================================================
subtest 'analyze: tolerates missing body key' => sub {
	my $analyser = App::Test::Generator::Analyzer::Complexity->new();

	# No body key at all -- defaults to empty string
	lives_ok { $analyser->analyze({}) }
		'analyze lives when body key absent';

	my $report = $analyser->analyze({});
	is($report->{cyclomatic_score}, $CYCLOMATIC_BASE,
		'absent body gives base score');
	is($report->{complexity_level}, $LEVEL_LOW,
		'absent body is low complexity');

	# Explicit undef body -- also defaults to empty string
	lives_ok { $analyser->analyze({ body => undef }) }
		'analyze lives when body is undef';

	$report = $analyser->analyze({ body => undef });
	is($report->{cyclomatic_score}, $CYCLOMATIC_BASE,
		'undef body gives base score');

	done_testing();
};

# ==================================================================
# analyze -- branch keywords are whole-word matched
# --------------------------------------------------
# Keywords embedded in identifiers must not trigger
# a branching point count
# ==================================================================
subtest 'analyze: branching keywords are whole-word matched' => sub {
	# 'iform' contains 'for' but should not count as a for loop
	my $report = _analyze_body('my $uniform = 1;');
	is($report->{branching_points}, 0,
		'"uniform" does not trigger for branching point');

	# 'notify' contains 'if' (as substring) but not as a word
	$report = _analyze_body('my $notify = 1;');
	is($report->{branching_points}, 0,
		'"notify" does not trigger if branching point');

	# 'foreacher' is not a keyword
	$report = _analyze_body('my $foreacher = 1;');
	is($report->{branching_points}, 0,
		'"foreacher" does not trigger foreach branching point');

	done_testing();
};

# ==================================================================
# analyze -- ? and other operators inside strings/comments
# must NOT inflate the cyclomatic score
# --------------------------------------------------
# Regression: the logical-operator count previously matched
# &&/||/? against the raw source body, so a literal "?" inside a
# string message (e.g. a prompt like "Are you sure?") or a
# keyword inside a comment was miscounted as a real decision point.
# ==================================================================
subtest 'analyze: ?/keywords inside strings or comments do not inflate score' => sub {
	# A bare string containing "?" but no real ternary operator
	my $report = _analyze_body('sub confirm { return "Are you sure?"; }');
	is($report->{cyclomatic_score}, $CYCLOMATIC_BASE,
		'"?" inside a string literal does not add to cyclomatic_score');

	# "if"/"die" appear only inside a comment, not as real code
	$report = _analyze_body(
		"sub get { # die if this fails, but it never does\n\treturn 1;\n}"
	);
	is($report->{branching_points}, 0, '"if" inside a comment does not count as a branching point');
	is($report->{exception_paths},  0, '"die" inside a comment does not count as an exception path');

	# A real ternary alongside a string containing "?" -- both must
	# be counted correctly: the real ternary detected, the string
	# content ignored
	$report = _analyze_body(
		q{sub ask { my $x = $a ? "Are you sure?" : "No way?"; return $x; }}
	);
	is($report->{cyclomatic_score}, $CYCLOMATIC_BASE + 1,
		'real ternary is still counted once despite "?" inside the surrounding strings');

	done_testing();
};

# ==================================================================
# analyze -- exception keywords are whole-word matched
# ==================================================================
subtest 'analyze: exception keywords are whole-word matched' => sub {
	# 'evaluate' contains 'eval' but should not count
	my $report = _analyze_body('my $evaluate = 1;');
	is($report->{exception_paths}, 0,
		'"evaluate" does not trigger eval exception path');

	# 'croaky' contains 'croak' but should not count
	$report = _analyze_body('my $croaky = 1;');
	is($report->{exception_paths}, 0,
		'"croaky" does not trigger croak exception path');

	done_testing();
};

done_testing();



( run in 1.613 second using v1.01-cache-2.11-cpan-6aa56a78535 )