lib/App/Test/Generator/Planner.pm

Structural Coverage (Approximate)

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

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;
    2: 
    3: use strict;
    4: use warnings;
    5: use Carp qw(croak);
    6: use Readonly;
    7: 
    8: use App::Test::Generator::TestStrategy;
    9: use App::Test::Generator::Planner::Isolation;
   10: use App::Test::Generator::Planner::Fixture;
   11: use App::Test::Generator::Planner::Mock;
   12: use App::Test::Generator::Planner::Grouping;
   13: 
   14: our $VERSION = '0.36';
   15: 
   16: # Accessor type strings used in plan_all() strategy mapping
   17: Readonly my $ACCESSOR_GET      => 'get';
   18: Readonly my $ACCESSOR_GETSET   => 'getset';
   19: Readonly my $ACCESSOR_INJECTOR => 'injector';
   20: 
   21: # Output type string for boolean detection
   22: Readonly my $OUTPUT_BOOLEAN => 'boolean';
   23: 
   24: =head1 VERSION
   25: 
   26: Version 0.36
   27: 
   28: =head2 new
   29: 
   30: Construct a new Planner instance.
   31: 
   32:     my $planner = App::Test::Generator::Planner->new(
   33:         schemas => \%schemas,
   34:         package => 'My::Module',
   35:     );
   36: 
   37: =head3 Arguments
   38: 
   39: =over 4
   40: 
   41: =item * C<schemas> - hashref of method name to schema hashref. Required.
   42: 
   43: =item * C<package> - the Perl package name of the module under test. Required.
   44: 
   45: =back
   46: 
   47: =head3 Returns
   48: 
   49: A blessed hashref.
   50: 
   51: =cut
   52: 
   53: sub new {
   54: 	my ($class, %args) = @_;
   55: 
   56: 	# schemas and package are required for meaningful planning
   57: 	croak 'schemas required' unless defined $args{schemas};
   58: 	croak 'package required' unless defined $args{package};
   59: 
   60: 	return bless {
   61: 		schemas => $args{schemas},
   62: 		package => $args{package},
   63: 	}, $class;
   64: }
   65: 
   66: =head2 plan_all
   67: 
   68: Generate a test plan for every method in the schema.
   69: 
   70:     my $plans = $planner->plan_all();
   71: 
   72: =head3 Arguments
   73: 
   74: None beyond C<$self>.
   75: 
   76: =head3 Returns
   77: 
   78: A hashref mapping method name to a plan hashref. Each plan hashref
   79: contains boolean flags such as C<getter_test>, C<getset_test>,
   80: C<object_injection_test>, and C<boolean_test> indicating which test
   81: types should be emitted for that method.
   82: 
   83: =cut
   84: 
   85: sub plan_all {
86 → 90 → 11586 → 90 → 0   86: 	my $self = $_[0];
   87: 	my %method_plan;
   88: 
   89: 	# Build a plan for each method in the schema
   90: 	foreach my $method (keys %{ $self->{schemas} }) {
   91: 		my $schema = $self->{schemas}{$method};
   92: 		my %plan;
   93: 
   94: 		# Map accessor type to the appropriate test flag
   95: 		if($schema->{accessor} && $schema->{accessor}->{type}) {

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

96: my $type = $schema->{accessor}->{type}; 97: if($type eq $ACCESSOR_GET) {

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

98: $plan{getter_test} = 1; 99: } elsif($type eq $ACCESSOR_GETSET) { 100: $plan{getset_test} = 1; 101: } elsif($type eq $ACCESSOR_INJECTOR) { 102: # Object injection requires a mock object in the test 103: $plan{object_injection_test} = 1; 104: } 105: } 106: 107: # Boolean output type requires a predicate test 108: if($schema->{output}->{type} && $schema->{output}->{type} eq $OUTPUT_BOOLEAN) {

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

109: $plan{boolean_test} = 1; 110: } 111: 112: $method_plan{$method} = \%plan; 113: } 114: 115 → 115 → 0 115: return \%method_plan; 116: } 117: 118: # -------------------------------------------------- 119: # build_plan 120: # 121: # Build a comprehensive test plan using 122: # all available planning subsystems: 123: # strategy, isolation, fixture, mock, 124: # and grouping. 125: # 126: # Entry: None beyond $self. 127: # Exit: Returns a hashref with keys: strategy, 128: # isolation, fixture, mock, groups. 129: # 130: # Notes: TODO: This method does not appear to be 131: # called anywhere. Consider removing it or 132: # integrating it into plan_all(). 133: # -------------------------------------------------- 134: sub build_plan { 135: my $self = $_[0]; 136: 137: # Generate the base strategy from the schema 138: my $strategy_engine = App::Test::Generator::TestStrategy->new( 139: schema => $self->{schemas} 140: ); 141: my $strategy = $strategy_engine->generate_plan(); 142: 143: # Apply isolation, fixture, mock and grouping layers 144: my $isolation = App::Test::Generator::Planner::Isolation->new()->plan( 145: $self->{schemas}, $strategy 146: ); 147: my $fixture = App::Test::Generator::Planner::Fixture->new()->plan( 148: $self->{schemas}, $isolation 149: ); 150: my $mock = App::Test::Generator::Planner::Mock->new()->plan($self->{schemas}); 151: my $groups = App::Test::Generator::Planner::Grouping->new()->plan($self->{schemas}); 152: 153: return { 154: strategy => $strategy, 155: isolation => $isolation, 156: fixture => $fixture, 157: mock => $mock, 158: groups => $groups, 159: }; 160: } 161: 162: =head1 AUTHOR 163: 164: Nigel Horne 165: 166: =cut 167: 168: 1;