App-Test-Generator
view release on metacpan or search on metacpan
bin/fuzz-harness-generator view on Meta::CPAN
# Build the .t header â include Test::Exception up front since
# lives_ok is always needed when there are tests to emit
my $t = <<'HEADER';
#!/usr/bin/env perl
# Auto-generated by fuzz-harness-generator --replay-corpus
# DO NOT EDIT - regenerate from corpus files instead
use strict;
use warnings;
use Test::More;
use Test::Exception;
HEADER
my $test_count = scalar @tests;
if($test_count == 0) {
$t .= "\nplan skip_all => 'No bugs recorded in corpus files';\n";
return $t;
}
# Emit one use statement per unique module (excluding the placeholder)
my %modules = map { $_->{'module'} => 1 } @tests;
for my $mod (sort keys %modules) {
next if $mod eq 'UNKNOWN::Module';
$t .= "use $mod;\n";
}
$t .= "\nplan tests => $test_count;\n\n";
for my $i (0 .. $#tests) {
my $test = $tests[$i];
my $n = $i + 1;
my $input = _format_input($test->{'input'});
my $label = "$test->{'method'} does not die on input from $test->{'file'}";
# Flatten and escape the original error for use as a comment
(my $orig_error = $test->{'error'} // '') =~ s/\n/ /g;
$orig_error =~ s/'/\\'/g;
$t .= "# Corpus bug: $orig_error\n";
$t .= "lives_ok { $test->{'module'}\->$test->{'method'}($input) }\n";
$t .= " '$label';\n\n";
}
return $t;
}
# --------------------------------------------------
# _format_input
#
# Purpose: Format a scalar input value as a Perl
# literal string suitable for embedding
# directly in generated test source code.
#
# Entry: $input - the input value to format.
# May be undef, a numeric string,
# or an arbitrary string.
#
# Exit: Returns a Perl literal string:
# 'undef' if $input is undef
# bare number if $input looks numeric
# single-quoted string otherwise, with
# backslashes and single quotes escaped.
#
# Side effects: None.
#
# Notes: Only scalar inputs are handled â corpus
# entries with arrayref or hashref inputs
# are not currently supported and will be
# formatted as a single-quoted string of
# the stringified reference, which will
# not reproduce the original input.
# --------------------------------------------------
sub _format_input {
my ($input) = @_;
return 'undef' unless defined $input;
# Emit bare numeric literals without quoting
return $input if $input =~ /^-?(?:\d+\.?\d*|\.\d+)$/;
# Escape backslashes first, then single quotes, to avoid
# double-escaping when both appear in the same string
(my $escaped = $input) =~ s/\\/\\\\/g;
$escaped =~ s/'/\\'/g;
return "'$escaped'";
}
# --------------------------------------------------
# _infer_module_from_schema
#
# Purpose: Attempt to determine the Perl module
# name for a given corpus method by
# locating and reading the companion YAML
# schema file that sits alongside the
# corpus directory.
#
# Entry: $corpus_file - path to the corpus JSON
# file, e.g.
# schemas/corpus/translate.json
# $method - the method name derived
# from the corpus filename,
# e.g. 'translate'
#
# Exit: Returns the module name string if found,
# or undef if no companion schema file
# exists or the schema contains no
# 'module:' line.
#
# Side effects: Reads schema files from disk.
#
# Notes: The corpus is expected to live one
# directory below the schemas directory,
# e.g. schemas/corpus/ alongside
# schemas/translate.yaml. This function
# walks up one level from the corpus
# directory to find the schema.
# Both .yaml and .yml extensions are
# tried, in that order.
# --------------------------------------------------
( run in 0.626 second using v1.01-cache-2.11-cpan-39bf76dae61 )