File Coverage

File:blib/lib/App/Test/Generator/Planner/Mock.pm
Coverage:100.0%

linestmtbrancondsubtimecode
1package App::Test::Generator::Planner::Mock;
2
3
11
11
11
64883
10
128
use strict;
4
11
11
11
19
4
185
use warnings;
5
11
11
11
17
8
203
use Carp    qw(croak);
6
11
11
11
213
1637
1224
use Readonly;
7
8# --------------------------------------------------
9# Mock strategy labels written to the plan output.
10# mock_system is used when a method calls external
11# commands; capture_io when it performs IO operations.
12# A method needing both gets an arrayref of both labels
13# — see note in plan() below.
14# --------------------------------------------------
15Readonly my $MOCK_SYSTEM     => 'mock_system';
16Readonly my $MOCK_CAPTURE_IO => 'capture_io';
17
18our $VERSION = '0.41';
19
20 - 60
=head1 VERSION

Version 0.41

=head1 DESCRIPTION

Plans mock strategy for each method that has external side effects,
based on side effect analysis metadata in the schema. Methods that
call external commands are assigned a system mock; methods that
perform IO are assigned IO capture. Used by
L<App::Test::Generator::Emitter::Perl> to generate appropriate mock
setup code in the test output.

=head2 new

Construct a new Mock planner.

    my $planner = App::Test::Generator::Planner::Mock->new;

=head3 Arguments

None.

=head3 Returns

A blessed hashref.

=head3 API specification

=head4 input

    {}

=head4 output

    {
        type => OBJECT,
        isa  => 'App::Test::Generator::Planner::Mock',
    }

=cut
61
62
17
96503
sub new { bless {}, shift }
63
64 - 117
=head2 plan

Produce a mock plan for each method that requires external mocking,
based on side effect analysis metadata in the schema.

    my $planner   = App::Test::Generator::Planner::Mock->new;
    my $mock_plan = $planner->plan($schema);

    for my $method (keys %{$mock_plan}) {
        printf "%s: %s\n", $method, $mock_plan->{$method};
    }

=head3 Arguments

=over 4

=item * C<$schema>

A hashref of method schemas, each optionally containing a
C<_analysis> key with a C<side_effects> sub-key as produced by
L<App::Test::Generator::Analyzer::SideEffect>.

=back

=head3 Returns

A hashref mapping method names to a mock strategy. Only methods that
require mocking appear in the output — pure methods are omitted.

Currently supported strategy values are C<mock_system> and
C<capture_io>. A method needing only one of these gets that value as
a plain scalar string. A method that both calls external commands and
performs IO needs both mocks applied, so it gets an arrayref
C<[mock_system, capture_io]> instead of a single string.

=head3 API specification

=head4 input

    {
        self   => { type => OBJECT,  isa => 'App::Test::Generator::Planner::Mock' },
        schema => { type => HASHREF },
    }

=head4 output

    {
        type => HASHREF,
        keys => {
            '*' => { type => 'scalar | arrayref' },
        },
    }

=cut
118
119sub plan {
120
18
2294
        my ($self, $schema) = @_;
121
122        # Validate that schema is a hashref before iterating
123
18
44
        croak 'schema must be a hashref' unless ref($schema) eq 'HASH';
124
125
16
11
        my %mock_plan;
126
127
16
16
12
20
        for my $method (keys %{$schema}) {
128                # Extract side effect analysis if present —
129                # default to empty hashref if not available
130
18
30
                my $effects = $schema->{$method}{_analysis}{side_effects} || {};
131
132                # --------------------------------------------------
133                # Assign mock strategy based on detected side effects.
134                # A method needing both gets an arrayref of both labels
135                # rather than silently dropping one of them.
136                # --------------------------------------------------
137
18
51
                if($effects->{calls_external} && $effects->{performs_io}) {
138
4
9
                        $mock_plan{$method} = [$MOCK_SYSTEM, $MOCK_CAPTURE_IO];
139                } elsif($effects->{calls_external}) {
140
4
9
                        $mock_plan{$method} = $MOCK_SYSTEM;
141                } elsif($effects->{performs_io}) {
142
4
7
                        $mock_plan{$method} = $MOCK_CAPTURE_IO;
143                }
144                # Pure methods require no mocking — omit from plan
145        }
146
147
16
51
        return \%mock_plan;
148}
149
1501;