File Coverage

blib/lib/Test/Apocalypse/Dependencies.pm
Criterion Covered Total %
statement 23 25 92.0
branch n/a
condition n/a
subroutine 9 9 100.0
pod n/a
total 32 34 94.1


line stmt bran cond sub pod time code
1             #
2             # This file is part of Test-Apocalypse
3             #
4             # This software is copyright (c) 2014 by Apocalypse.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9 38     38   2072535 use strict; use warnings;
  38     38   160  
  38         1421  
  38         160  
  38         38  
  38         1660  
10             package Test::Apocalypse::Dependencies;
11             $Test::Apocalypse::Dependencies::VERSION = '1.006';
12             BEGIN {
13 38     38   717 $Test::Apocalypse::Dependencies::AUTHORITY = 'cpan:APOCAL';
14             }
15              
16             # ABSTRACT: Plugin to check for metadata dependencies
17              
18 38     38   152 use Test::More;
  38         45  
  38         219  
19 38     38   36331 use File::Slurp 9999.13;
  38         340343  
  38         2858  
20 38     38   19367 use YAML::Any 0.72;
  38         34048  
  38         190  
21 38     38   131035 use JSON::Any 1.25;
  38         703759  
  38         191  
22 38     38   85919 use File::Find::Rule 0.32;
  38         7701  
  38         228  
23 38     38   9914 use Perl::PrereqScanner 1.000;
  0            
  0            
24             use Test::Deep 0.108;
25             use CPAN::Meta::Requirements 2.113640;
26              
27             sub _do_automated { 0 }
28              
29             sub do_test {
30             # load the metadata
31             my $runtime_req;
32             my $test_req;
33             my $provides;
34             if ( -e 'META.json' ) {
35             my $file = read_file( 'META.json' );
36             my $metadata = JSON::Any->new->Load( $file );
37             $runtime_req = $metadata->{'prereqs'}{'runtime'}{'requires'};
38             $test_req = $metadata->{'prereqs'}{'test'}{'requires'};
39             $provides = $metadata->{'provides'} if exists $metadata->{'provides'};
40             } elsif ( -e 'META.yml' ) {
41             my $file = read_file( 'META.yml' );
42             my $metadata = Load( $file );
43             $runtime_req = $metadata->{'requires'};
44             $provides = $metadata->{'provides'} if exists $metadata->{'provides'};
45             } else {
46             die 'No META.(json|yml) found!';
47             }
48              
49             # Okay, scan the files
50             my $found_runtime = CPAN::Meta::Requirements->new;
51             my $found_test = CPAN::Meta::Requirements->new;
52             foreach my $file ( File::Find::Rule->file()->name( qr/\.pm$/ )->in( 'lib' ) ) {
53             $found_runtime->add_requirements( Perl::PrereqScanner->new->scan_file( $file ) );
54             }
55              
56             # scan the test dir only if we have test metadata
57             if ( defined $test_req ) {
58             foreach my $file ( File::Find::Rule->file()->name( qr/\.(pm|t|pl)$/ )->in( 't' ) ) {
59             $found_test->add_requirements( Perl::PrereqScanner->new->scan_file( $file ) );
60             }
61             }
62              
63             # Okay, the spec says that anything already in the runtime req shouldn't be listed in test req
64             # That means we need to "fake" the prereq and make sure the comparison is OK
65             if ( defined $test_req ) {
66             my %temp = %{ $found_test->as_string_hash };
67             foreach my $mod ( keys %temp ) {
68             if ( ! exists $test_req->{ $mod } and exists $runtime_req->{ $mod } ) {
69             # don't copy runtime_req's version because it might be different and cmp_deeply will complain!
70             $test_req->{ $mod } = $temp{ $mod };
71             }
72             }
73             }
74              
75             # We remove any prereqs that we provided in the package
76             if ( defined $provides ) {
77             foreach my $p ( keys %$provides ) {
78             $found_runtime->clear_requirement( $p );
79             $found_test->clear_requirement( $p );
80             }
81             }
82              
83             # Thanks to PoCo::SmokeBox::Uploads::Rsync's use of PoCo::Generic, we have to do this
84             # Mangle the found version to the required one if it was 0
85             {
86             my %temp = %{ $found_runtime->as_string_hash };
87             foreach my $p ( keys %temp ) {
88             if ( $runtime_req->{ $p } ne '0' and $temp{ $p } eq '0' ) {
89             $found_runtime->clear_requirement( $p );
90             $found_runtime->add_minimum( $p => $runtime_req->{ $p } );
91             }
92             }
93             }
94              
95             # Do the same for the test stuff
96             if ( defined $test_req ) {
97             my %temp = %{ $found_test->as_string_hash };
98             foreach my $p ( keys %temp ) {
99             if ( $test_req->{ $p } ne '0' and $temp{ $p } eq '0' ) {
100             $found_test->clear_requirement( $p );
101             $found_test->add_minimum( $p => $runtime_req->{ $p } );
102             }
103             }
104             }
105              
106             # remove 'perl' dep - we check it in MinimumVersion anyway
107             delete $runtime_req->{'perl'} if exists $runtime_req->{'perl'};
108             delete $test_req->{'perl'} if defined $test_req and exists $test_req->{'perl'};
109             $found_runtime->clear_requirement( 'perl' );
110             $found_test->clear_requirement( 'perl' );
111              
112             # Convert version objects to regular or we'll get something like this:
113             # Compared $data->{"Test\:\:NoPlan"}
114             # got : 'v0.0.6'
115             # expect : '0.0.6'
116             $found_runtime = $found_runtime->as_string_hash;
117             $found_runtime->{ $_ } =~ s/^v// for keys %$found_runtime;
118             $runtime_req->{ $_ } =~ s/^v// for keys %$runtime_req;
119              
120             # Do the actual comparison!
121             if ( defined $test_req ) {
122             plan tests => 2;
123              
124             $found_test = $found_test->as_string_hash;
125             $found_test->{ $_ } =~ s/^v// for keys %$found_test;
126             $test_req->{ $_ } =~ s/^v// for keys %$test_req;
127              
128             # TODO interesting, somewhere deep in the build chain it auto-upgraded Test::More version...
129             # I had 0.88 set but somehow 0.96 was in the META.yml argh!
130             if ( $found_test->{'Test::More'} ne $test_req->{'Test::More'} ) {
131             diag( 'Found weird Test::More version mismatch, ignoring it! (' . $found_test->{'Test::More'} . ' vs ' . $test_req->{'Test::More'} . ')' );
132             $found_test->{'Test::More'} = $test_req->{'Test::More'};
133             }
134             } else {
135             plan tests => 1;
136             }
137              
138             cmp_deeply( $found_runtime, $runtime_req, "Runtime requires" );
139             cmp_deeply( $found_test, $test_req, "Test requires" ) if defined $test_req;
140              
141             return;
142             }
143              
144             1;
145              
146             __END__
147              
148             =pod
149              
150             =encoding UTF-8
151              
152             =for :stopwords Apocalypse Niebur Ryan metadata
153              
154             =for Pod::Coverage do_test
155              
156             =head1 NAME
157              
158             Test::Apocalypse::Dependencies - Plugin to check for metadata dependencies
159              
160             =head1 VERSION
161              
162             This document describes v1.006 of Test::Apocalypse::Dependencies - released October 25, 2014 as part of Test-Apocalypse.
163              
164             =head1 DESCRIPTION
165              
166             Loads the metadata and uses L<Perl::PrereqScanner> to look for dependencies and compares the lists.
167              
168             =head1 SEE ALSO
169              
170             Please see those modules/websites for more information related to this module.
171              
172             =over 4
173              
174             =item *
175              
176             L<Test::Apocalypse|Test::Apocalypse>
177              
178             =back
179              
180             =head1 AUTHOR
181              
182             Apocalypse <APOCAL@cpan.org>
183              
184             =head1 COPYRIGHT AND LICENSE
185              
186             This software is copyright (c) 2014 by Apocalypse.
187              
188             This is free software; you can redistribute it and/or modify it under
189             the same terms as the Perl 5 programming language system itself.
190              
191             The full text of the license can be found in the
192             F<LICENSE> file included with this distribution.
193              
194             =head1 DISCLAIMER OF WARRANTY
195              
196             THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
197             APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
198             HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
199             OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
200             THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
201             PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
202             IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
203             ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
204              
205             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
206             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
207             THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
208             GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
209             USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
210             DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
211             PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
212             EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
213             SUCH DAMAGES.
214              
215             =cut