#!/usr/bin/env perl

use strict;
use warnings;

use App::Test::Generator;
use autodie qw(:all);
use File::Temp;
use Getopt::Long qw(GetOptions);
use Pod::Usage;

=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

my $infile;
my $outfile;
my $help;
my $run;
my $verbose;
my $version;
my $dry_run;

Getopt::Long::Configure('bundling');

GetOptions(
	'help|h' => \$help,
	'input|i=s' => \$infile,
	'dry-run|n' => \$dry_run,
	'output|o=s' => \$outfile,
	'run|r' => \$run,
	'verbose|v' => \$verbose,
	'version|V' => \$version,
) or pod2usage(2);

pod2usage(-exitval => 0, -verbose => 1) if($help);

if($version) {
	print $App::Test::Generator::VERSION, "\n";
	exit 0;
}

if($infile && @ARGV) {
	pod2usage('Specify input file either as argument or via --input, not both');
}

$infile ||= shift @ARGV or pod2usage('No config file given');

if($dry_run && $run) {
	pod2usage('--dry-run cannot be used with --run');
}

if ($dry_run && $outfile) {
	warn '--dry-run specified; --output will be ignored';
}

if($verbose) {
	$ENV{'TEST_VERBOSE'} = 1;
}

if($run && !$outfile) {
	my $fh;
	($fh, $outfile) = File::Temp::tempfile();
	close $fh;

	App::Test::Generator::generate($infile, $outfile);

	exit system('prove', '-l', $outfile) >> 8;
}

if ($dry_run) {
	my ($fh, $tmp) = File::Temp::tempfile();
	close $fh;

	eval {
		App::Test::Generator::generate($infile, $tmp);
		1;
	} or do {
		die "Dry-run failed for $infile: $@";
	};

	unlink $tmp;
	print "Dry-run OK: $infile parsed and validated successfully\n";
	exit 0;
} elsif($outfile && -e $outfile && !$run) {
	warn "Overwriting existing file: $outfile";
}

App::Test::Generator::generate($infile, $outfile);

if($outfile) {
	chmod 0755, $outfile if($outfile =~ /\.(pl|cgi)$/);
	if($run) {
		system("prove -l $outfile");
	}
}

exit 0;
