App-Test-Generator
view release on metacpan or search on metacpan
Revision history for App-Test-Generator
0.45 Mon Aug 10 11:17:51 AM EDT 2026
[Enhancements]
- Added --version option to bin/extract_schemas
- Changed close_stdin default from off to on
- Arrayref testing - add an undef entry in the middle of the array
- Hashref testing - added undef in a nested hash
- Add t/path.t: explicit CFG path-coverage tests for Model::Method,
BenchmarkGenerator, Analyzer::Complexity, Analyzer::SideEffect, and
Planner::Isolation. Each subtest exercises one uniquely identifiable
branch not covered by the module-specific unit tests. Paths added:
resolve_return_type() signal branches (legacy_typeÃ4 including the
value='object'/'self'/other/undef sub-paths, context_aware,
error_pattern) and tie-break cases (all-zeroâconstant, object=property
tieâobject); resolve_confidence() at all four threshold boundary
points (19âlow, 20âmedium, 39âmedium, 40âhigh); add_evidence()
weight=0 stored as 0 not default 1; _representative_value() all 15
branches (float/integer with no/min-only/max-only/both constraints,
boolean/arrayref/hashref/unknown types, undef spec); _quote_value()
all 4 paths; _build_call() all 5 call-syntax combinations;
generate() missing-key croaks, has_new+builtin skips constructor,
empty new_spec hashrefâno-arg constructor, empty transformsâdefault
variant; Complexity::analyze() given/when branch tokens, keyword
inside dquoted strings stripped, escaped dquote handled, unmatched
brace depth clamp, early_returns boundaries at 1 and 2 returns;
SideEffect::analyze() read/write IO keywords, self+globalsâimpure
purity path, false-positive guards for $self->{field}= inside strings
and comments; Planner::Isolation::plan() scalar-falsy time/network
values omit flags, hashref-truthy env propagates.
Dead code flagged: Model::Method::resolve_return_type() line 552 â
the `|| 'unknown'` fallback is unreachable because %score is always
initialised with 3 keys so $winner is always a non-empty string.
[Bug fixes]
- Fix SchemaExtractor::_detect_accessor_methods injecting the property
name as a spurious extra input parameter when a getter/setter's
argument is named differently from the stored property (e.g. sub
logdir { my $dir = shift; ... $self->{logdir} = $dir } generated
both 'dir' and 'logdir' as position-0 parameters). The position
assignment now targets the existing input key rather than creating a
new key named after the property.
- Fix t/type_params.t dying with "Your vendor has not defined
BSD::Resource macro RLIMIT_AS" on platforms where BSD::Resource is
installed but does not export RLIMIT_AS (e.g. some BSDs and macOS
builds). The RLIMIT_AS() call is now wrapped in eval; if it croaks,
the test is skipped with an explanatory message instead of aborting.
Also fix "Bad plan. You planned 0 tests but ran 1" on the same
platform: the BEGIN { use_ok(...) } block fired test #1 before the
plan(skip_all => ...) call declared 0 tests. Replaced with a plain
use so no test runs before the skip checks.
- Fix _compile_signature_isolated() calling decode_json() on empty or
non-JSON output when the child subprocess is killed by the kernel
OOM killer (SIGKILL) before it can write to stdout or stderr: the
caller now guards for empty stdout and wraps decode_json() in eval,
so a silent child crash degrades gracefully (return undef â fall
back to heuristics) rather than croaking with "malformed JSON
string" and propagating through the Test::Builder subtest boundary
to kill the test process with exit 255.
- Fix test-generator-index coverage trend chart always ending one commit
behind the current run: the coverage snapshot is written to the archive
AFTER the HTML is generated, so the current commit's point was never in
the trend data â the last visible point was the previous commit's
(which could show anomalously low coverage, e.g. a partial Devel::Cover
run, making the trend appear to crash at the right-hand edge). The
current run is now appended as the final trend point using the same
arithmetic mean of per-file percentages as the archive-based points,
guarded by a SHA check to avoid duplication if the snapshot was somehow
already committed before HTML generation.
- Fix test-generator-index delta column showing the wrong value for
blib/-instrumented modules (the common case under 'cover -test').
%deltas was keyed by the normalised lib/ path ($display_file) but
the lookup used the raw Devel::Cover blib/ key ($file), so the
exists() check always failed and the code silently fell through to
a sparkline-based fallback. The fallback computes delta from the
last two sparkline points; when the most-recent archive entry
contained a 0.0 (from an older undef-percentage snapshot), the
fallback computed 0.0 - 95.6 = -95.6%, displaying "â¼ 95.6%" â the
same number as the actual coverage. Fixed by: (1) using $display_file
(already normalised to lib/) for both the %deltas lookup and the
$prev_data lookup; (2) fixing the sparkline key-resolution order to
avoid prepending "blib/" to a key already starting with "blib/"
(which produced a double-prefix "blib/blib/..." path that never
matched anything in historical snapshots).
- Fix t/fuzz.t invoking bin/fuzz-harness-generator via the shebang
(#!/usr/bin/env perl) rather than $^X: on CPAN smokers where $PATH
- Fix SchemaExtractor _infer_type_from_expression() and
_parse_modern_signature() using hand-rolled brace/bracket depth
counters to split comma-separated lists, which mishandled nested
brackets (e.g. a signature default value containing a hashref
literal could be split on the comma inside the hashref); both now
use Text::Balanced::extract_bracketed() to skip over nested
structures correctly.
- Fix Mutator.pm's _dedup_mutants(), _is_redundant_mutation(), and
apply_mutant() reaching into Mutant objects via direct hash access
(e.g. $m->{line}), bypassing the class's own accessor methods; all
six call sites now use the Mutant accessors ($m->line, $m->original,
$m->transform, etc).
- Fix Devel::App::Test::Generator::LCSAJ::Runtime's DB::DB debugger
hook calling abs_path() (a filesystem stat) on every single
statement executed under the debugger; resolved paths are now
memoised per raw $file in %NORM_CACHE.
- Fix lib/App/Test/Generator/Sample/Module.pm declaring
package Test::App::Generator::Sample::Module (reversed word order)
instead of App::Test::Generator::Sample::Module, so the package
name did not match its location under
lib/App/Test/Generator/Sample/; renamed throughout the file.
- Fix Generator.pm SYNOPSIS extract-schemas example passing two
positional arguments (bin/extract-schemas lib/Sample/Module.pm)
instead of one, referencing a nonexistent lib/Sample/Module.pm path,
and naming the generated schema file schemas/greet.yaml when
extract-schemas actually writes schemas/greet.yml; corrected all
three.
- Fix lib/App/Test/Generator/Exporter/YAML.pm having no package
statement (so it loaded into main::), no input validation before
YAML::XS::DumpFile(), and no test coverage; added the package
statement, Params::Validate::Strict validation of plan/file
(rejecting non-hashref plans and missing/empty file paths), and
t/Exporter-YAML.t.
- Fix generate()'s _assert_identifier() check on the function name
rejecting fully-qualified sub names such as DB::DB, breaking
t/app.t's self-test sweep against
Devel::App::Test::Generator::LCSAJ::Runtime.pm (DB::DB is a Perl
debugger hook, always installed into the DB:: package regardless
of its source package); the function-name check now allows "::"
separators, same as the existing module-name check.
- Fix SchemaExtractor's heuristic numeric-type inference missing
parameters that are only ever validated via an explicit
looks_like_number($param) call rather than direct arithmetic
adjacency (e.g. a parameter used as looks_like_number($b) in a
guard clause and only later folded into arithmetic via
$a + ($b // 0), where $b never sits next to an operator itself);
such parameters fell back to type 'string', so fuzz-generated
non-numeric inputs caused generated tests to fail against code
that legitimately dies on non-numeric input. An explicit
looks_like_number($param) call in the source is now treated as a
direct numeric-type assertion, checked before the existing
arithmetic-operator and comparison heuristics.
- Fix _compile_signature_isolated()'s "fast path" Safe compartment,
tried before falling back to the subprocess unconditionally;
Type::Params/Types::Common pull in XS modules and Safe cannot host
XS/dynamic loading, so the compartment never succeeded for any real
signature_for() declaration and was dead code giving a false
impression of sandboxing. Removed; the subprocess path (gated on
allow_signature_exec => 1) is now the only path.
- Fix Generator.pm splicing module/function/transform/field names
unescaped into generated test source; added _assert_identifier()
and applied it before every such splice point so a name that is
not identifier-shaped now croaks instead of producing a test file
with injected code.
- Fix extract-schemas2 calling Planner->new without the required
package argument, crashing on every invocation; package is now
passed through from the extracted schema.
- Fix Template.pm _dedup_cases() always being a no-op: a return
inside the eval{} block returned from the eval, not from
_dedup_cases, so the deduplicated result was discarded and the
unduplicated $cases was always returned to the caller.
- Fix SchemaExtractor _detect_dependencies() relationship detection
losing pos() state on a shared $code string across nested global
matches; affected loops now operate on independent copies/resets.
- Fix SchemaExtractor numeric boundary-value hints double-counting
values already present from a previous hint pass; boundary values
are now added through a seen-value set, so re-running hint
generation on the same schema no longer duplicates values.
- Fix SchemaExtractor _detect_external_object_dependency() not
resetting pos($method_body) before its global match, so a prior
match elsewhere on the same string could cause this detector to
start scanning mid-string and miss leading dependencies; pos() is
now explicitly reset to 0 first.
- Fix CoverageGuidedFuzzer calling target_sub with no time bound, so
a target that hangs (e.g. on an unexpected infinite-loop input)
hung the whole fuzz run; calls are now wrapped in alarm()-based
timeout (default 5s, configurable via timeout => N, 0 disables).
- Fix LCSAJ.pm's CFG builder connecting every branch point only to a
newly-created true-block successor, leaving the false-arm block
disconnected from the frontier and silently dropped as an empty
leaf with no lines or edges; both true and false successors are
now wired into the frontier so subsequent statements are recorded
against both arms.
- Fix Mutator generate_mutants() never calling each mutation
strategy's applies_to() pre-filter before mutate(), and never
populating the context/line_content fields on the Mutant objects
it constructs; both are now wired through.
- Fix Analyzer::SideEffect.pm and Analyzer::Complexity.pm counting
IO/exec keywords, branch/logic/exception keywords, and the
literal ? character when they merely appeared inside a string
literal or comment (e.g. "Are you sure?" or a # comment containing
"die"); source is now stripped of string and comment content
before these keyword/operator counts are taken.
- Fix Analyzer::Return.pm's \$self(?!->) returns_self pattern
matching the \$self prefix of any longer variable name (e.g.
\$self_backup, \$selfish); added a \b word boundary. Also fixed
all three return-pattern matches running as a single non-/g match,
so a method with several qualifying return statements only ever
contributed one evidence entry instead of one per occurrence.
- Fix Mutation::BooleanNegation and Mutation::ReturnUndef mutating
only the first PPI token of a multi-token return expression (e.g.
$self->{value}), since $ret->schild(1) captures just the leading
Symbol token of a chained/dereferencing expression; this produced
broken mutants like 'return !($self)->{value};' and
'return undef->{value};' that die at runtime rather than testing
the intended boolean/undef substitution. Both now resolve the
full expression span (up to a trailing postfix conditional/loop
modifier or the statement terminator) and wrap/replace it as a
whole.
- Fix SchemaExtractor _analyze_relationships() extracting parameter
names with a hardcoded my (...) = @_ regex only, so shift-style
( run in 0.534 second using v1.01-cache-2.11-cpan-788537b7465 )