App-Test-Generator
view release on metacpan or search on metacpan
0.25 Thu Jan 1 15:41:06 EST 2026
Ternary ? 1 : 0 return is taken to be an indicator of boolean returns
Now parses this pod to know that it's supposed to return a string:
Returns the sanitized HTML string
Use :: to call methods in non-oo modules, rather than ->
Flag when type is set to object by can is not set
0.24 Sun Dec 28 15:10:09 EST 2025
Return chances of false positive file path semantics
If the type of an variable can't be determined, guess at string, but lower the confidence level
Error Message Extraction:
Capture error messages from die/croak/confess
Use them to understand what makes input invalid die "Age must be positive" if $age <= 0;
Store that a negative/zero age is invalid
Use test of scalar(@_) to check for number of optional/mandatory args
Throw a float at a routine that only takes integers - it should error
Added example extraction
Parse POD for example calls and extract valid parameter combinations =head2 SYNOPSIS my $obj = Module->new(foo => 'bar', count => 5);
Store these as known-good test values
Corpus bool testing now uses ok rather than is
output:
type: number
value: 0
### `$module`
The name of the module (optional).
Using the reserved word `builtin` means you're testing a Perl builtin function.
If omitted, the generator will guess from the config filename:
`My-Widget.conf` -> `My::Widget`.
### `$function`
The function/method to test.
This defaults to `run`.
### `%new`
lib/App/Test/Generator.pm view on Meta::CPAN
output:
type: number
value: 0
=head3 C<$module>
The name of the module (optional).
Using the reserved word C<builtin> means you're testing a Perl builtin function.
If omitted, the generator will guess from the config filename:
C<My-Widget.conf> -> C<My::Widget>.
=head3 C<$function>
The function/method to test.
This defaults to C<run>.
=head3 C<%new>
lib/App/Test/Generator/SchemaExtractor.pm view on Meta::CPAN
$type = 'boolean' if $type =~ /^(true|false|bool)$/;
# Skip if it's just a number (like "returns 1")
$type = 'integer' if $type eq 'int';
$type = 'number' if $type =~ /^(num|float)$/;
$type = 'arrayref' if $type eq 'array';
$type = 'hashref' if $type eq 'hash';
if($type =~ /^\d+$/) {
if($type eq '1' || $type eq '0') {
# Try hard to guess if the result is a boolean
if($pod =~ /1 on success.+0 (on|if) /i) {
$type = 'boolean';
} elsif($pod =~ /return 0 .+ 1 on success/) {
$type = 'boolean';
} else {
$type = 'integer';
}
} else {
$type = 'integer';
}
lib/App/Test/Generator/SchemaExtractor.pm view on Meta::CPAN
my $params = $schema->{$mode};
foreach my $param (keys %$params) {
my $p = $params->{$param};
next unless(ref($p) eq 'HASH');
unless ($p->{type}) {
$self->_log(" DEBUG {$mode}{$param}: Setting to 'string' as a default");
$p->{'type'} = 'string';
$schema->{_confidence}{$mode}->{level} = 'low'; # Setting a default means it's a guess
}
}
}
# --------------------------------------------------
# _analyze_relationships
#
# Purpose: Detect inter-parameter relationships
# in a method's source code, including
# mutually exclusive parameters, required
lib/App/Test/Generator/SchemaExtractor.pm view on Meta::CPAN
# Process output
if($schema->{'output'} && (scalar(keys %{$schema->{'output'}}))) {
if((ref($schema->{output}{_error_handling}) eq 'HASH') && (scalar(keys %{$schema->{output}{_error_handling}}) == 0)) {
delete $schema->{output}{_error_handling};
}
$output->{'output'} = $schema->{'output'};
}
if($schema->{'output'}{'type'} && ($schema->{'output'}{'type'} eq 'scalar')) {
$schema->{'output'}{'type'} = 'string';
$schema->{_confidence}{output}->{level} = 'low'; # A guess
}
# Add 'new' field if object instantiation is needed
if ($schema->{new}) {
# TODO: consider allowing parent class packages up the ISA chain
if(ref($schema->{new}) || ($schema->{new} eq $package_name)) {
$output->{new} = $schema->{new} eq $package_name ? undef : $schema->{'new'};
} else {
$self->_log(" NEW: Don't use $schema->{new} for object insantiation");
delete $schema->{new};
t/40-more.t view on Meta::CPAN
# Verify the generated test has correct boolean values
my $content = slurp($bool_t);
like($content, qr/'test_nuls' => 0/, 'should convert "off" to 0');
like($content, qr/'test_undef' => 0/, 'should convert "no" to 0');
like($content, qr/'test_empty' => 0/, 'should convert "false" to 0');
like($content, qr/'dedup' => 1/, 'should convert "on" to 1');
unlink $bool_conf, $bool_t;
};
# Test module name guessing from filename
subtest 'module name guessing' => sub {
my $guess_conf = File::Spec->catfile($dir, 'My-Test-Module.yml');
write_yaml($guess_conf, {
function => 'test',
input => { test => { type => 'string' } },
output => { type => 'string' }
# No module specified - should guess from filename
});
pass('TODO When Legacy Files Removed');
# App::Test::Generator->generate($guess_conf, 't/guess_test.t');
# my $content = slurp('t/guess_test.t');
# like($content, qr/My::Test::Module/, 'should guess module name from filename');
# unlink $guess_conf, 't/guess_test.t';
unlink $guess_conf;
};
# Test YAML corpus validation
subtest 'YAML corpus validation' => sub {
my $corpus_conf = File::Spec->catfile($dir, 'corpus_test.yml');
my $corpus_t = File::Spec->catfile($dir, 'corpus_test.t');
my $bad_corpus = File::Spec->catfile($dir, 'bad_corpus.yml');
# Create invalid YAML corpus (non-array values)
write_yaml($bad_corpus, {
( run in 1.655 second using v1.01-cache-2.11-cpan-39bf76dae61 )