libtest-minimumversion-perl/lib/Test/MinimumVersion.pm

362 lines
9.6 KiB
Perl

use 5.006;
use strict;
use warnings;
package Test::MinimumVersion;
$Test::MinimumVersion::VERSION = '0.101082';
# ABSTRACT: does your code require newer perl than you think?
use base 'Exporter';
#pod =head1 SYNOPSIS
#pod
#pod Example F<minimum-perl.t>:
#pod
#pod #!perl
#pod use Test::MinimumVersion;
#pod all_minimum_version_ok('5.008');
#pod
#pod =cut
use CPAN::Meta;
use File::Find::Rule;
use File::Find::Rule::Perl;
use Perl::MinimumVersion 1.32; # numerous bugfies
use version 0.70;
use Test::Builder;
@Test::MinimumVersion::EXPORT = qw(
minimum_version_ok
all_minimum_version_ok
all_minimum_version_from_metayml_ok
all_minimum_version_from_metajson_ok
all_minimum_version_from_mymetayml_ok
all_minimum_version_from_mymetajson_ok
);
sub import {
my($self) = shift;
my $pack = caller;
my $Test = Test::Builder->new;
$Test->exported_to($pack);
$Test->plan(@_);
$self->export_to_level(1, $self, @Test::MinimumVersion::EXPORT);
}
sub _objectify_version {
my ($version) = @_;
$version = eval { $version->isa('version') }
? $version
: version->new($version);
}
#pod =func minimum_version_ok
#pod
#pod minimum_version_ok($file, $version);
#pod
#pod This test passes if the given file does not seem to require any version of perl
#pod newer than C<$version>, which may be given as a version string or a version
#pod object.
#pod
#pod =cut
sub minimum_version_ok {
my ($file, $version) = @_;
my $Test = Test::Builder->new;
$version = _objectify_version($version);
my $pmv = Perl::MinimumVersion->new($file);
unless (defined $pmv) {
$Test->ok(0, $file);
$Test->diag(
"$file could not be parsed: " . PPI::Document->errstr
);
return;
}
my $explicit_minimum = $pmv->minimum_explicit_version || 0;
my $minimum = $pmv->minimum_syntax_version($explicit_minimum) || 0;
my $is_syntax = 1
if $minimum and $minimum > $explicit_minimum;
$minimum = $explicit_minimum
if $explicit_minimum and $explicit_minimum > $minimum;
my %min = $pmv->version_markers;
if ($minimum <= $version) {
$Test->ok(1, $file);
} else {
$Test->ok(0, $file);
$Test->diag(
"$file requires $minimum "
. ($is_syntax ? 'due to syntax' : 'due to explicit requirement')
);
if ($is_syntax and my $markers = $min{ $minimum }) {
$Test->diag("version markers for $minimum:");
$Test->diag("- $_ ") for @$markers;
}
}
}
#pod =func all_minimum_version_ok
#pod
#pod all_minimum_version_ok($version, \%arg);
#pod
#pod Given either a version string or a L<version> object, this routine produces a
#pod test plan (if there is no plan) and tests each relevant file with
#pod C<minimum_version_ok>.
#pod
#pod Relevant files are found by L<File::Find::Rule::Perl>.
#pod
#pod C<\%arg> is optional. Valid arguments are:
#pod
#pod paths - in what paths to look for files; defaults to (bin, script, t, lib,
#pod xt/smoke, and any .pm or .PL files in the current working
#pod directory) if it contains files, they will be checked
#pod no_plan - do not plan the tests about to be run
#pod skip - files to skip; this can be useful in weird cases like gigantic
#pod files, files falsely detected as Perl, or code that uses
#pod a source filter; this should be an arrayref of filenames
#pod
#pod =cut
sub all_minimum_version_ok {
my ($version, $arg) = @_;
$arg ||= {};
$arg->{paths} ||= [
qw(bin script lib t xt/smoke),
glob("*.pm"),
glob("*.PL"),
];
$arg->{skip} ||= [];
my $Test = Test::Builder->new;
$version = _objectify_version($version);
my @perl_files;
for my $path (@{ $arg->{paths} }) {
if (-f $path and -s $path) {
push @perl_files, $path;
} elsif (-d $path) {
push @perl_files, File::Find::Rule->perl_file->in($path);
}
}
my %skip = map {; $_ => 1 } @{ $arg->{skip} };
@perl_files = grep {; ! $skip{$_} } @perl_files;
unless ($Test->has_plan or $arg->{no_plan}) {
$Test->plan(tests => scalar @perl_files);
}
minimum_version_ok($_, $version) for @perl_files;
}
#pod =func all_minimum_version_from_metayml_ok
#pod
#pod all_minimum_version_from_metayml_ok(\%arg);
#pod
#pod This routine checks F<META.yml> for an entry in F<requires> for F<perl>. If no
#pod META.yml file or no perl version is found, all tests are skipped. If a version
#pod is found, the test proceeds as if C<all_minimum_version_ok> had been called
#pod with that version.
#pod
#pod =cut
sub __version_from_meta {
my ($fn) = @_;
my $meta = CPAN::Meta->load_file($fn, { lazy_validation => 1 })->as_struct;
my $version = $meta->{prereqs}{runtime}{requires}{perl};
}
sub __from_meta {
my ($fn, $arg) = @_;
$arg ||= {};
my $Test = Test::Builder->new;
$Test->plan(skip_all => "$fn could not be found")
unless -f $fn and -r _;
$Test->plan(skip_all => "no minimum perl version could be determined")
unless my $version = __version_from_meta($fn);
all_minimum_version_ok($version, $arg);
}
sub all_minimum_version_from_metayml_ok {
__from_meta('META.yml', @_);
}
#pod =func all_minimum_version_from_metajson_ok
#pod
#pod all_minimum_version_from_metajson_ok(\%arg);
#pod
#pod This routine checks F<META.json> for an entry in F<requires> for F<perl>. If
#pod no META.json file or no perl version is found, all tests are skipped. If a
#pod version is found, the test proceeds as if C<all_minimum_version_ok> had been
#pod called with that version.
#pod
#pod =cut
sub all_minimum_version_from_metajson_ok { __from_meta('META.json', @_); }
#pod =func all_minimum_version_from_mymetayml_ok
#pod
#pod all_minimum_version_from_mymetayml_ok(\%arg);
#pod
#pod This routine checks F<MYMETA.yml> for an entry in F<requires> for F<perl>. If
#pod no MYMETA.yml file or no perl version is found, all tests are skipped. If a
#pod version is found, the test proceeds as if C<all_minimum_version_ok> had been
#pod called with that version.
#pod
#pod =cut
sub all_minimum_version_from_mymetayml_ok { __from_meta('MYMETA.yml', @_); }
#pod =func all_minimum_version_from_mymetajson_ok
#pod
#pod all_minimum_version_from_mymetajson_ok(\%arg);
#pod
#pod This routine checks F<MYMETA.json> for an entry in F<requires> for F<perl>. If
#pod no MYMETA.json file or no perl version is found, all tests are skipped. If a
#pod version is found, the test proceeds as if C<all_minimum_version_ok> had been
#pod called with that version.
#pod
#pod =cut
sub all_minimum_version_from_mymetajson_ok { __from_meta('MYMETA.json', @_); }
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Test::MinimumVersion - does your code require newer perl than you think?
=head1 VERSION
version 0.101082
=head1 SYNOPSIS
Example F<minimum-perl.t>:
#!perl
use Test::MinimumVersion;
all_minimum_version_ok('5.008');
=head1 FUNCTIONS
=head2 minimum_version_ok
minimum_version_ok($file, $version);
This test passes if the given file does not seem to require any version of perl
newer than C<$version>, which may be given as a version string or a version
object.
=head2 all_minimum_version_ok
all_minimum_version_ok($version, \%arg);
Given either a version string or a L<version> object, this routine produces a
test plan (if there is no plan) and tests each relevant file with
C<minimum_version_ok>.
Relevant files are found by L<File::Find::Rule::Perl>.
C<\%arg> is optional. Valid arguments are:
paths - in what paths to look for files; defaults to (bin, script, t, lib,
xt/smoke, and any .pm or .PL files in the current working
directory) if it contains files, they will be checked
no_plan - do not plan the tests about to be run
skip - files to skip; this can be useful in weird cases like gigantic
files, files falsely detected as Perl, or code that uses
a source filter; this should be an arrayref of filenames
=head2 all_minimum_version_from_metayml_ok
all_minimum_version_from_metayml_ok(\%arg);
This routine checks F<META.yml> for an entry in F<requires> for F<perl>. If no
META.yml file or no perl version is found, all tests are skipped. If a version
is found, the test proceeds as if C<all_minimum_version_ok> had been called
with that version.
=head2 all_minimum_version_from_metajson_ok
all_minimum_version_from_metajson_ok(\%arg);
This routine checks F<META.json> for an entry in F<requires> for F<perl>. If
no META.json file or no perl version is found, all tests are skipped. If a
version is found, the test proceeds as if C<all_minimum_version_ok> had been
called with that version.
=head2 all_minimum_version_from_mymetayml_ok
all_minimum_version_from_mymetayml_ok(\%arg);
This routine checks F<MYMETA.yml> for an entry in F<requires> for F<perl>. If
no MYMETA.yml file or no perl version is found, all tests are skipped. If a
version is found, the test proceeds as if C<all_minimum_version_ok> had been
called with that version.
=head2 all_minimum_version_from_mymetajson_ok
all_minimum_version_from_mymetajson_ok(\%arg);
This routine checks F<MYMETA.json> for an entry in F<requires> for F<perl>. If
no MYMETA.json file or no perl version is found, all tests are skipped. If a
version is found, the test proceeds as if C<all_minimum_version_ok> had been
called with that version.
=head1 AUTHOR
Ricardo Signes
=head1 CONTRIBUTORS
=for stopwords Ricardo SIGNES Steve Hay
=over 4
=item *
Ricardo SIGNES <rjbs@codesimply.com>
=item *
Ricardo SIGNES <rjbs@cpan.org>
=item *
Steve Hay <steve.m.hay@googlemail.com>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2007 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut