package Test::Stream::Plugin::SkipWithout;
use strict;
use warnings;

use Test::Stream::Context qw/context/;
use Test::Stream::Util qw/pkg_to_file/;
use Scalar::Util qw/reftype/;

use Test::Stream::Plugin qw/import/;

sub load_ts_plugin {
    my $class = shift;
    my $caller = shift;
    for my $arg (@_) {
        if (ref $arg) {
            check_versions($caller, $arg);
        }
        elsif ($arg =~ m/^v?\d/) {
            check_perl_version($caller, $arg);
        }
        else {
            check_installed($caller, $arg);
        }
    }
}

sub skip {
    my ($msg) = @_;
    my $ctx = context();
    $ctx->plan(0, SKIP => $msg);
}

sub check_installed {
    my ($caller, $mod) = @_;
    my $file = pkg_to_file($mod);
    return if eval { require $file; 1 };
    my $error = $@;
    return skip("Module '$mod' is not installed")
        if $error =~ m/Can't locate \Q$file\E in \@INC/;

    # Some other error, rethrow it.
    die $error;
}

sub check_perl_version {
    my ($caller, $ver) = @_;
    return if eval "no warnings 'portable'; require $ver; 1";
    my $error = $@;
    if ($error =~ m/^(Perl \S* required)/i) {
        return skip($1);
    }

    # Other Error
    die $error;
}

sub check_versions {
    my ($caller, $ref) = @_;
    my $type = reftype($ref) || "";
    die "'$ref' is not a valid import argument to " . __PACKAGE__ . " at $caller->[1] line $caller->[2].\n"
        unless $type eq 'HASH';

    # Sort so that the order is always the same in output
    for my $mod (sort keys %$ref) {
        my $ver = $ref->{$mod};
        check_installed($caller, $mod);
        next if eval { $mod->VERSION($ver); 1 };
        chomp(my $error = $@);
        $error =~ s/ at .*$//;
        skip($error);
    }
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Test::Stream::Plugin::SkipWithout - Plugin to skip tests if certain package
requirements are not met.

=head1 DEPRECATED

B<This distribution is deprecated> in favor of L<Test2>, L<Test2::Suite>, and
L<Test2::Workflow>.

See L<Test::Stream::Manual::ToTest2> for a conversion guide.

=head1 DESCRIPTION

Sometimes you have tests that are nice to run, but depend on tools that may not
be available. Instead of adding the tool as a dep, or making the test always
skip, it is common to make the test run conditionally. This package helps make
that possible.

This module is modeled after L<Test::Requires>. This module even stole most of
the syntax. The difference is that this module is based on L<Test::Stream>
directly, and does not go through L<Test::Builder>. Another difference is that
the packages you check for are not imported into your namespace for you, this
is intentional.

=head1 SYNOPSIS

    use Test::Stream SkipWithout => [
        'v5.10',                 # minimum perl version
        'Necessary::Package',    # We need this, we do not care what version it is

        # A hashref can be used to specify modules + minimum versions
        {
            'Scalar::Util' => '1.3',    # We need at least this version of Scalar::Util
            'Some::Tool'   => '2.5',    # We need version 2.5 of Some::Tool
        },
    ];

    # The tools and features are not imported for us, so we import them here.
    # This gives us control over the import arguments as well.
    use v5.10;
    use Necessary::Package qw/foo bar/;
    use Scalar::Util qw/blessed reftype/;
    use Some::Tool qw/do_it/;

=head1 SOURCE

The source code repository for Test::Stream can be found at
F<http://github.com/Test-More/Test-Stream/>.

=head1 MAINTAINERS

=over 4

=item Chad Granum E<lt>exodist@cpan.orgE<gt>

=back

=head1 AUTHORS

=over 4

=item Chad Granum E<lt>exodist@cpan.orgE<gt>

=back

=head1 COPYRIGHT

Copyright 2015 Chad Granum E<lt>exodist7@gmail.comE<gt>.

This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

See F<http://dev.perl.org/licenses/>

=cut
