| File: | blib/lib/App/Test/Generator/Analyzer/Return.pm |
| Coverage: | 82.2% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | package App::Test::Generator::Analyzer::Return; | |||||
| 2 | ||||||
| 3 | 24 24 24 | 66822 17 302 | use strict; | |||
| 4 | 24 24 24 | 33 42 476 | use warnings; | |||
| 5 | 24 24 24 | 42 27 429 | use Carp qw(croak); | |||
| 6 | 24 24 24 | 34 22 4719 | use Readonly; | |||
| 7 | ||||||
| 8 | # -------------------------------------------------- | |||||
| 9 | # Evidence weights for each detected return pattern. | |||||
| 10 | # Higher weights indicate stronger signals that the | |||||
| 11 | # detected pattern is the primary return behaviour. | |||||
| 12 | # -------------------------------------------------- | |||||
| 13 | Readonly my $WEIGHT_RETURNS_PROPERTY => 20; | |||||
| 14 | Readonly my $WEIGHT_RETURNS_SELF => 15; | |||||
| 15 | Readonly my $WEIGHT_RETURNS_CONSTANT => 10; | |||||
| 16 | ||||||
| 17 | our $VERSION = '0.36'; | |||||
| 18 | ||||||
| 19 - 58 | =head1 VERSION
Version 0.36
=head1 DESCRIPTION
Analyses the source code of a method and adds evidence to a
L<App::Test::Generator::Model::Method> object describing what kind of
value the method returns. Evidence is used downstream by
L<App::Test::Generator::Model::Method/resolve_return_type> to determine
the most likely return type.
=head2 new
Construct a new Return analyser.
my $analyser = App::Test::Generator::Analyzer::Return->new;
=head3 Arguments
None.
=head3 Returns
A blessed hashref.
=head3 API specification
=head4 input
{}
=head4 output
{
type => OBJECT,
isa => 'App::Test::Generator::Analyzer::Return',
}
=cut | |||||
| 59 | ||||||
| 60 | sub new { | |||||
| 61 | 290 | 101855 | my $class = $_[0]; | |||
| 62 | 290 | 334 | return bless {}, $class; | |||
| 63 | } | |||||
| 64 | ||||||
| 65 - 113 | =head2 analyze
Scan the source code of a method for return patterns and add weighted
evidence to the method object. Detects three patterns: returning a
property from C<$self>, returning C<$self> itself, and returning a
constant literal value.
my $analyser = App::Test::Generator::Analyzer::Return->new;
$analyser->analyze($method);
my $type = $method->resolve_return_type;
=head3 Arguments
=over 4
=item * C<$method>
An L<App::Test::Generator::Model::Method> object. Evidence is added
to this object in place via C<add_evidence>.
=back
=head3 Returns
Nothing (undef). All results are communicated via side effects on the
C<$method> object.
=head3 Notes
The interface of this analyser differs from
L<App::Test::Generator::Analyzer::ReturnMeta>, which operates on a raw
schema hashref. This analyser operates on a C<Model::Method> object
directly.
=head3 API specification
=head4 input
{
self => { type => OBJECT, isa => 'App::Test::Generator::Analyzer::Return' },
method => { type => OBJECT, isa => 'App::Test::Generator::Model::Method' },
}
=head4 output
{ type => UNDEF }
=cut | |||||
| 114 | ||||||
| 115 | sub analyze { | |||||
| 116 | 288 | 289 | my ($self, $method) = @_; | |||
| 117 | ||||||
| 118 | # Accept either a Model::Method object or a raw hashref, | |||||
| 119 | # since callers in SchemaExtractor pass raw hashrefs | |||||
| 120 | my $source = ref($method) && $method->can('source') | |||||
| 121 | ? $method->source() | |||||
| 122 | 288 | 914 | : ($method->{source} // $method->{body} // ''); | |||
| 123 | ||||||
| 124 | # -------------------------------------------------- | |||||
| 125 | # Detect: return $self->{property} | |||||
| 126 | # Negative lookahead ensures this does not also match | |||||
| 127 | # plain return $self (handled separately below) | |||||
| 128 | # -------------------------------------------------- | |||||
| 129 | 288 | 531 | if($source =~ /return\s+\$self->\{(\w+)\}/) { | |||
| 130 | 30 | 62 | $method->add_evidence( | |||
| 131 | category => 'return', | |||||
| 132 | signal => 'returns_property', | |||||
| 133 | value => $1, | |||||
| 134 | weight => $WEIGHT_RETURNS_PROPERTY, | |||||
| 135 | ); | |||||
| 136 | } | |||||
| 137 | ||||||
| 138 | # -------------------------------------------------- | |||||
| 139 | # Detect: return $self | |||||
| 140 | # Use negative lookahead to avoid matching | |||||
| 141 | # return $self->{...} which is a property return | |||||
| 142 | # -------------------------------------------------- | |||||
| 143 | 288 | 490 | if($source =~ /return\s+\$self(?!->)/) { | |||
| 144 | 11 | 25 | $method->add_evidence( | |||
| 145 | category => 'return', | |||||
| 146 | signal => 'returns_self', | |||||
| 147 | weight => $WEIGHT_RETURNS_SELF, | |||||
| 148 | ); | |||||
| 149 | } | |||||
| 150 | ||||||
| 151 | # -------------------------------------------------- | |||||
| 152 | # Detect: return of a constant literal â quoted string, | |||||
| 153 | # numeric literal, or undef. All indicate the method | |||||
| 154 | # returns a fixed value rather than a computed state. | |||||
| 155 | # -------------------------------------------------- | |||||
| 156 | 288 | 546 | if($source =~ /return\s+(?:['"\d]|undef\b)/) { | |||
| 157 | 155 | 258 | $method->add_evidence( | |||
| 158 | category => 'return', | |||||
| 159 | signal => 'returns_constant', | |||||
| 160 | weight => $WEIGHT_RETURNS_CONSTANT, | |||||
| 161 | ); | |||||
| 162 | } | |||||
| 163 | ||||||
| 164 | 288 | 305 | return; | |||
| 165 | } | |||||
| 166 | ||||||
| 167 - 175 | =head1 LICENCE AND COPYRIGHT Copyright 2025-2026 Nigel Horne. Usage is subject to GPL2 licence terms. If you use it, please let me know. =cut | |||||
| 176 | ||||||
| 177 | 1; | |||||