#!/usr/bin/perl
#
# Copyright (c) 2018  Peter Pentchev
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

use v5.010;
use strict;
use warnings;

use Test::More;
use Test::Command;

use lib 't/lib';
use Test::FeatureCheck qw(
	env_init
	get_error_output get_ok_output
	test_fcheck_init
);

my %c = env_init;

my @usage_lines;

plan tests => 12;

my $fcheck_base = test_fcheck_init \%c;

# More than one usage line with -h
subtest 'Usage output with -h' => sub {
	my $c = Test::Command->new(cmd => [$c{prog}, '-h']);
	$c->exit_is_num(0, '-h succeeded');
	$c->stderr_is_eq('', '-h did not output any errors');
	my @lines = split /\n/, $c->stdout_value;
	BAIL_OUT('Too few lines in the -h output') unless @lines > 1;
	if (!$c{is_python}) {
		BAIL_OUT('Unexpected -h first line') unless
		    $lines[0] =~ /^ Usage: \s+ feature-check /x;
	} else {
		BAIL_OUT('Unexpected -h first line') unless
		    $lines[0] =~ /^ usage: \s+ $/x;
	}
	@usage_lines = @lines;
};

subtest 'List of its own features' => sub {
	my @lines = get_ok_output([$c{prog}, '--features'], 'get features');
	is scalar @lines, 1, 'list features output a single line';
	BAIL_OUT('No "Features: " on the features line') unless
	    $lines[0] =~ /^ Features: \s (?<features> .* ) $/x;
	my @words = split /\s+/, $+{features};
	my %names = map { split /[:\/=]/, $_, 2 } @words;
	BAIL_OUT('No "feature-check" in the features list') unless
	    defined $names{'feature-check'};
	BAIL_OUT('No "single" in the features list') unless
	    defined $names{'single'};
	BAIL_OUT('Only know how to test the "single" feature version 1.x') unless
	    $names{'single'} =~ m{^ 1 (?: \..* )? $ }x;
	BAIL_OUT('Found "x" in the features list') if
	    defined $names{x};
};

subtest 'Fail with no program or feature specified' => sub {
	my @lines = get_error_output([$c{prog}], 'no program specified');
	if ($c{is_python}) {
		ok join('\n', @lines) =~ m{^usage:},
		    'no program output the usage message';
	} else {
		is_deeply \@lines, \@usage_lines,
		    'no program output the usage message';
	}
};

subtest 'Fail with no feature specified' => sub {
	my @lines = get_error_output([$c{prog}, $c{fcheck}],
	    'no feature specified');
	if ($c{is_python}) {
		ok join('\n', @lines) =~ m{^usage:},
		    'no feature output the usage message';
	} else {
		is_deeply \@lines, \@usage_lines,
		    'no feature output the usage message';
	}
};

subtest 'Real work: existing feature' => sub {
	my @lines = get_ok_output([$c{prog}, $c{fcheck}, 'base'],
	    'existing feature');
	is scalar @lines, 0, 'good feature output nothing';
};

subtest 'Real work: show the feature version' => sub {
	my @lines = get_ok_output([$c{prog}, '-v', $c{fcheck}, 'base'],
	    'show version');
	is_deeply \@lines, [$fcheck_base], 'correct feature version';
};

subtest 'Real work: different option names' => sub {
	my $current_opt = $ENV{FCHECK_TEST_OPT};
	for my $opt (qw(--version --features -V)) {
		$ENV{FCHECK_TEST_OPT} = $opt;
		# Argh, Python argparse won't accept ('-O', $opt)
		# if $opt starts with a dash...
		my @lines = get_ok_output(
		    [$c{prog}, "-O$opt", $c{fcheck}, 'base'],
		    "feature option '$opt'");
		is scalar @lines, 0, 'good feature output nothing';
	}
	$ENV{FCHECK_TEST_OPT} = $current_opt;
};

subtest 'Real work: different features prefix' => sub {
	my $current_opt = $ENV{FCHECK_TEST_PREFIX};
	for my $pfx ('Features: ', 'V ', 'something/') {
		$ENV{FCHECK_TEST_PREFIX} = $pfx;
		my @lines = get_ok_output(
		    [$c{prog}, "-P$pfx", $c{fcheck}, 'base'],
		    "feature prefix '$pfx'");
		is scalar @lines, 0, 'good feature output nothing';
	}
	$ENV{FCHECK_TEST_PREFIX} = $current_opt;
};

subtest 'Real work: unknown feature' => sub {
	my @lines = get_error_output([$c{prog}, $c{fcheck}, 'x'],
	    'unknown feature');
	is scalar @lines, 0, 'bad feature output nothing';
};

subtest 'Real work: nonexistent program' => sub {
	my @lines = get_error_output([$c{prog}, '/nonexistent', 'x'],
	    'bad program');
	is scalar @lines, 0, 'bad program output nothing';
};

subtest 'Real work: unfeatured program' => sub {
	my $old_option = $ENV{FCHECK_TEST_OPT};
	$ENV{FCHECK_TEST_OPT} = '--not-features';
	my @lines = get_error_output([$c{prog}, $c{fcheck}, 'x'],
	    'weird program');
	is scalar @lines, 0, 'weird program output nothing';
	$ENV{FCHECK_TEST_OPT} = $old_option;
};
