The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

use strict;
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
=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.
=cut