File Coverage

blib/lib/Test/Prereq.pm
Criterion Covered Total %
statement 137 157 87.2
branch 27 40 67.5
condition 3 7 42.8
subroutine 30 31 96.7
pod 1 1 100.0
total 198 236 83.9


line stmt bran cond sub pod time code
1             package Test::Prereq;
2 7     7   74237 use parent qw(Test::Builder::Module);
  7         2131  
  7         36  
3              
4 7     7   440 use strict;
  7         11  
  7         118  
5 7     7   4087 use utf8;
  7         69  
  7         36  
6              
7 7     7   264 use v5.22;
  7         21  
8 7     7   29 use feature qw(postderef);
  7         11  
  7         839  
9 7     7   31 no warnings qw(experimental::postderef);
  7         8  
  7         261  
10              
11 7     7   23 use warnings;
  7         10  
  7         169  
12 7     7   22 no warnings;
  7         7  
  7         308  
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   26 use vars qw($VERSION $EXCLUDE_CPANPLUS @EXPORT @prereqs);
  7         8  
  7         540  
75              
76              
77             $VERSION = '2.002';
78              
79             @EXPORT = qw( prereq_ok );
80              
81 7     7   50 use Carp qw(carp);
  7         11  
  7         493  
82 7     7   5854 use ExtUtils::MakeMaker;
  7         682958  
  7         1023  
83 7     7   60 use File::Find;
  7         11  
  7         500  
84 7     7   3715 use Module::Extract::Use;
  7         10770  
  7         405  
85              
86             my $Test = __PACKAGE__->builder;
87              
88             {
89 7     7   73 no warnings;
  7         12  
  7         1633  
90              
91             * ExtUtils::MakeMaker::WriteMakefile = sub {
92 4     4   43 my %hash = @_;
93              
94 4         10 my $name = $hash{NAME};
95             my %prereqs =
96 16 100       64 map { defined $_ ? %$_ : () }
97 4         19 @hash{qw(PREREQ_PM BUILD_REQUIRES CONFIGURE_REQUIRES TEST_REQUIRES)};
98              
99 4         42 @Test::Prereq::prereqs = sort keys %prereqs;
100              
101 4         19 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
128             libraries found in F from the reported prerequisites.
129              
130             The optional third argument is an array reference to a list
131             of names that C should ignore. You might want to use
132             this if your 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 isn't
136             really a good idea. Some modules have moved to different distributions,
137             so you should just specify all the modules that you use instead of relying
138             on a particular distribution to provide them. Not only that, expanding
139             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 969 $Test->plan( tests => 1 ) unless $Test->has_plan;
151 2         229 __PACKAGE__->_prereq_check( @_ );
152             }
153              
154             sub import {
155 8     8   70 my $self = shift;
156 8         17 my $caller = caller;
157 7     7   43 no strict 'refs';
  7         9  
  7         10855  
158 8         16 *{$caller.'::prereq_ok'} = \&prereq_ok;
  8         43  
159              
160 8         38 $Test->exported_to($caller);
161 8         152 $Test->plan(@_);
162             }
163              
164             sub _prereq_check {
165 2     2   6 my $class = shift;
166              
167 2   50     25 my $name = shift // 'Prereq test';
168 2   50     35 my $skip = shift // [];
169              
170 2 50       11 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         10 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         13 my $loaded = $class->_get_loaded_modules();
184              
185 2 50       16 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         17 foreach my $module ( @$prereqs ) {
194 34         40 delete $loaded->{$module};
195             }
196              
197             # remove modules found in distribution
198 2         16 my $distro = $class->_get_dist_modules( 'blib/lib' );
199 2         15 foreach my $module ( $distro->@* ) {
200 4         9 delete $loaded->{$module};
201             }
202              
203             # remove modules found in test directory
204 2         13 $distro = $class->_get_test_libraries();
205 2         5 foreach my $module ( $distro->@* ) {
206 0         0 delete $loaded->{$module};
207             }
208              
209             # remove modules in the skip array
210 2         7 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       10 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         18 $Test->ok( 1, $name );
227             }
228              
229 2         1380 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   13 sub _master_file { 'Makefile.PL' }
240              
241             sub _get_prereqs {
242 5     5   12323 my $class = shift;
243 5         32 my $file = $class->_master_file;
244              
245 5         14 delete $INC{$file}; # make sure we load it again
246              
247             {
248 5         10 local $^W = 0;
  5         30  
249              
250 5 100       2082 unless( do "./$file" ) {
251 1         28 print STDERR "_get_prereqs: Error loading $file: $@\n";
252 1         7 return;
253             }
254 4         17 delete $INC{$file}; # pretend we were never here
255             }
256              
257 4         25 my @modules = sort @Test::Prereq::prereqs;
258 4         26 @Test::Prereq::prereqs = ();
259 4         18 return \@modules;
260             }
261              
262             # get all the loaded modules. we'll filter this later
263             sub _get_loaded_modules {
264 3     3   888 my $class = shift;
265              
266             # return unless( defined $_[0] and defined $_[1] );
267             # return unless( -d $_[0] and -d $_[1] );
268              
269 3         6 my( @libs, @t, @scripts );
270              
271 3 100   33   353 File::Find::find( sub { push @libs, $File::Find::name if m/\.pm$/ }, 'blib/lib' )
  33 50       1267  
272             if -e 'blib/lib';
273 3 100   33   154 File::Find::find( sub { push @t, $File::Find::name if m/\.t$/ }, 't' )
  33 50       297  
274             if -e 't';
275 3 100   6   170 File::Find::find( sub { push @scripts, $File::Find::name if -f $_ }, 'blib/script' )
  6 50       218  
276             if -e 'blib/script';
277              
278 3         11 my @found = ();
279 3         8 foreach my $file ( @libs, @t, @scripts ) {
280 36         63 push @found, @{ $class->_get_from_file( $file ) };
  36         263  
281             }
282              
283 3         11 return { map { $_, 1 } @found };
  108         190  
284             }
285              
286             sub _get_test_libraries {
287 2     2   5 my $class = shift;
288              
289 2         3 my $dirsep = "/";
290              
291 2         4 my @found = ();
292              
293 2 50   22   96 File::Find::find( sub { push @found, $File::Find::name if m/\.p(l|m)$/ }, 't' );
  22         212  
294              
295             my @files =
296             map {
297 2         14 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       18 push @files, 'test.pl' if -e 'test.pl';
305              
306 2         7 return \@files;
307             }
308              
309             sub _get_dist_modules {
310 2     2   4 my $class = shift;
311              
312 2 50 33     44 return unless( defined $_[0] and -d $_[0] );
313              
314 2         5 my $dirsep = "/";
315              
316 2         7 my @found = ();
317              
318 2 100   22   179 File::Find::find( sub { push @found, $File::Find::name if m/\.pm$/ }, $_[0] );
  22         967  
319              
320             my @files =
321             map {
322 2         12 my $x = $_;
  4         8  
323 4         53 $x =~ s/^$_[0]($dirsep)?//;
324 4         12 $x =~ s/\.pm$//;
325 4         29 $x =~ s|$dirsep|::|g;
326 4         12 $x;
327             }
328             @found;
329              
330 2         6 return \@files;
331             }
332              
333             sub _get_from_file {
334 38     38   2080 state $extor = Module::Extract::Use->new;
335 38         170 my( $class, $file ) = @_;
336              
337 38         148 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         1790062 state $can_import = { map { $_, 1 } qw(base parent) };
  113         441  
  8         38  
344 113 100       317 exists $can_import->{$_->module}
345             ?
346             $_->imports->@*
347             :
348             ();
349             } $modules->@*;
350              
351 38         235 my @modules = map { $_->module } $modules->@*;
  113         331  
352 38         230 push @modules, @imports;
353              
354 38         360 return \@modules;
355             }
356              
357             =back
358              
359             =head1 TO DO
360              
361             =over 4
362              
363             =item * set up a couple fake module distributions to test
364              
365             =item * warn about things that show up in C unnecessarily
366              
367             =back
368              
369             =head1 SOURCE AVAILABILITY
370              
371             This source is in Github:
372              
373             http://github.com/briandfoy/test-prereq
374              
375             =head1 CONTRIBUTORS
376              
377             Many thanks to:
378              
379             Andy Lester, Slavin Rezić, Randal Schwartz, Iain Truskett, Dylan Martin
380              
381             =head1 AUTHOR
382              
383             brian d foy, C<< >>
384              
385             =head1 COPYRIGHT and LICENSE
386              
387             Copyright © 2002-2016, brian d foy . All rights reserved.
388             This software is available under the Artistic License 2.
389              
390             =cut
391              
392             1;