App-Test-Generator
view release on metacpan or search on metacpan
# t/Analyzer-SideEffect.t already has a dedicated subtest proving
# performs_io/calls_external ignore keywords inside string literals
# and comments. mutates_self and mutates_globals had no equivalent
# protection: they matched against the raw $body instead of the
# string/comment-stripped $code_only, so a docstring merely
# mentioning "$self->{name} = ..." or "%ENV" falsely set those flags.
# This was a real bug (verified to misfire before the fix), not just
# a documentation gap, and has been corrected in the production code
# to match the same $code_only convention IO_PATTERN/EXEC_PATTERN
# already used.
# ==================================================================
subtest 'Analyzer::SideEffect::analyze - mutates_self ignores field-assignment text inside a string literal' => sub {
require App::Test::Generator::Analyzer::SideEffect;
my $analyser = App::Test::Generator::Analyzer::SideEffect->new;
my $report = $analyser->analyze({
body => q{sub foo { return "use $self->{name} = x in docs"; }},
});
is($report->{mutates_self}, 0,
'field-assignment text inside a string literal does not set mutates_self');
is_deeply($report->{mutation_fields}, [],
'no mutation_fields captured from the string literal');
done_testing();
};
subtest 'Analyzer::SideEffect::analyze - mutates_globals ignores global-variable text inside a string literal' => sub {
require App::Test::Generator::Analyzer::SideEffect;
my $analyser = App::Test::Generator::Analyzer::SideEffect->new;
my $report = $analyser->analyze({
body => q{sub foo { return "Set %ENV manually"; }},
});
is($report->{mutates_globals}, 0,
'global-variable text inside a string literal does not set mutates_globals');
done_testing();
};
# ==================================================================
# App::Test::Generator::CoverageGuidedFuzzer
#
# t/CoverageGuided_Fuzzer_unit.t already exhaustively covers new(),
# run(), corpus(), bugs(), save_corpus(), and load_corpus() against
# their documented API. The one POD-documented behaviour with no
# existing regression coverage is run()'s bug-filtering rule: a
# target_sub die is only recorded in bugs() when the input that
# triggered it is schema-valid (see run()'s POD Notes, added this
# session). Verify both halves of that rule with a deterministic
# seed: a target that always dies, fed integers constrained to
# [100,200], must record only in-range inputs as bugs even though
# some generated inputs (the int-boundary bias picks 0/-1/1) fall
# outside that range and are correctly discarded as expected failures.
# ==================================================================
subtest 'CoverageGuidedFuzzer::run - only records bugs for schema-valid input' => sub {
require App::Test::Generator::CoverageGuidedFuzzer;
my $fuzzer = App::Test::Generator::CoverageGuidedFuzzer->new(
schema => { input => { type => 'integer', min => 100, max => 200 } },
target_sub => sub { die "boom\n" },
iterations => 30,
seed => 42,
);
$fuzzer->run();
my @bugs = @{ $fuzzer->bugs() };
ok(scalar(@bugs) > 0, 'at least one in-range die was recorded as a bug');
ok(scalar(@bugs) < 30,
'at least one out-of-range die was correctly NOT recorded as a bug');
ok((!grep { $_->{input} < 100 || $_->{input} > 200 } @bugs),
'every recorded bug input falls within the schema-declared min/max');
done_testing();
};
# ==================================================================
# App::Test::Generator::Emitter::Perl
#
# TestStrategy.pm sets $plan{boundary_tests} when a method's schema
# carries non-empty _yamltest_hints, but _emit_method_tests() had no
# dispatch branch for that flag at all -- a $TEST_BOUNDARY constant
# was defined but never read. Methods planned for boundary testing
# silently got zero generated test code for it. Fixed by adding the
# dispatch line plus a new _emit_boundary_test() that emits one
# smoke-test block per boundary_values/invalid_inputs hint value.
# ==================================================================
subtest 'Emitter::Perl::emit - boundary_tests flag emits one block per hint value' => sub {
require App::Test::Generator::Emitter::Perl;
my $emitter = App::Test::Generator::Emitter::Perl->new(
schema => {
clamp => {
_yamltest_hints => {
boundary_values => [0, 255],
invalid_inputs => [-1],
},
},
},
plans => { clamp => { boundary_tests => 1 } },
package => 'My::Module',
);
my $code = $emitter->emit;
like($code, qr/\$obj->clamp\(0\)/, 'boundary value 0 emitted');
like($code, qr/\$obj->clamp\(255\)/, 'boundary value 255 emitted');
like($code, qr/\$obj->clamp\(-1\)/, 'invalid_inputs value -1 emitted');
done_testing();
};
subtest 'Emitter::Perl::emit - boundary_tests flag with no hint values emits nothing' => sub {
require App::Test::Generator::Emitter::Perl;
my $emitter = App::Test::Generator::Emitter::Perl->new(
schema => { clamp => { _yamltest_hints => {} } },
plans => { clamp => { boundary_tests => 1 } },
package => 'My::Module',
);
my $code = $emitter->emit;
unlike($code, qr/survives boundary input/,
( run in 0.998 second using v1.01-cache-2.11-cpan-f03e8824b8d )