File Coverage

blib/lib/Test/GreaterVersion.pm
Criterion Covered Total %
statement 93 101 92.0
branch 21 28 75.0
condition 1 3 33.3
subroutine 17 17 100.0
pod 2 2 100.0
total 134 151 88.7


line stmt bran cond sub pod time code
1             package Test::GreaterVersion;
2              
3             =head1 NAME
4              
5             Test::GreaterVersion -- Test if you incremented VERSION
6              
7             =head1 SYNOPSIS
8              
9             has_greater_version('My::Module');
10              
11             has_greater_version_than_cpan('My::Module');
12            
13             =head1 DESCRIPTION
14              
15             There are two functions which are supposed to be used
16             in your automated release suites to assure that you incremented your
17             version before your install the module or upload it to CPAN.
18              
19             C checks if your module source has a greater
20             VERSION number than the version installed in the system.
21              
22             C checks if your module source has
23             a greater VERSION number than the version found on CPAN.
24              
25             The version is checked by looking for the VERSION scalar in the
26             module. The names of these two functions are always exported.
27              
28             The two test functions expect your module files layed out in
29             the standard way, i.e. tests are called in the top directory and
30             module if found in the C directory:
31              
32             Module Path
33             doc
34             examples
35             lib
36             t
37              
38             The version of My::Module is therefore expected in the file
39             C. There's currently no way to alter that
40             location. (The file name is OS independent via the magic of
41             L.)
42              
43             The version information is actually parsed by
44             L.
45              
46             The version numbers are compared calling
47             C. See L or L
48             for version number syntax. (Short: Both 1.00203 and v1.2.30 work.)
49              
50             Please note that these test functions should not be put in normal
51             test script below C. They will usually break the tests.
52             These functions are to be put in some install script to check the
53             versions automatically.
54              
55             =cut
56              
57 6     6   5100 use strict;
  6         13  
  6         231  
58 6     6   34 use warnings;
  6         9  
  6         194  
59              
60 6     6   8395 use ExtUtils::MakeMaker;
  6         691217  
  6         1053  
61 6     6   28558 use CPAN;
  6         1576001  
  6         9251  
62 6     6   195 use CPAN::Version;
  6         40  
  6         246  
63 6     6   60 use Cwd;
  6         34  
  6         1036  
64 6     6   65 use File::Spec;
  6         22  
  6         439  
65 6     6   53 use Test::Builder;
  6         30  
  6         399  
66              
67 6     6   50 use base qw(Exporter);
  6         20  
  6         26640  
68             our @EXPORT = qw(has_greater_version
69             has_greater_version_than_cpan);
70              
71             our $VERSION = 0.010;
72              
73             # the development version of the module is expected
74             # to be below this directory
75             our $libdir = 'lib';
76              
77             our $Test = Test::Builder->new;
78              
79             sub import {
80 6     6   153 my ($self) = shift;
81 6         24 my $pack = caller;
82              
83 6         103 $Test->exported_to($pack);
84 6         145 $Test->plan(@_);
85              
86 6         1870 $self->export_to_level( 1, $self, 'has_greater_version' );
87 6         521 $self->export_to_level( 1, $self, 'has_greater_version_than_cpan' );
88             }
89              
90             =head1 FUNCTIONS
91              
92             =head2 has_greater_version ($module)
93              
94             Returns 1 if your module in 'lib/' has a version and if
95             it is greater than the version of the installed module,
96             0 otherwise.
97              
98             1 is also returned if the module is not installed, i.e. your
99             module is new.
100              
101             1 is also returned if the module is installed but has no version
102             defined, i.e. your module in 'lib/' is a fix of this bug.
103              
104             =cut
105              
106             sub has_greater_version {
107 5     5 1 3829 my ($module) = @_;
108              
109             # fail if the module's name is missing
110 5 100       27 unless ($module) {
111 1         5 return $Test->diag("You didn't specify a module name");
112             }
113              
114 4         15 my $version_from_lib = _get_version_from_lib($module);
115 4 100       12 unless (defined $version_from_lib) {
116             # fail if module is not in lib
117 2         129 return $Test->diag('module is not in lib');
118             }
119              
120 2 100       8 if ($version_from_lib eq 'undef') {
121             # fail if module has no version
122 1         5 return $Test->diag('module in lib has no version');
123             }
124              
125             # so the module in lib has a version
126 1         11 $Test->diag('module is in lib and has version');
127              
128 1         120 my $version_installed = _get_installed_version($module);
129 1 50       5 unless (defined $version_installed) {
130 1         5 $Test->diag('module is not installed');
131              
132             # module doesn't seem to be installed, that's okay --
133             # it might be new
134 1         71 return 1;
135             }
136              
137 0 0       0 if ($version_installed eq 'undef') {
138 0         0 $Test->diag('version of installed module is not defined');
139              
140             # installed module seems to have no version, that's okay
141             # if the module in lib has
142 0         0 return 1;
143             }
144            
145             # so the installed module has a version, too
146 0         0 $Test->diag('module is installed and has version');
147             # let's compare them
148            
149 0         0 $Test->ok( CPAN::Version->vgt( $version_from_lib, $version_installed ),
150             "$module has greater version" );
151             }
152              
153             =head2 has_greater_version_than_cpan ($module)
154              
155             Returns 1 if your module in 'lib/' has a version and if
156             it is greater than the module's version on CPAN,
157             0 otherwise.
158              
159             1 is also returned if the module is there is no CPAN
160             information available for your module, i.e. your
161             module is new and will be the first release to CPAN or
162             has no version defined.
163              
164             Due to the interface of the CPAN module there's currently
165             no way to tell if the module is not on CPAN or if there
166             has been an error in getting the module information from CPAN.
167             As a result this function should only be called if you are
168             sure that there's a version of the module on CPAN.
169              
170             Depending on the configuration of your CPAN shell the first
171             call of this function may seem to block the test. When
172             you notice this behaviour it's likely that the CPAN shell is
173             trying to get the latest module index which may take some time.
174              
175             Please note also that depending on your CPAN mirror the module
176             information might be up to date or not.
177              
178             =cut
179              
180             sub has_greater_version_than_cpan {
181 5     5 1 4509 my ($module) = @_;
182              
183             # fail if the module's name is missing
184 5 100       20 unless ($module) {
185 1         5 return $Test->diag('You didn\'t specify a module name');
186             }
187              
188 4         13 my $version_from_lib = _get_version_from_lib($module);
189 4 100       13 unless (defined $version_from_lib) {
190             # fail if module is not in lib
191 2         9 return $Test->diag('module is not in lib');
192             }
193              
194 2 100       14 if ($version_from_lib eq 'undef') {
195             # fail if module has no version
196 1         6 return $Test->diag('module in lib has no version');
197             }
198              
199             # so the module in lib has a version
200 1         5 $Test->diag('module is in lib and has version');
201              
202 1         176 my $cpan_version = _get_version_from_cpan($module);
203 1 50       8 unless ($cpan_version) {
204 1         5 $Test->diag('module is not on CPAN or has no version');
205              
206             # module doesn't seem to be on CPAN, that's okay --
207             # it might be new. If it has no version that's okay,
208             # too -- we have one
209 1         141 return 1;
210             }
211            
212             # so the module on CPAN has a version, too
213 0         0 $Test->diag('module is on CPAN and has version');
214             # let's compare them
215              
216 0         0 $Test->ok( CPAN::Version->vgt( $version_from_lib, $cpan_version ),
217             "$module has greater version than on CPAN" );
218             }
219              
220             =head1 INTERNAL FUNCTIONS
221              
222             These are not to be called by anyone.
223              
224             =head2 _get_installed_version ($module)
225              
226             Gets the version of the installed module. The version
227             information is found with the help of the CPAN module.
228              
229             Returns undef if the file doesn't exist.
230             Returns 'undef' (yes, the string) if it has no version.
231             Returns the version otherwise.
232              
233             We don't use CPAN::Shell::inst_version() since it doesn't
234             remove blib before searching for the version and
235             we want to have a diag() output in the test. And because
236             the manpage doesn't list the function in the stable
237             interface.
238              
239             =cut
240              
241             sub _get_installed_version {
242 4     4   3846 my ($module) = @_;
243              
244             # Strip blib from @INC so the CPAN::Shell
245             # won't find the module even if it's there.
246             # (Tests add blib to @INC).
247             # Localize @INC so we won't affect others
248 4         11 local @INC = grep { $_ !~ /blib/ } @INC;
  46         142  
249              
250 4         14 my $file = _module_to_file($module);
251              
252 4         9 my $bestv;
253 4         10 for my $incdir (@INC) {
254 22         435 my $bfile = File::Spec->catfile( $incdir, $file );
255              
256             # skip if it's not a file
257 22 100       2425 next unless -f $bfile;
258              
259             # get the version
260 2         296 my $foundv = MM->parse_version($bfile);
261              
262             # remember which version is greatest
263 2 50 33     727 if ( !$bestv || CPAN::Version->vgt( $foundv, $bestv ) ) {
264 2         6 $bestv = $foundv;
265             }
266             }
267              
268 4         18 return $bestv;
269             }
270              
271             =head2 _get_version_from_lib ($module)
272              
273             Gets the version of the module found in 'lib/'.
274             Transforms the module name into a filename which points
275             to a file found under 'lib/'.
276              
277             Cparse_version()> tries to find the version.
278              
279             Returns undef if the file doesn't exist.
280             Returns 'undef' (yes, the string) if it has no version.
281             Returns the version otherwise.
282              
283             =cut
284              
285             sub _get_version_from_lib {
286 11     11   4867 my $module = shift;
287              
288 11         91 my $cwd = getcwd();
289 11         38 my $file =
290             File::Spec->catfile( $cwd, $libdir, _module_to_file($module));
291              
292 11 100       521 unless (-f $file) {
293 5         37 $Test->diag("file '$file' doesn't exist");
294 5         803 return;
295             }
296            
297             # try to get the version
298 6     6   32 my $code = sub { MM->parse_version($file) };
  6         236  
299 6         31 my ( $version, $error ) = $Test->_try($code);
300              
301             # fail on errors
302 6 50       3745 return $Test->diag("parse_version had errors: $@")
303             if $error;
304              
305 6         35 return $version;
306              
307             }
308              
309             # convert module name to file under lib (OS-independent)
310             sub _module_to_file {
311 15     15   60 my ($module) = @_;
312              
313             # get list of components
314 15         68 my @components = split( /::/, $module );
315              
316             # a/b.pm under UNI* for 'a::b'
317 15         349 my $file=File::Spec->catfile(@components);
318              
319 15         212 return "$file.pm";
320             }
321              
322             =head2 _get_version_from_cpan ($module)
323              
324             Gets the module's version as found on CPAN. The version
325             information is found with the help of the CPAN module.
326              
327             Returns undef if the module is not on CPAN or the CPAN module
328             failed somehow. Returns the version otherwise.
329              
330             =cut
331              
332             sub _get_version_from_cpan {
333 1     1   3 my ($module) = @_;
334              
335             # Turn off coloured output of the CPAN shell.
336             # This breaks the test/Harness/whatever.
337 1         22 CPAN::HandleConfig->load();
338 1         619 $CPAN::Config->{colorize_output} = 0;
339              
340             # taken from CPAN manpage
341 1         16 my $m = CPAN::Shell->expand( 'Module', $module );
342              
343             # the module is not on CPAN or something broke
344 1 50       3464960 unless ($m) {
345 1         14 $Test->diag("CPAN-version of '$module' not available");
346 1         214 return;
347             }
348              
349             # there is a version on CPAN
350 0           return $m->cpan_version();
351             }
352              
353             =head1 NOTES
354              
355             This module was inspired by brian d foy's talk
356             'Managing Complexity with Module::Release' at the Nordic Perl
357             Workshop in 2006.
358              
359             =head1 TODO
360              
361             It might be nice that has_greater_version() and
362             has_greater_version_than_cpan() wouldn't fail on equal versions
363             if the modules source code is equal, too. Thanks to Slaven Rezic
364             for that suggestion. That way the tests could be used in a normal
365             test suite.
366              
367              
368             =head1 AUTHOR
369              
370             Gregor Goldbach
371              
372             =head1 SIMILAR MODULES
373              
374             L tests if there is a VERSION defined.
375              
376             L does it, too, but has the ability to
377             check all Perl modules in C.
378              
379             Neither of these compare versions.
380              
381             =head1 COPYRIGHT
382              
383             Copyright (c) 2007 by Gregor Goldbach. All rights reserved.
384              
385             This program is free software; you can redistribute it and/or modify it
386             under the same terms as Perl itself.
387              
388             =cut
389              
390             1;