File Coverage

File:bin/fuzz-harness-generator
Coverage:74.8%

linestmtbrancondsubtimecode
1#!/usr/bin/env perl
2
3
6
6
6
10365
4
96
use strict;
4
6
6
6
8
4
104
use warnings;
5
6
6
6
6
1689
6
119
use App::Test::Generator;
7
6
6
6
12
6
8
use autodie qw(:all);
8
6
6
6
11999
5
168
use File::Temp;
9
6
6
6
1857
27155
10
use Getopt::Long qw(GetOptions);
10
6
6
6
1544
108660
1481
use Pod::Usage;
11
12 - 60
=head1 NAME

fuzz-harness-generator - Generate fuzzing + corpus-based test harnesses from test schemas

=head1 SYNOPSIS

  fuzz-harness-generator [-r] [-o output_file] input_file

  fuzz-harness-generator --dry-run input.yaml

=head1 DESCRIPTION

This tool generates a C<t/fuzz.t> test file that fuzzes and validates a target module's function or method,
using both randomized fuzz cases and static corpus
cases (Perl or YAML).

=head1 OPTIONS

=over 4

=item B<--help>

Show this help.

=item B<--input>

The input configuration file

=item B<--output>

The (optional) output file.

=item B<--dry-run>

Validate the input configuration and schema extraction without writing any output files or running tests.

=item B<--run>

Call C<prove> on the output file.

C<fuzz-harness-generator -r t/conf/data_text_append.conf> will, therefore, dynamically create and run tests on the C<append> method of L<Data::Text>

=item B<--version>

Prints the version of L<App::Test::Generator>

=back

=cut
61
62
6
414133
my $infile;
63my $outfile;
64
6
0
my $help;
65
6
0
my $run;
66
6
0
my $verbose;
67
6
0
my $version;
68
6
0
my $dry_run;
69
70
6
10
Getopt::Long::Configure('bundling');
71
72
6
85
GetOptions(
73        'help|h' => \$help,
74        'input|i=s' => \$infile,
75        'dry-run|n' => \$dry_run,
76        'output|o=s' => \$outfile,
77        'run|r' => \$run,
78        'verbose|v' => \$verbose,
79        'version|V' => \$version,
80) or pod2usage(2);
81
82
6
2651
pod2usage(-exitval => 0, -verbose => 1) if($help);
83
84
5
7
if($version) {
85
1
6
        print $App::Test::Generator::VERSION, "\n";
86
1
23
        exit 0;
87}
88
89
4
10
if($infile && @ARGV) {
90
0
0
        pod2usage('Specify input file either as argument or via --input, not both');
91}
92
93
4
7
$infile ||= shift @ARGV or pod2usage('No config file given');
94
95
4
7
if($dry_run && $run) {
96
0
0
        pod2usage('--dry-run cannot be used with --run');
97}
98
99
4
7
if ($dry_run && $outfile) {
100
1
6
        warn '--dry-run specified; --output will be ignored';
101}
102
103
4
161
if($verbose) {
104
0
0
        $ENV{'TEST_VERBOSE'} = 1;
105}
106
107
4
11
if($run && !$outfile) {
108
0
0
        my $fh;
109
0
0
        ($fh, $outfile) = File::Temp::tempfile();
110
0
0
        close $fh;
111
112
0
0
        App::Test::Generator::generate($infile, $outfile);
113
114
0
0
        exit system('prove', '-l', $outfile) >> 8;
115}
116
117
4
11
if ($dry_run) {
118
3
10
        my ($fh, $tmp) = File::Temp::tempfile();
119
3
675
        close $fh;
120
121        eval {
122
3
5
                App::Test::Generator::generate($infile, $tmp);
123
2
76
                1;
124
3
1162
        } or do {
125
1
342
                die "Dry-run failed for $infile: $@";
126        };
127
128
2
5
        unlink $tmp;
129
2
671
        print "Dry-run OK: $infile parsed and validated successfully\n";
130
2
64
        exit 0;
131} elsif($outfile && -e $outfile && !$run) {
132
0
0
        warn "Overwriting existing file: $outfile";
133}
134
135
1
7
App::Test::Generator::generate($infile, $outfile);
136
137
1
36
if($outfile) {
138
1
1
        chmod 0755, $outfile if($outfile =~ /\.(pl|cgi)$/);
139
1
2
        if($run) {
140
0
0
                system("prove -l $outfile");
141        }
142}
143
144
1
25
exit 0;