lib/App/Test/Generator/Planner/Mock.pm

Structural Coverage (Approximate)

TER1 (Statement): 100.00%
TER2 (Branch): 100.00%
TER3 (LCSAJ): 100.0% (3/3)
Approximate LCSAJ segments: 7

LCSAJ Legend

Covered — this LCSAJ path was executed during testing.

Not covered — this LCSAJ path was never executed. These are the paths to focus on.

Multiple dots on a line indicate that multiple control-flow paths begin at that line. Hovering over any dot shows:

        start → end → jump
        

Uncovered paths show [NOT COVERED] in the tooltip.

Mutant Testing Legend

Survived (tests missed this) Killed (tests detected this) No mutation
    1: package App::Test::Generator::Planner::Mock;
    2: 
    3: use strict;
    4: use warnings;
    5: use Carp    qw(croak);
    6: 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: # Note: if a method does both, mock_system takes
   13: # precedence — see note in plan() below.
   14: # --------------------------------------------------
   15: Readonly my $MOCK_SYSTEM     => 'mock_system';
   16: Readonly my $MOCK_CAPTURE_IO => 'capture_io';
   17: 
   18: our $VERSION = '0.36';
   19: 
   20: =head1 VERSION
   21: 
   22: Version 0.36
   23: 
   24: =head1 DESCRIPTION
   25: 
   26: Plans mock strategy for each method that has external side effects,
   27: based on side effect analysis metadata in the schema. Methods that
   28: call external commands are assigned a system mock; methods that
   29: perform IO are assigned IO capture. Used by
   30: L<App::Test::Generator::Emitter::Perl> to generate appropriate mock
   31: setup code in the test output.
   32: 
   33: =head2 new
   34: 
   35: Construct a new Mock planner.
   36: 
   37:     my $planner = App::Test::Generator::Planner::Mock->new;
   38: 
   39: =head3 Arguments
   40: 
   41: None.
   42: 
   43: =head3 Returns
   44: 
   45: A blessed hashref.
   46: 
   47: =head3 API specification
   48: 
   49: =head4 input
   50: 
   51:     {}
   52: 
   53: =head4 output
   54: 
   55:     {
   56:         type => OBJECT,
   57:         isa  => 'App::Test::Generator::Planner::Mock',
   58:     }
   59: 
   60: =cut
   61: 
   62: sub new { bless {}, shift }
   63: 
   64: =head2 plan
   65: 
   66: Produce a mock plan for each method that requires external mocking,
   67: based on side effect analysis metadata in the schema.
   68: 
   69:     my $planner   = App::Test::Generator::Planner::Mock->new;
   70:     my $mock_plan = $planner->plan($schema);
   71: 
   72:     for my $method (keys %{$mock_plan}) {
   73:         printf "%s: %s\n", $method, $mock_plan->{$method};
   74:     }
   75: 
   76: =head3 Arguments
   77: 
   78: =over 4
   79: 
   80: =item * C<$schema>
   81: 
   82: A hashref of method schemas, each optionally containing a
   83: C<_analysis> key with a C<side_effects> sub-key as produced by
   84: L<App::Test::Generator::Analyzer::SideEffect>.
   85: 
   86: =back
   87: 
   88: =head3 Returns
   89: 
   90: A hashref mapping method names to mock strategy strings. Only methods
   91: that require mocking appear in the output — pure methods are omitted.
   92: 
   93: Currently supported strategy values are C<mock_system> and
   94: C<capture_io>. If a method both calls external commands and performs
   95: IO, C<mock_system> takes precedence. This is a known limitation and
   96: may be revised in a future version to support multiple strategies per
   97: method.
   98: 
   99: =head3 API specification
  100: 
  101: =head4 input
  102: 
  103:     {
  104:         self   => { type => OBJECT,  isa => 'App::Test::Generator::Planner::Mock' },
  105:         schema => { type => HASHREF },
  106:     }
  107: 
  108: =head4 output
  109: 
  110:     {
  111:         type => HASHREF,
  112:         keys => {
  113:             '*' => { type => SCALAR },
  114:         },
  115:     }
  116: 
  117: =cut
  118: 
  119: sub plan {
120 → 127 → 147120 → 127 → 0  120: 	my ($self, $schema) = @_;
  121: 
  122: 	# Validate that schema is a hashref before iterating
  123: 	croak 'schema must be a hashref' unless ref($schema) eq 'HASH';
  124: 
  125: 	my %mock_plan;
  126: 
  127: 	for my $method (keys %{$schema}) {
  128: 		# Extract side effect analysis if present —
  129: 		# default to empty hashref if not available
  130: 		my $effects = $schema->{$method}{_analysis}{side_effects} || {};
  131: 
  132: 		# --------------------------------------------------
  133: 		# Assign mock strategy based on detected side effects.
  134: 		# mock_system takes precedence over capture_io when
  135: 		# both are present — this is a known limitation.
  136: 		# TODO: consider supporting multiple strategies per
  137: 		# method as an arrayref in a future version.
  138: 		# --------------------------------------------------
  139: 		if($effects->{calls_external}) {

Mutants (Total: 1, Killed: 1, Survived: 0)

140: $mock_plan{$method} = $MOCK_SYSTEM; 141: } elsif($effects->{performs_io}) { 142: $mock_plan{$method} = $MOCK_CAPTURE_IO; 143: } 144: # Pure methods require no mocking — omit from plan 145: } 146: 147 → 147 → 0 147: return \%mock_plan; 148: } 149: 150: 1;