File Coverage

blib/lib/Test/Distribution.pm
Criterion Covered Total %
statement 162 214 75.7
branch 16 56 28.5
condition 10 17 58.8
subroutine 38 47 80.8
pod 3 4 75.0
total 229 338 67.7


line stmt bran cond sub pod time code
1             package Test::Distribution;
2              
3             # pragmata
4 8     8   6435 use strict;
  8         18  
  8         589  
5 8     8   66 use vars qw($VERSION @default_types @supported_types);
  8         16  
  8         862  
6 8     8   46 use warnings;
  8         15  
  8         272  
7              
8             # perl modules
9 8     8   13736 use ExtUtils::Manifest qw(manicheck);
  8         141763  
  8         1000  
10 8     8   16550 use Test::More;
  8         195525  
  8         93  
11              
12              
13             $VERSION = '2.00';
14              
15             @default_types = qw/manifest use versions prereq pod description podcover/;
16             @supported_types = qw/manifest use versions prereq pod description podcover sig/;
17              
18             my @error;
19             for (qw/File::Spec File::Basename File::Find::Rule/) {
20             eval "require $_";
21             push @error => $_ if $@;
22             }
23             if (@error) {
24             # construct a nice message with proper placement of commas and
25             # the verb 'to be' in the enumeration of the error(s)
26              
27             @error = sort @error;
28             my $is = @error == 1 ? 'is' : 'are';
29             my $last = pop @error;
30             my $msg = join ', ' => @error;
31             $msg .= ' and ' if length $msg;
32             $msg .= "$last $is required for Test::Distribution";
33             plan skip_all => $msg;
34             exit;
35             }
36              
37             # This runs during BEGIN
38              
39             sub import {
40 13 100   13   218 return if our $been_here++;
41 8         22 my $pkg = shift;
42 8         36 my %args = @_;
43              
44 8     8   4928 use vars qw(@default_types);
  8         21  
  8         6689  
45 8   100     68 $args{only} ||= \@default_types;
46 8 100       51 $args{only} = [ $args{only} ] unless ref $args{only} eq 'ARRAY';
47              
48 8   50     61 $args{not} ||= [];
49 8 50       40 $args{not} = [ $args{not} ] unless ref $args{not} eq 'ARRAY';
50              
51 8   100     41 $args{tests} ||= 0;
52              
53 8         88 $args{dirlist} = [ qw(blib lib) ];
54 8   33     55 $args{dir} ||= File::Spec->catfile(@{ $args{dirlist} });
  8         166  
55              
56 8   100     56 $args{podcoveropts} ||= {};
57              
58 8         34 run_tests(\%args);
59             }
60              
61             # This runs after CHECK, i.e. at run-time
62              
63             sub run_tests {
64 8     8 0 18 my $args = shift;
65 8         61 my %args = %$args;
66              
67 8 50       512 our @files = -d $args{dir} ? File::Find::Rule->file()->name('*.pm')->in($args{dir}) : ();
68              
69 8         156 our @packages = map {
70             # $_ is like 'blib/lib/Foo/Bar/Baz.pm',
71             # after splitpath: $dir is 'blib/lib/Foo/Bar', $file is 'Baz.pm',
72             # after splitdir: @dir is qw(blib lib Foo Bar),
73             # after shifting off @{$args{dirlist}}, @dir is qw(Foo Bar),
74             # so now we can portably construct the package name.
75              
76 8         11374 my ($vol, $dir, $file) = File::Spec->splitpath($_);
77 8         138 my @dir = grep { length } File::Spec->splitdir($dir);
  32         203  
78 8         21 shift @dir for @{ $args{dirlist} };
  8         42  
79 8         626 join '::' => @dir, File::Basename::basename($file, '.pm');
80             } @files;
81              
82 8         20 my %perform;
83 8         16 %perform = map { $_ => 1 } @{$args{only}};
  22         69  
  8         26  
84 8         18 delete @perform{ @{$args{not}} };
  8         26  
85              
86             # need to use() modules before we can check their $VERSIONS,
87             # so we might as well test with use_ok().
88              
89 8 100       50 $perform{use} = 1 if $perform{versions};
90              
91 8         17 our %testers;
92 8         34 our $tests = $args{tests};
93 8         43 for my $type (keys %perform) {
94 24 50       473 die "no such test type: $type\n"
95             unless grep /^$type$/ => our @supported_types;
96              
97 24         52 my $pkg = __PACKAGE__ . '::' . $type;
98 24         276 $testers{$type} = $pkg->new(
99             packages => \@packages,
100             files => \@files,
101             %args,
102             );
103              
104 24         109 $tests += $testers{$type}->num_tests;
105             }
106              
107 8         52 plan tests => $tests;
108              
109 8         13829 for my $type (@supported_types) {
110 64 100       303735 $testers{$type}->run_tests($args) if $perform{$type};
111             }
112             }
113              
114 1     1 1 9 sub packages { our @packages }
115 1     1 1 5 sub files { our @files }
116 6     6 1 2794 sub num_tests { our $tests }
117              
118             package Test::Distribution::base;
119              
120             sub new {
121 24     24   142 my ($class, %args) = @_;
122 24         84 bless \%args, $class;
123             }
124              
125 0     0   0 sub num_tests { 0 }
126 0     0   0 sub run_tests {}
127              
128              
129             package Test::Distribution::pod;
130 8     8   58 use Test::More;
  8         19  
  8         44  
131             our @ISA = 'Test::Distribution::base';
132              
133 5     5   10 sub num_tests { scalar @{ $_[0]->{files} } }
  5         44  
134              
135 5         10 sub run_tests { SKIP: {
136 5     5   11 my $self = shift;
137              
138 5         12 eval {
139 5         6955 require Test::Pod;
140 5         210739 Test::Pod->import;
141             };
142 5 50       251 skip 'Test::Pod required for testing POD', $self->num_tests() if $@;
143              
144 5         15 for my $file (@{ $self->{files} }) { pod_file_ok($file) }
  5         69  
  5         23  
145             } }
146              
147              
148             package Test::Distribution::podcover;
149 8     8   9628 use Test::More;
  8         15  
  8         70  
150             our @ISA = 'Test::Distribution::base';
151              
152 3     3   6 sub num_tests { scalar @{ $_[0]->{packages} } }
  3         26  
153              
154 3         8 sub run_tests { SKIP: {
155 3     3   8 my $self = shift;
156 3         22 my $args = shift;
157              
158 3         7 eval {
159 3         5309 require Test::Pod::Coverage;
160 3         4441 Test::Pod::Coverage->import;
161             };
162 3 50       117 skip 'Test::Pod::Coverage required for testing POD', $self->num_tests() if $@;
163              
164 3         10 my $trustme = $args->{podcoveropts};
165 3         7 for my $package (@{ $self->{packages} }) { pod_coverage_ok($package, $trustme, 'Pod Coverage ok') }
  3         35  
  3         13  
166             } }
167              
168              
169             package Test::Distribution::use;
170 8     8   3884 use Test::More;
  8         21  
  8         34  
171             our @ISA = 'Test::Distribution::base';
172              
173 5     5   10 sub num_tests { scalar @{ $_[0]->{packages} } }
  5         44  
174              
175             sub run_tests {
176 5     5   13 my $self = shift;
177 5     5   672 for my $package (@{ $self->{packages} }) { use_ok($package) }
  5         9  
  5         9  
  5         77  
  5         10  
  5         15  
  5         27  
178             }
179              
180              
181             package Test::Distribution::versions;
182 8     8   2987 use Test::More;
  8         18  
  8         34  
183             our @ISA = 'Test::Distribution::base';
184              
185             sub num_tests {
186 4     4   9 my $self = shift;
187            
188 4         7 my $num_packages = scalar @{ $self->{packages} };
  4         26  
189              
190 4 50       18 if($self->{distversion}) {
191 0         0 return $num_packages * 2 - 1; # Don't test package itself to see if its own dist version matches
192             }
193             else {
194 4         15 return $num_packages;
195             }
196              
197             }
198              
199             sub run_tests {
200 4     4   11 my $self = shift;
201              
202 4         9 for my $package (@{ $self->{packages} }) {
  4         17  
203 4         10 our $version;
204            
205 4         8 my $this_version = do {
206 8     8   3193 no strict 'refs';
  8         22  
  8         1695  
207 4         7 ${"$package\::VERSION"}
  4         25  
208             };
209              
210 4 50       23 unless (defined $version) {
211 4         11 $version = $this_version;
212 4         26 ok(defined($version), "$package defines a version");
213 4         1404 next;
214             }
215              
216 0         0 ok(defined($version), "$package defines a version");
217              
218 0 0       0 if($self->{distversion}) {
219 0         0 is($this_version, $version, "$package version matches");
220             }
221             }
222             }
223              
224              
225             package Test::Distribution::description;
226 8     8   41 use Test::More;
  8         16  
  8         40  
227             our @ISA = 'Test::Distribution::base';
228              
229 2     2   16 sub num_tests { 4 }
230              
231             sub run_tests {
232 2     2   8 my $self = shift;
233 2         84 ok(-e, "$_ exists") for qw/MANIFEST README/;
234 2   33     1629 ok(-e 'Changes' || -e 'ChangeLog' || -e 'Changes.pod' || -e 'ChangeLog.pod', 'Changes(.pod)? or ChangeLog(.pod)? exists');
235 2   33     744 ok(-e 'Build.PL' || -e 'Makefile.PL', 'Build.PL or Makefile.PL exists');
236             }
237              
238              
239             package Test::Distribution::manifest;
240 8     8   3376 use Test::More;
  8         20  
  8         52  
241             our @ISA = 'Test::Distribution::base';
242              
243 2     2   6 sub num_tests { 1 }
244              
245             sub run_tests {
246 2     2   6 my $self = shift;
247            
248 2         14 my @missing_files = ExtUtils::Manifest::manicheck();
249 2         7015 ok(scalar @missing_files == 0, "Checking MANIFEST integrity");
250             }
251              
252              
253             package Test::Distribution::prereq;
254 8     8   2759 use Test::More;
  8         17  
  8         36  
255             our @ISA = 'Test::Distribution::base';
256              
257 6     6   39 sub num_tests { 1 }
258              
259 3         9 sub run_tests { SKIP: {
260 3     3   9 my $self = shift;
261              
262 3         10 eval {
263 3         34 require File::Find::Rule;
264 3         14522 require Module::CoreList;
265             };
266 3 50       181421 skip 'Module::Build PREREQ_PM not yet implemented', $self->num_tests() if -f 'Build.PL';
267 0 0         skip 'File::Find::Rule and Module::CoreList required for testing PREREQ_PM', $self->num_tests() if $@;
268 0 0         skip "testing PREREQ_PM not implemented for perl $] because Module::CoreList doesn't know about it", $self->num_tests unless
269             exists $Module::CoreList::version{ $] };
270              
271 0           my (%use, %package);
272              
273             File::Find::Rule->file()->nonempty()->or(
274             File::Find::Rule->name(qr/\.p(l|m|od)$/),
275             File::Find::Rule->exec(sub {
276 0     0     my $fh;
277 0 0         return 0 unless open $fh, $_;
278 0           my $shebang = <$fh>;
279 0           close $fh;
280 0           return $shebang =~ /^#!.*\bperl/;
281             }),
282             )->exec(sub {
283 0     0     my $fh;
284 0 0         return 0 unless open $fh, $_;
285 0           while (<$fh>) {
286 0 0         $use{$1}++ if /^use \s+ ([^\W\d][\w:]+) (\s*\n | .*;)/x;
287 0 0         $package{$1}++ if /^package \s+ ([\w:]+) \s* ;/x;
288             }
289 0           return 1;
290 0           })->in($self->{dir});
291              
292             # We're not interested in use()d modules that are provided by
293             # this distro, or in core modules. It's ok core modules aren't
294             # mentioned in PREREQ_PM.
295              
296 8     8   8350 no warnings 'once';
  8         15  
  8         3141  
297 0           delete @use{ keys %package, keys %{ $Module::CoreList::version{$]} } };
  0            
298              
299 0 0         open my $fh, 'Makefile.PL' or die "can't open Makefile.PL: $!\n";
300 0           my $make = do { local $/; <$fh> };
  0            
  0            
301 0 0         close $fh or die "can't close Makefile.PL: $!\n";
302 0           $make =~ s/use \s+ ExtUtils::MakeMaker \s* ;/no strict;/gx;
303              
304 0           $make .= 'sub WriteMakefile {
305             my %h = @_; our @prereq = keys %{ $h{PREREQ_PM} || {} } }';
306 0           eval $make;
307 0 0         die $@ if $@;
308              
309 0           delete @use{our @prereq};
310 0 0         ok(keys(%use) == 0, 'All non-core use()d modules listed in PREREQ_PM')
311             or diag(prereq_error(%use));
312             } }
313              
314             # construct an error message for test output
315             sub prereq_error {
316 0     0     my %use = @_;
317 0           my @modules = sort keys %use;
318 0           (@modules > 1 ? 'These modules are' : 'A module is') .
319             " used but not mentioned in Makefile.PL's PREREQ_PM:\n" .
320 0 0         join "\n" => map { " $_" } @modules;
321             }
322              
323             # XXX - not yet implemented and no docs or tests yet.
324             package Test::Distribution::exports;
325 8     8   45 use Test::More;
  8         13  
  8         170  
326             our @ISA = 'Test::Distribution::base';
327              
328 0     0     sub num_tests { 0 }
329              
330             sub run_tests {
331 0     0     my $self = shift;
332             }
333              
334             package Test::Distribution::sig;
335 8     8   3557 use Test::More;
  8         15  
  8         37  
336             our @ISA = 'Test::Distribution::base';
337              
338             sub num_tests {
339 0 0   0     return (-f 'SIGNATURE') ? 1 : 0;
340             }
341              
342 0           sub run_tests { SKIP: {
343 0     0     my $self = shift;
344 0 0         return unless $self->num_tests();
345 0           eval {
346 0           require Module::Signature;
347 0           Module::Signature->import;
348             };
349 0 0         if($@) {
350 0           skip 'Module::Signature required for this test', $self->num_tests();
351             }
352             else {
353 0           my $ret = Module::Signature::verify();
354 0 0         skip "Module::Signature cannot verify", 1 if $ret eq Module::Signature::CANNOT_VERIFY();
355              
356 0           cmp_ok $ret, '==', Module::Signature::SIGNATURE_OK(), "Valid signature";
357             }
358             } }
359             1;
360              
361             __END__