App-Test-Generator

 view release on metacpan or  search on metacpan

lib/App/Test/Generator/SchemaExtractor.pm  view on Meta::CPAN

#
# Notes:      Only fires when output type is
#             not yet set or is 'unknown'. Does not
#             override explicitly set types.
# --------------------------------------------------
sub _enhance_boolean_detection {
	my ($self, $output, $pod, $code, $method_name) = @_;

	my $boolean_score = 0;	# Track evidence for boolean return

	return unless !$output->{type} || $output->{type} eq 'unknown';

	# Look for stronger boolean indicators
	if ($pod && !$output->{type}) {
		# Common boolean return patterns in POD
		if ($pod =~ /returns?\s+(true|false|true|false|1|0)\s+(?:on|for|upon)\s+(success|failure|error|valid|invalid)/i) {
			$boolean_score += 30;
			$self->_log('  OUTPUT: Strong boolean indicator in POD (+30)');
		}

		# Check for method names that suggest boolean returns
		if ($pod =~ /(?:method|sub)\s+(\w+)/) {
			my $inferred_method_name = $1;
			if ($inferred_method_name =~ /^(is_|has_|can_|should_|contains_|exists_)/) {
				$boolean_score += 20;
				$self->_log("  OUTPUT: Inferred method name '$inferred_method_name' suggests boolean return (+20)");
			}
		}
	}

	# Analyze code for boolean patterns
	if ($code) {
		# Count boolean return idioms
		my $true_returns = () = $code =~ /return\s+1\s*;/g;
		my $false_returns = () = $code =~ /return\s+0\s*;/g;

		if ($true_returns + $false_returns >= 2) {
			$boolean_score += 40;
			$self->_log('  OUTPUT: Multiple 1/0 returns suggest boolean (+40)');
		} elsif ($true_returns + $false_returns == 1) {
			$boolean_score += 10;
			$self->_log('  OUTPUT: Single 1/0 return (+10)');
		}

		# Ternary operators that return booleans
		if ($code =~ /return\s+(?:\w+\s*[!=]=\s*\w+|\w+\s*>\s*\w+|\w+\s*<\s*\w+)\s*\?\s*(?:1|0)\s*:\s*(?:1|0)/) {
			$boolean_score += 25;
			$self->_log('  OUTPUT: Ternary with 1/0 suggests boolean (+25)');
		}

		# Check for common boolean method patterns
		if ($code =~ /return\s+[!\$\@\%]/) {
			# Returns negation or existence check
			$boolean_score += 15;
			$self->_log('  OUTPUT: Returns negation/existence check (+15)');
		}
	}

	# Check method name for boolean indicators
	if ($method_name) {
		if ($method_name =~ /^(is_|has_|can_|should_|contains_|exists_|check_|verify_|validate_)/) {
			$boolean_score += 25;
			$self->_log("  OUTPUT: Method name '$method_name' suggests boolean return (+25)");
		}
		if ($method_name =~ /_ok$/) {
			$boolean_score += 30;
			$self->_log("  OUTPUT: Method name '$method_name' ends with '_ok' (+30)");
		}
	}

	# Apply boolean type if we have strong evidence
	# Override weak type assignments (like 'array' from false positive)
	if($boolean_score >= $BOOLEAN_SCORE_THRESHOLD) {
		if (!$output->{type} || $output->{type} eq 'scalar' || $output->{type} eq 'array' || $output->{type} eq 'undef') {
			my $old_type = $output->{type} || 'none';
			$output->{type} = 'boolean';
			$self->_log("  OUTPUT: Boolean score $boolean_score >= $BOOLEAN_SCORE_THRESHOLD, setting type to boolean (was: $old_type)");
		}
	}
}

# --------------------------------------------------
# _detect_list_context
#
# Purpose:    Detect methods that return different
#             values depending on calling context
#             via wantarray, and methods that
#             return explicit lists.
#
# Entry:      $output - output hashref (modified
#                       in place).
#             $code   - method body source string.
#
# Exit:       Returns nothing. Modifies $output
#             in place, setting _context_aware,
#             _list_context, _scalar_context,
#             _list_return, and/or type keys.
#
# Side effects: Logs detections to stdout when
#               verbose is set.
# --------------------------------------------------
sub _detect_list_context {
	my ($self, $output, $code) = @_;
	return unless $code;

	# Check for wantarray usage
	if ($code =~ /wantarray/) {
		$output->{_context_aware} = 1;
		$self->_log('  OUTPUT: Method uses wantarray - context sensitive');

		# Debug: show what we're matching against
		if ($code =~ /(wantarray[^;]+;)/s) {
			$self->_log("  DEBUG wantarray line: $1");
		}

		if ($code =~ /wantarray\s*\?\s*\(([^)]+)\)\s*:\s*([^;]+)/s) {
			# Pattern 1: wantarray ? (list, items) : scalar_value (with parens)
			my ($list_return, $scalar_return) = ($1, $2);
			$self->_log("  DEBUG list (with parens): [$list_return], scalar: [$scalar_return]");

			$output->{_list_context} = $self->_infer_type_from_expression($list_return);



( run in 0.573 second using v1.01-cache-2.11-cpan-e1769b4cff6 )