File Coverage

blib/lib/Test/Prereq.pm
Criterion Covered Total %
statement 138 158 87.3
branch 27 40 67.5
condition 3 7 42.8
subroutine 30 31 96.7
pod 1 1 100.0
total 199 237 83.9


line stmt bran cond sub pod time code
1             package Test::Prereq;
2 7     7   274833 use parent qw(Test::Builder::Module);
  7         2177  
  7         37  
3              
4 7     7   441 use strict;
  7         14  
  7         141  
5 7     7   4152 use utf8;
  7         99  
  7         35  
6              
7 7     7   256 use v5.22;
  7         23  
8 7     7   36 use feature qw(postderef);
  7         12  
  7         979  
9 7     7   46 no warnings qw(experimental::postderef);
  7         9  
  7         242  
10              
11 7     7   34 use warnings;
  7         10  
  7         167  
12 7     7   32 no warnings;
  7         12  
  7         362  
13              
14             =encoding utf8
15              
16             =head1 NAME
17              
18             Test::Prereq - check if Makefile.PL has the right pre-requisites
19              
20             =head1 SYNOPSIS
21              
22             # if you use Makefile.PL
23             use Test::More;
24             eval "use Test::Prereq";
25             plan skip_all => "Test::Prereq required to test dependencies" if $@;
26             prereq_ok();
27              
28             # specify a perl version, test name, or module names to skip
29             prereq_ok( $version, $name, \@skip );
30              
31             # if you use Module::Build
32             use Test::More;
33             eval "use Test::Prereq::Build";
34             plan skip_all => "Test::Prereq::Build required to test dependencies" if $@;
35             prereq_ok();
36              
37             # or from the command line for a one-off check
38             perl -MTest::Prereq -eprereq_ok
39              
40             #The prerequisites test take quite some time so the following construct is
41             #recommended for non-author testers
42             use Test::More;
43             eval "use Test::Prereq::Build";
44              
45             my $msg;
46             if ($@) {
47             $msg = 'Test::Prereq::Build required to test dependencies';
48             } elsif (not $ENV{TEST_AUTHOR}) {
49             $msg = 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.';
50             }
51             plan skip_all => $msg if $msg;
52             prereq_ok();
53              
54             =head1 DESCRIPTION
55              
56             The C function examines the modules it finds in
57             F, F, and the test files it finds in F
58             (and F). It figures out which modules they use and compares
59             that list of modules to those in the C section of
60             F.
61              
62             If you use C instead, see L
63             instead.
64              
65             =head2 Warning about redefining ExtUtils::MakeMaker::WriteMakefile
66              
67             C has its own version of
68             C so it can run the F
69             and get the argument list of that function. You may see warnings
70             about this.
71              
72             =cut
73              
74 7     7   41 use vars qw($VERSION $EXCLUDE_CPANPLUS @EXPORT @prereqs);
  7         20  
  7         612  
75              
76              
77             $VERSION = '2.003';
78              
79             @EXPORT = qw( prereq_ok );
80              
81 7     7   59 use Carp qw(carp);
  7         13  
  7         373  
82 7     7   5934 use ExtUtils::MakeMaker;
  7         762878  
  7         784  
83 7     7   65 use File::Find;
  7         14  
  7         394  
84 7     7   3814 use Module::Extract::Use;
  7         13232  
  7         387  
85              
86             my $Test = __PACKAGE__->builder;
87              
88             {
89 7     7   50 no warnings;
  7         15  
  7         1825  
90              
91             * ExtUtils::MakeMaker::WriteMakefile = sub {
92 4     4   99 my %hash = @_;
93              
94 4         20 my $name = $hash{NAME};
95             my %prereqs =
96 16 100       77 map { defined $_ ? %$_ : () }
97 4         37 @hash{qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)};
98              
99 4         40 @Test::Prereq::prereqs = sort keys %prereqs;
100              
101 4         26 1;
102             }
103             }
104              
105             #unless( caller ) { prereq_ok() }
106              
107             =head1 FUNCTIONS
108              
109             =over 4
110              
111             =item prereq_ok( [ VERSION, [ NAME [, SKIP_ARRAY] ] ] )
112              
113             Tests F to ensure all non-core module dependencies are in
114             C. If you haven't set a testing plan already,
115             C creates a plan of one test.
116              
117             If you don't specify a version, C assumes you want to compare
118             the list of prerequisite modules to the version of perl running the
119             test.
120              
121             Valid versions come from C (which uses C<$]>).
122              
123             #!/usr/bin/perl
124             use Module::CoreList;
125             print map "$_\n", sort keys %Module::CoreList::version;
126              
127             C attempts to remove modules found in F and libraries
128             found in F from the reported prerequisites.
129              
130             The optional third argument is an array reference to a list of names
131             that C should ignore. You might want to use this if your
132             tests do funny things with C.
133              
134             Versions prior to 1.038 would use CPAN.pm to virtually include
135             prerequisites in distributions that you declared explicitly. This
136             isn't really a good idea. Some modules have moved to different
137             distributions, so you should just specify all the modules that you use
138             instead of relying on a particular distribution to provide them. Not
139             only that, expanding distributions with CPAN.pm takes forever.
140              
141             If you want the old behavior, set the C
142             environment variable to a true value.
143              
144             =cut
145              
146             my $default_version = $];
147             my $version = $];
148              
149             sub prereq_ok {
150 2 100   2 1 1297 $Test->plan( tests => 1 ) unless $Test->has_plan;
151 2         957 __PACKAGE__->_prereq_check( @_ );
152             }
153              
154             sub import {
155 8     8   66 my $self = shift;
156 8         20 my $caller = caller;
157 7     7   69 no strict 'refs';
  7         16  
  7         12843  
158 8         21 *{$caller.'::prereq_ok'} = \&prereq_ok;
  8         42  
159              
160 8         51 $Test->exported_to($caller);
161 8         110 $Test->plan(@_);
162             }
163              
164             sub _prereq_check {
165 2     2   7 my $class = shift;
166              
167 2   50     12 my $name = shift // 'Prereq test';
168 2   50     21 my $skip = shift // [];
169              
170 2 50       10 unless( ref $skip eq ref [] ) {
171 0         0 carp( 'The second parameter to prereq_ok must be an array reference!' );
172 0         0 return;
173             }
174              
175             # get the declared prereqs from the Makefile.PL
176 2         8 my $prereqs = $class->_get_prereqs();
177 2 50       7 unless( $prereqs ) {
178 0         0 $class->_not_ok( "\t" .
179             $class->_master_file . " did not return a true value.\n" );
180 0         0 return 0;
181             }
182              
183 2         11 my $loaded = $class->_get_loaded_modules();
184              
185 2 50       11 unless( $loaded ) {
186 0         0 $class->_not_ok( "\tCouldn't look up the modules for some reasons.\n" ,
187             "\tDo the blib/lib and t directories exist?\n",
188             );
189 0         0 return 0;
190             }
191              
192             # remove modules found in PREREQ_PM
193 2         6 foreach my $module ( @$prereqs ) {
194 34         53 delete $loaded->{$module};
195             }
196              
197             # remove modules found in distribution
198 2         14 my $distro = $class->_get_dist_modules( 'blib/lib' );
199 2         28 foreach my $module ( $distro->@* ) {
200 4         11 delete $loaded->{$module};
201             }
202              
203             # remove modules found in test directory
204 2         13 $distro = $class->_get_test_libraries();
205 2         8 foreach my $module ( $distro->@* ) {
206 0         0 delete $loaded->{$module};
207             }
208              
209             # remove modules in the skip array
210 2         6 foreach my $module ( $skip->@* ) {
211 0         0 delete $loaded->{$module};
212             }
213              
214 2 50       7 if( $EXCLUDE_CPANPLUS ) {
215 0         0 foreach my $module ( keys %$loaded ) {
216 0 0       0 next unless $module =~ m/^CPANPLUS::/;
217 0         0 delete $loaded->{$module};
218             }
219             }
220              
221 2 50       11 if( keys %$loaded ) { # stuff left in %loaded, oops!
222             $class->_not_ok( "Found some modules that didn't show up in PREREQ_PM or *_REQUIRES\n",
223 0         0 map { "\t$_\n" } sort keys %$loaded );
  0         0  
224             }
225             else {
226 2         19 $Test->ok( 1, $name );
227             }
228              
229 2         1269 return 1;
230             }
231              
232             sub _not_ok {
233 0     0   0 my( $self, $name, @message ) = @_;
234              
235 0         0 $Test->ok( 0, $name );
236 0         0 $Test->diag( join "", @message );
237             }
238              
239 4     4   24 sub _master_file { 'Makefile.PL' }
240              
241             sub _get_prereqs {
242 5     5   20115 my $class = shift;
243 5         65 my $file = $class->_master_file;
244              
245 5         19 delete $INC{$file}; # make sure we load it again
246              
247             {
248 5         17 local $^W = 0;
  5         48  
249              
250 5 100       2269 unless( do "./$file" ) {
251 1         43 print STDERR "_get_prereqs: Error loading $file: $@\n";
252 1         15 return;
253             }
254 4         19 delete $INC{$file}; # pretend we were never here
255             }
256              
257 4         34 my @modules = sort @Test::Prereq::prereqs;
258 4         11 @Test::Prereq::prereqs = ();
259 4         25 return \@modules;
260             }
261              
262             # get all the loaded modules. we'll filter this later
263             sub _get_loaded_modules {
264 3     3   1461 my $class = shift;
265              
266             # return unless( defined $_[0] and defined $_[1] );
267             # return unless( -d $_[0] and -d $_[1] );
268              
269 3         7 my( @libs, @t, @scripts );
270              
271 3 100   33   348 File::Find::find( sub { push @libs, $File::Find::name if m/\.pm$/ }, 'blib/lib' )
  33 50       1927  
272             if -e 'blib/lib';
273 3 100   33   215 File::Find::find( sub { push @t, $File::Find::name if m/\.t$/ }, 't' )
  33 50       421  
274             if -e 't';
275 3 100   6   209 File::Find::find( sub { push @scripts, $File::Find::name if -f $_ }, 'blib/script' )
  6 50       306  
276             if -e 'blib/script';
277              
278 3         19 my @found = ();
279 3         11 foreach my $file ( @libs, @t, @scripts ) {
280 36         59 push @found, @{ $class->_get_from_file( $file ) };
  36         198  
281             }
282              
283 3         11 return { map { $_, 1 } @found };
  51         126  
284             }
285              
286             sub _get_test_libraries {
287 2     2   5 my $class = shift;
288              
289 2         6 my $dirsep = "/";
290              
291 2         4 my @found = ();
292              
293 2 50   22   117 File::Find::find( sub { push @found, $File::Find::name if m/\.p(l|m)$/ }, 't' );
  22         250  
294              
295             my @files =
296             map {
297 2         15 my $x = $_;
  0         0  
298 0         0 $x =~ s/^.*$dirsep//;
299 0         0 $x =~ s|$dirsep|::|g;
300 0         0 $x;
301             }
302             @found;
303              
304 2 50       25 push @files, 'test.pl' if -e 'test.pl';
305              
306 2         10 return \@files;
307             }
308              
309             sub _get_dist_modules {
310 2     2   6 my $class = shift;
311              
312 2 50 33     52 return unless( defined $_[0] and -d $_[0] );
313              
314 2         8 my $dirsep = "/";
315              
316 2         6 my @found = ();
317              
318 2 100   22   207 File::Find::find( sub { push @found, $File::Find::name if m/\.pm$/ }, $_[0] );
  22         1243  
319              
320             my @files =
321             map {
322 2         15 my $x = $_;
  4         12  
323 4         59 $x =~ s/^$_[0]($dirsep)?//;
324 4         16 $x =~ s/\.pm$//;
325 4         22 $x =~ s|$dirsep|::|g;
326 4         63 $x;
327             }
328             @found;
329              
330 2         9 return \@files;
331             }
332              
333             sub _get_from_file {
334 38     38   4609 state $extor = Module::Extract::Use->new;
335 38         176 my( $class, $file ) = @_;
336              
337 38         110 my $modules = $extor->get_modules_with_details( $file );
338              
339             # We also depend on the super classes, which might not be
340             # part of the distro
341             my @imports =
342             map {
343 38         2397051 state $can_import = { map { $_, 1 } qw(base parent) };
  126         449  
  8         34  
344 126 100       448 exists $can_import->{$_->module}
345             ?
346             $_->imports->@*
347             :
348             ();
349             } $modules->@*;
350              
351             my @modules =
352 133         232 grep { state %Seen; ! $Seen{$_}++ } (
  133         339  
353             @imports,
354 38         198 map { $_->module } $modules->@*
  126         344  
355             );
356              
357 38         295 return \@modules;
358             }
359              
360             =back
361              
362             =head1 TO DO
363              
364             =over 4
365              
366             =item * set up a couple fake module distributions to test
367              
368             =item * warn about things that show up in C unnecessarily
369              
370             =back
371              
372             =head1 SOURCE AVAILABILITY
373              
374             This source is in Github:
375              
376             http://github.com/briandfoy/test-prereq
377              
378             =head1 CONTRIBUTORS
379              
380             Many thanks to:
381              
382             Andy Lester, Slavin Rezić, Randal Schwartz, Iain Truskett, Dylan Martin
383              
384             =head1 AUTHOR
385              
386             brian d foy, C<< >>
387              
388             =head1 COPYRIGHT and LICENSE
389              
390             Copyright © 2002-2016, brian d foy . All rights reserved.
391             This software is available under the Artistic License 2.
392              
393             =cut
394              
395             1;