File Coverage

lib/Test/RequiredMinimumDependencyVersion.pm
Criterion Covered Total %
statement 83 83 100.0
branch 28 28 100.0
condition 10 12 83.3
subroutine 11 11 100.0
pod 3 3 100.0
total 135 137 98.5


line stmt bran cond sub pod time code
1             package Test::RequiredMinimumDependencyVersion;
2              
3 7     7   466550 use 5.006;
  7         82  
4 7     7   40 use strict;
  7         14  
  7         155  
5 7     7   36 use warnings;
  7         18  
  7         329  
6              
7             our $VERSION = '0.003';
8              
9 7     7   45 use Carp ();
  7         12  
  7         145  
10 7     7   3174 use Perl::PrereqScanner ();
  7         4360277  
  7         238  
11 7     7   63 use Test::Builder ();
  7         15  
  7         104  
12 7     7   3402 use Test::XTFiles ();
  7         109897  
  7         192  
13 7     7   50 use version 0.77 ();
  7         104  
  7         4570  
14              
15             my $TEST = Test::Builder->new();
16              
17             # - Do not use subtests because subtests cannot be tested with
18             # Test::Builder:Tester.
19             # - Do not use a plan because a method that sets a plan cannot be tested
20             # with Test::Builder:Tester.
21             # - Do not call done_testing in a method that should be tested by
22             # Test::Builder::Tester because TBT cannot test them.
23              
24             sub all_files_ok {
25 4     4 1 26 my ($self) = @_;
26              
27 4         58 my @files = Test::XTFiles->new->all_perl_files();
28 4 100       27692 if ( !@files ) {
29 1         20 $TEST->skip_all("No files found\n");
30 1         14 return 1;
31             }
32              
33 3         54 my $rc = 1;
34 3         10 for my $file (@files) {
35 4 100       23 if ( !$self->file_ok($file) ) {
36 1         10 $rc = 0;
37             }
38             }
39              
40 3         33 $TEST->done_testing;
41              
42 3 100       25 return 1 if $rc;
43 1         5 return;
44             }
45              
46             sub new {
47 19     19 1 22967 my $class = shift;
48              
49 19 100       181 Carp::croak 'Odd number of arguments' if @_ % 2;
50 18         79 my %args = @_;
51              
52 18         115 my $self = bless { _module => {} }, $class;
53              
54 18 100 100     420 Carp::croak 'No modules specified' if !exists $args{module} || ref $args{module} ne ref {};
55              
56 16         38 for my $module ( sort keys %{ $args{module} } ) {
  16         101  
57 19         40 my $version;
58 19         37 my $ok = eval {
59 19         138 $version = version->parse( $args{module}{$module} );
60 18         76 1;
61             };
62 19 100 66     261 Carp::croak "Cannot parse version '$args{module}{$module}'" if !defined $ok || !$ok;
63              
64 18         71 $self->{_module}{$module} = $version;
65             }
66              
67             KEY:
68 15         48 for my $key ( keys %args ) {
69 15 100       60 next KEY if $key eq 'module';
70              
71 1         101 Carp::croak "new() knows nothing about argument '$key'";
72             }
73              
74 14         55 return $self;
75             }
76              
77             sub file_ok {
78 11     11 1 14206 my ( $self, $file ) = @_;
79              
80 11 100 100     380 Carp::croak 'usage: file_ok(FILE)' if @_ != 2 || !defined $file;
81              
82 8         22 my $parse_msg = "Parse file ($file)";
83              
84 8 100       162 if ( !-f $file ) {
85 1         7 $TEST->ok( 0, $parse_msg );
86 1         1138 $TEST->diag("\n");
87 1         240 $TEST->diag("File $file does not exist or is not a file");
88 1         235 return;
89             }
90              
91 7         21 my $req;
92 7         18 my $ok = eval {
93 7         104 $req = Perl::PrereqScanner->new->scan_file($file);
94 6         125428 1;
95             };
96              
97 7 100 66     7561 if ( !defined $ok || !$ok ) {
98              
99             # Cannot parse file
100 1         578 $TEST->ok( 0, $parse_msg );
101 1         967 return;
102             }
103              
104 6         31 $TEST->ok( 1, $parse_msg );
105              
106 6         1640 my %minimum_prereqs = %{ $self->{_module} };
  6         29  
107              
108 6         14 my $rc = 1;
109             MODULE:
110 6         22 for my $module ( sort keys %minimum_prereqs ) {
111 7         26 my $want = $req->requirements_for_module($module);
112 7 100       317 next MODULE if !defined $want;
113              
114 6         13 my $minimum = $minimum_prereqs{$module};
115 6         56 my $want_ok = version->parse($want) >= $minimum;
116              
117 6 100       26 if ( $want eq '0' ) {
118 1         2 $want = 'any';
119             }
120              
121 6         38 $TEST->ok( $want_ok, "$module $want >= $minimum" );
122              
123 6 100       3821 if ( !$want_ok ) {
124 3         12 $rc = 0;
125             }
126             }
127              
128 6 100       35 return 1 if $rc;
129 3         23 return;
130             }
131              
132             1;
133              
134             __END__
135              
136             =pod
137              
138             =encoding UTF-8
139              
140             =head1 NAME
141              
142             Test::RequiredMinimumDependencyVersion - require a minimum version for your dependencies
143              
144             =head1 VERSION
145              
146             Version 0.003
147              
148             =head1 SYNOPSIS
149              
150             use Test::RequiredMinimumDependencyVersion;
151             Test::RequiredMinimumDependencyVersion->new(module => { ... })->all_files_ok;
152              
153             =head1 DESCRIPTION
154              
155             There are some modules where you'll always depend on a minimal version,
156             either because of a bug or because of an API change. A good example would be
157             L<Test::More|Test::More> where version 0.88 introduced C<done_testing()> or
158             L<version|version> which strongly urges to set 0.77 as a minimum in your code.
159              
160             This test can be used to check that, whenever you use these modules, you also
161             declare the minimum version.
162              
163             This test is an author test and should not run on end-user installations.
164             Recommendation is to put it into your F<xt> instead of your F<t> directory.
165              
166             =head1 USAGE
167              
168             =head2 new( ARGS )
169              
170             Returns a new C<Test::RequiredMinimumDependencyVersion> instance. C<new>
171             takes a hash with its arguments.
172              
173             Test::RequiredMinimumDependencyVersion->new(
174             module => {
175             'Test::More' => '0.88',
176             },
177             );
178              
179             The following arguments are supported:
180              
181             =head3 module (required)
182              
183             The C<module> argument is a hash ref where the keys are the modules you want
184             to enforce and the minimal version is its value.
185              
186             =head2 file_ok( FILENAME )
187              
188             This will run a test for parsing the file with
189             L<Perl::PrereqScanner|Perl::PrereqScanner> and another test for every
190             C<module> you specified if it is used in this file. It is therefore unlikely
191             to know the exact number of tests that will run in advance. Use
192             C<done_testing> from L<Test::More|Test::More> if you call this test directly
193             instead of a C<plan>.
194              
195             C<file_ok> returns something I<true> if all checked dependencies are at least
196             of the required minimal version and I<false> otherwise.
197              
198             =head2 all_files_ok
199              
200             Calls the C<all_perl_files> method of L<Test::XTFiles> to get all the files to
201             be tested. All files will be checked by calling C<file_ok>.
202              
203             It calls C<done_testing> or C<skip_all> so you can't have already called
204             C<plan>.
205              
206             C<all_files_ok> returns something I<true> if all files test ok and I<false>
207             otherwise.
208              
209             Please see L<XT::Files> for how to configure the files to be checked.
210              
211             WARNING: The API was changed with 0.003. Arguments to C<all_files_ok>
212             are now silently discarded and the method is now configured with
213             L<XT::Files>.
214              
215             =head1 EXAMPLES
216              
217             =head2 Example 1 Default Usage
218              
219             Check all files in the F<bin>, F<script> and F<lib> directory.
220              
221             use 5.006;
222             use strict;
223             use warnings;
224              
225             use Test::RequiredMinimumDependencyVersion;
226              
227             Test::RequiredMinimumDependencyVersion->new(
228             module => {
229             'version' => '0.77',
230             },
231             )->all_files_ok;
232              
233             =head2 Example 2 Check non-default directories or files
234              
235             Use the same test file as in Example 1 and create a F<.xtfilesrc> config
236             file in the root directory of your distribution.
237              
238             [Dirs]
239             module = lib
240             module = tools
241             module = corpus/hello
242              
243             [Files]
244             module = corpus/my.pm
245              
246             =head2 Example 3 Call C<file_ok> directly
247              
248             use 5.006;
249             use strict;
250             use warnings;
251              
252             use Test::More 0.88;
253             use Test::RequiredMinimumDependencyVersion;
254              
255             my $trmdv = Test::RequiredMinimumDependencyVersion->new(
256             module => {
257             'Test::More' => '0.88',
258             },
259             );
260             $trmdv->file_ok('t/00-load.t');
261             $trmdv->file_ok('xt/author/pod-links.t');
262              
263             done_testing();
264              
265             =head1 SEE ALSO
266              
267             L<Test::More|Test::More>
268              
269             =head1 SUPPORT
270              
271             =head2 Bugs / Feature Requests
272              
273             Please report any bugs or feature requests through the issue tracker
274             at L<https://github.com/skirmess/Test-RequiredMinimumDependencyVersion/issues>.
275             You will be notified automatically of any progress on your issue.
276              
277             =head2 Source Code
278              
279             This is open source software. The code repository is available for
280             public review and contribution under the terms of the license.
281              
282             L<https://github.com/skirmess/Test-RequiredMinimumDependencyVersion>
283              
284             git clone https://github.com/skirmess/Test-RequiredMinimumDependencyVersion.git
285              
286             =head1 AUTHOR
287              
288             Sven Kirmess <sven.kirmess@kzone.ch>
289              
290             =head1 COPYRIGHT AND LICENSE
291              
292             This software is Copyright (c) 2018-2019 by Sven Kirmess.
293              
294             This is free software, licensed under:
295              
296             The (two-clause) FreeBSD License
297              
298             =cut
299              
300             # vim: ts=4 sts=4 sw=4 et: syntax=perl