A couple of tests about commented versions
[p5sagit/Module-Metadata.git] / t / metadata.t
CommitLineData
7a4e305a 1#!/usr/bin/perl -w
2# -*- mode: cperl; tab-width: 8; indent-tabs-mode: nil; basic-offset: 2 -*-
3# vim:ts=8:sw=2:et:sta:sts=2
4
5use strict;
6use lib 't/lib';
f33c0a6c 7use IO::File;
7a4e305a 8use MBTest;
9
975132cb 10my $undef;
11
7a4e305a 12# parse various module $VERSION lines
13# these will be reversed later to create %modules
14my @modules = (
975132cb 15 $undef => <<'---', # no $VERSION line
16package Simple;
17---
18 $undef => <<'---', # undefined $VERSION
19package Simple;
20our $VERSION;
21---
7a4e305a 22 '1.23' => <<'---', # declared & defined on same line with 'our'
23package Simple;
24our $VERSION = '1.23';
25---
26 '1.23' => <<'---', # declared & defined on separate lines with 'our'
27package Simple;
28our $VERSION;
29$VERSION = '1.23';
30---
ad924b83 31 '1.23' => <<'---', # commented & defined on same line
32package Simple;
33our $VERSION = '1.23'; # our $VERSION = '4.56';
34---
35 '1.23' => <<'---', # commented & defined on separate lines
36package Simple;
37# our $VERSION = '4.56';
38our $VERSION = '1.23';
39---
7a4e305a 40 '1.23' => <<'---', # use vars
41package Simple;
42use vars qw( $VERSION );
43$VERSION = '1.23';
44---
45 '1.23' => <<'---', # choose the right default package based on package/file name
46package Simple::_private;
47$VERSION = '0';
48package Simple;
49$VERSION = '1.23'; # this should be chosen for version
50---
51 '1.23' => <<'---', # just read the first $VERSION line
52package Simple;
53$VERSION = '1.23'; # we should see this line
54$VERSION = eval $VERSION; # and ignore this one
55---
56 '1.23' => <<'---', # just read the first $VERSION line in reopened package (1)
57package Simple;
58$VERSION = '1.23';
59package Error::Simple;
60$VERSION = '2.34';
61package Simple;
62---
63 '1.23' => <<'---', # just read the first $VERSION line in reopened package (2)
64package Simple;
65package Error::Simple;
66$VERSION = '2.34';
67package Simple;
68$VERSION = '1.23';
69---
70 '1.23' => <<'---', # mentions another module's $VERSION
71package Simple;
72$VERSION = '1.23';
73if ( $Other::VERSION ) {
74 # whatever
75}
76---
77 '1.23' => <<'---', # mentions another module's $VERSION in a different package
78package Simple;
79$VERSION = '1.23';
80package Simple2;
81if ( $Simple::VERSION ) {
82 # whatever
83}
84---
85 '1.23' => <<'---', # $VERSION checked only in assignments, not regexp ops
86package Simple;
87$VERSION = '1.23';
88if ( $VERSION =~ /1\.23/ ) {
89 # whatever
90}
91---
92 '1.23' => <<'---', # $VERSION checked only in assignments, not relational ops
93package Simple;
94$VERSION = '1.23';
95if ( $VERSION == 3.45 ) {
96 # whatever
97}
98---
99 '1.23' => <<'---', # $VERSION checked only in assignments, not relational ops
100package Simple;
101$VERSION = '1.23';
102package Simple2;
103if ( $Simple::VERSION == 3.45 ) {
104 # whatever
105}
106---
107 '1.23' => <<'---', # Fully qualified $VERSION declared in package
108package Simple;
109$Simple::VERSION = 1.23;
110---
111 '1.23' => <<'---', # Differentiate fully qualified $VERSION in a package
112package Simple;
113$Simple2::VERSION = '999';
114$Simple::VERSION = 1.23;
115---
116 '1.23' => <<'---', # Differentiate fully qualified $VERSION and unqualified
117package Simple;
118$Simple2::VERSION = '999';
119$VERSION = 1.23;
120---
121 '1.23' => <<'---', # $VERSION declared as package variable from within 'main' package
122$Simple::VERSION = '1.23';
123{
124 package Simple;
125 $x = $y, $cats = $dogs;
126}
127---
128 '1.23' => <<'---', # $VERSION wrapped in parens - space inside
129package Simple;
130( $VERSION ) = '1.23';
131---
132 '1.23' => <<'---', # $VERSION wrapped in parens - no space inside
133package Simple;
134($VERSION) = '1.23';
135---
136 '1.23' => <<'---', # $VERSION follows a spurious 'package' in a quoted construct
137package Simple;
138__PACKAGE__->mk_accessors(qw(
139 program socket proc
140 package filename line codeline subroutine finished));
141
142our $VERSION = "1.23";
143---
144 '1.23' => <<'---', # $VERSION using version.pm
145 package Simple;
146 use version; our $VERSION = version->new('1.23');
147---
148 '1.23' => <<'---', # $VERSION using version.pm and qv()
149 package Simple;
150 use version; our $VERSION = qv('1.230');
151---
152 '1.23' => <<'---', # Two version assignments, should ignore second one
153 $Simple::VERSION = '1.230';
154 $Simple::VERSION = eval $Simple::VERSION;
155---
156 '1.23' => <<'---', # declared & defined on same line with 'our'
157package Simple;
158our $VERSION = '1.23_00_00';
159---
160 '1.23' => <<'---', # package NAME VERSION
161 package Simple 1.23;
162---
163 '1.23_01' => <<'---', # package NAME VERSION
164 package Simple 1.23_01;
165---
166 'v1.2.3' => <<'---', # package NAME VERSION
167 package Simple v1.2.3;
168---
169 'v1.2_3' => <<'---', # package NAME VERSION
170 package Simple v1.2_3;
171---
92ad06ed 172 '1.23' => <<'---', # trailing crud
173 package Simple;
174 our $VERSION;
175 $VERSION = '1.23-alpha';
176---
177 '1.23' => <<'---', # trailing crud
178 package Simple;
179 our $VERSION;
180 $VERSION = '1.23b';
181---
182 '1.234' => <<'---', # multi_underscore
183 package Simple;
184 our $VERSION;
185 $VERSION = '1.2_3_4';
186---
187 '0' => <<'---', # non-numeric
188 package Simple;
189 our $VERSION;
190 $VERSION = 'onetwothree';
191---
710f253f 192 $undef => <<'---', # package NAME BLOCK, undef $VERSION
193package Simple {
194 our $VERSION;
195}
196---
197 '1.23' => <<'---', # package NAME BLOCK, with $VERSION
198package Simple {
199 our $VERSION = '1.23';
200}
201---
202 '1.23' => <<'---', # package NAME VERSION BLOCK
203package Simple 1.23 {
204 1;
205}
206---
207 'v1.2.3_4' => <<'---', # package NAME VERSION BLOCK
208package Simple v1.2.3_4 {
209 1;
210}
211---
7a4e305a 212);
213my %modules = reverse @modules;
214
3c614865 215plan tests => 51 + 2 * keys( %modules );
7a4e305a 216
217require_ok('Module::Metadata');
218
1abfcc9a 219# class method C<find_module_by_name>
220my $module = Module::Metadata->find_module_by_name(
221 'Module::Metadata' );
222ok( -e $module, 'find_module_by_name() succeeds' );
223
224#########################
225
7a4e305a 226my $tmp = MBTest->tmpdir;
227
228use DistGen;
229my $dist = DistGen->new( dir => $tmp );
230$dist->regen;
231
232$dist->chdir_in;
233
7a4e305a 234
235# fail on invalid module name
236my $pm_info = Module::Metadata->new_from_module(
237 'Foo::Bar', inc => [] );
238ok( !defined( $pm_info ), 'fail if can\'t find module by module name' );
239
240
241# fail on invalid filename
242my $file = File::Spec->catfile( 'Foo', 'Bar.pm' );
243$pm_info = Module::Metadata->new_from_file( $file, inc => [] );
244ok( !defined( $pm_info ), 'fail if can\'t find module by file name' );
245
246
247# construct from module filename
248$file = File::Spec->catfile( 'lib', split( /::/, $dist->name ) ) . '.pm';
249$pm_info = Module::Metadata->new_from_file( $file );
250ok( defined( $pm_info ), 'new_from_file() succeeds' );
251
f33c0a6c 252# construct from filehandle
253my $handle = IO::File->new($file);
254$pm_info = Module::Metadata->new_from_handle( $handle, $file );
255ok( defined( $pm_info ), 'new_from_handle() succeeds' );
256$pm_info = Module::Metadata->new_from_handle( $handle );
257is( $pm_info, undef, "new_from_handle() without filename returns undef" );
02a3d478 258close($handle);
f33c0a6c 259
7a4e305a 260# construct from module name, using custom include path
261$pm_info = Module::Metadata->new_from_module(
262 $dist->name, inc => [ 'lib', @INC ] );
263ok( defined( $pm_info ), 'new_from_module() succeeds' );
264
265
266foreach my $module ( sort keys %modules ) {
267 my $expected = $modules{$module};
268 SKIP: {
269 skip( "No our() support until perl 5.6", 2 )
270 if $] < 5.006 && $module =~ /\bour\b/;
271 skip( "No package NAME VERSION support until perl 5.11.1", 2 )
272 if $] < 5.011001 && $module =~ /package\s+[\w\:\']+\s+v?[0-9._]+/;
273
274 $dist->change_file( 'lib/Simple.pm', $module );
275 $dist->regen;
276
277 my $warnings = '';
278 local $SIG{__WARN__} = sub { $warnings .= $_ for @_ };
279 my $pm_info = Module::Metadata->new_from_file( $file );
280
281 # Test::Builder will prematurely numify objects, so use this form
282 my $errs;
975132cb 283 my $got = $pm_info->version;
284 if ( defined $expected ) {
285 ok( $got eq $expected,
286 "correct module version (expected '$expected')" )
287 or $errs++;
288 } else {
289 ok( !defined($got),
290 "correct module version (expected undef)" )
291 or $errs++;
292 }
7a4e305a 293 is( $warnings, '', 'no warnings from parsing' ) or $errs++;
975132cb 294 diag "Got: '$got'\nModule contents:\n$module" if $errs;
7a4e305a 295 }
296}
297
298# revert to pristine state
299$dist->regen( clean => 1 );
300
301# Find each package only once
302$dist->change_file( 'lib/Simple.pm', <<'---' );
303package Simple;
304$VERSION = '1.23';
305package Error::Simple;
306$VERSION = '2.34';
307package Simple;
308---
309
310$dist->regen;
311
312$pm_info = Module::Metadata->new_from_file( $file );
313
314my @packages = $pm_info->packages_inside;
315is( @packages, 2, 'record only one occurence of each package' );
316
317
318# Module 'Simple.pm' does not contain package 'Simple';
319# constructor should not complain, no default module name or version
320$dist->change_file( 'lib/Simple.pm', <<'---' );
321package Simple::Not;
322$VERSION = '1.23';
323---
324
325$dist->regen;
326$pm_info = Module::Metadata->new_from_file( $file );
327
328is( $pm_info->name, undef, 'no default package' );
329is( $pm_info->version, undef, 'no version w/o default package' );
330
331# Module 'Simple.pm' contains an alpha version
332# constructor should report first $VERSION found
333$dist->change_file( 'lib/Simple.pm', <<'---' );
334package Simple;
335$VERSION = '1.23_01';
336$VERSION = eval $VERSION;
337---
338
339$dist->regen;
340$pm_info = Module::Metadata->new_from_file( $file );
341
342is( $pm_info->version, '1.23_01', 'alpha version reported');
343
344# NOTE the following test has be done this way because Test::Builder is
345# too smart for our own good and tries to see if the version object is a
346# dual-var, which breaks with alpha versions:
347# Argument "1.23_0100" isn't numeric in addition (+) at
348# /usr/lib/perl5/5.8.7/Test/Builder.pm line 505.
349
350ok( $pm_info->version > 1.23, 'alpha version greater than non');
351
352# revert to pristine state
353$dist->regen( clean => 1 );
354
355# parse $VERSION lines scripts for package main
356my @scripts = (
357 <<'---', # package main declared
358#!perl -w
359package main;
360$VERSION = '0.01';
361---
362 <<'---', # on first non-comment line, non declared package main
363#!perl -w
364$VERSION = '0.01';
365---
366 <<'---', # after non-comment line
367#!perl -w
368use strict;
369$VERSION = '0.01';
370---
371 <<'---', # 1st declared package
372#!perl -w
373package main;
374$VERSION = '0.01';
375package _private;
376$VERSION = '999';
377---
378 <<'---', # 2nd declared package
379#!perl -w
380package _private;
381$VERSION = '999';
382package main;
383$VERSION = '0.01';
384---
385 <<'---', # split package
386#!perl -w
387package main;
388package _private;
389$VERSION = '999';
390package main;
391$VERSION = '0.01';
392---
393 <<'---', # define 'main' version from other package
394package _private;
395$::VERSION = 0.01;
396$VERSION = '999';
397---
398 <<'---', # define 'main' version from other package
399package _private;
400$VERSION = '999';
401$::VERSION = 0.01;
402---
403);
404
405my ( $i, $n ) = ( 1, scalar( @scripts ) );
406foreach my $script ( @scripts ) {
407 $dist->change_file( 'bin/simple.plx', $script );
408 $dist->regen;
409 $pm_info = Module::Metadata->new_from_file(
410 File::Spec->catfile( 'bin', 'simple.plx' ) );
411
412 is( $pm_info->version, '0.01', "correct script version ($i of $n)" );
413 $i++;
414}
415
416
417# examine properties of a module: name, pod, etc
418$dist->change_file( 'lib/Simple.pm', <<'---' );
419package Simple;
420$VERSION = '0.01';
421package Simple::Ex;
422$VERSION = '0.02';
388bf282 423
7a4e305a 424=head1 NAME
425
426Simple - It's easy.
427
428=head1 AUTHOR
429
430Simple Simon
431
432=cut
433---
434$dist->regen;
435
436$pm_info = Module::Metadata->new_from_module(
437 $dist->name, inc => [ 'lib', @INC ] );
438
439is( $pm_info->name, 'Simple', 'found default package' );
440is( $pm_info->version, '0.01', 'version for default package' );
441
442# got correct version for secondary package
443is( $pm_info->version( 'Simple::Ex' ), '0.02',
444 'version for secondary package' );
445
446my $filename = $pm_info->filename;
447ok( defined( $filename ) && -e $filename,
448 'filename() returns valid path to module file' );
449
450@packages = $pm_info->packages_inside;
451is( @packages, 2, 'found correct number of packages' );
452is( $packages[0], 'Simple', 'packages stored in order found' );
453
454# we can detect presence of pod regardless of whether we are collecting it
455ok( $pm_info->contains_pod, 'contains_pod() succeeds' );
456
457my @pod = $pm_info->pod_inside;
458is_deeply( \@pod, [qw(NAME AUTHOR)], 'found all pod sections' );
459
460is( $pm_info->pod('NONE') , undef,
461 'return undef() if pod section not present' );
462
463is( $pm_info->pod('NAME'), undef,
464 'return undef() if pod section not collected' );
465
466
467# collect_pod
468$pm_info = Module::Metadata->new_from_module(
469 $dist->name, inc => [ 'lib', @INC ], collect_pod => 1 );
470
471my $name = $pm_info->pod('NAME');
472if ( $name ) {
473 $name =~ s/^\s+//;
474 $name =~ s/\s+$//;
475}
476is( $name, q|Simple - It's easy.|, 'collected pod section' );
477
478
479{
480 # Make sure processing stops after __DATA__
481 $dist->change_file( 'lib/Simple.pm', <<'---' );
482package Simple;
483$VERSION = '0.01';
484__DATA__
485*UNIVERSAL::VERSION = sub {
486 foo();
487};
488---
489 $dist->regen;
490
491 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
492 is( $pm_info->name, 'Simple', 'found default package' );
493 is( $pm_info->version, '0.01', 'version for default package' );
494 my @packages = $pm_info->packages_inside;
495 is_deeply(\@packages, ['Simple'], 'packages inside');
496}
497
498{
499 # Make sure we handle version.pm $VERSIONs well
500 $dist->change_file( 'lib/Simple.pm', <<'---' );
501package Simple;
502$VERSION = version->new('0.60.' . (qw$Revision: 128 $)[1]);
503package Simple::Simon;
504$VERSION = version->new('0.61.' . (qw$Revision: 129 $)[1]);
505---
506 $dist->regen;
507
508 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
509 is( $pm_info->name, 'Simple', 'found default package' );
510 is( $pm_info->version, '0.60.128', 'version for default package' );
511 my @packages = $pm_info->packages_inside;
512 is_deeply([sort @packages], ['Simple', 'Simple::Simon'], 'packages inside');
513 is( $pm_info->version('Simple::Simon'), '0.61.129', 'version for embedded package' );
514}
515
388bf282 516# check that package_versions_from_directory works
517
518$dist->change_file( 'lib/Simple.pm', <<'---' );
519package Simple;
520$VERSION = '0.01';
521package Simple::Ex;
522$VERSION = '0.02';
523{
524 package main; # should ignore this
525}
526{
527 package DB; # should ignore this
528}
529{
530 package Simple::_private; # should ignore this
531}
532
533=head1 NAME
534
535Simple - It's easy.
536
537=head1 AUTHOR
538
539Simple Simon
540
541=cut
542---
543$dist->regen;
544
545my $exp_pvfd = {
546 'Simple' => {
547 'file' => 'Simple.pm',
548 'version' => '0.01'
549 },
550 'Simple::Ex' => {
551 'file' => 'Simple.pm',
552 'version' => '0.02'
553 }
554};
555
556my $got_pvfd = Module::Metadata->package_versions_from_directory('lib');
557
ca33f3bd 558is_deeply( $got_pvfd, $exp_pvfd, "package_version_from_directory()" )
388bf282 559 or diag explain $got_pvfd;
ca33f3bd 560
561{
c06d0187 562 my $got_provides = Module::Metadata->provides(dir => 'lib', version => 2);
ca33f3bd 563 my $exp_provides = {
564 'Simple' => {
565 'file' => 'lib/Simple.pm',
566 'version' => '0.01'
567 },
568 'Simple::Ex' => {
569 'file' => 'lib/Simple.pm',
570 'version' => '0.02'
571 }
572 };
573
574 is_deeply( $got_provides, $exp_provides, "provides()" )
575 or diag explain $got_provides;
576}
577
578{
c06d0187 579 my $got_provides = Module::Metadata->provides(dir => 'lib', prefix => 'other', version => 1.4);
ca33f3bd 580 my $exp_provides = {
581 'Simple' => {
582 'file' => 'other/Simple.pm',
583 'version' => '0.01'
584 },
585 'Simple::Ex' => {
586 'file' => 'other/Simple.pm',
587 'version' => '0.02'
588 }
589 };
590
591 is_deeply( $got_provides, $exp_provides, "provides()" )
592 or diag explain $got_provides;
593}
3c614865 594
595# Check package_versions_from_directory with regard to case-sensitivity
596{
597 $dist->change_file( 'lib/Simple.pm', <<'---' );
598package simple;
599$VERSION = '0.01';
600---
601 $dist->regen;
602
603 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
604 is( $pm_info->name, undef, 'no default package' );
605 is( $pm_info->version, undef, 'version for default package' );
606 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
607 is( $pm_info->version('Simple'), undef, 'version for capitalized package' );
608
609 $dist->change_file( 'lib/Simple.pm', <<'---' );
610package simple;
611$VERSION = '0.01';
612package Simple;
613$VERSION = '0.02';
614package SiMpLe;
615$VERSION = '0.03';
616---
617 $dist->regen;
618
619 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
620 is( $pm_info->name, 'Simple', 'found default package' );
621 is( $pm_info->version, '0.02', 'version for default package' );
622 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
623 is( $pm_info->version('Simple'), '0.02', 'version for capitalized package' );
624 is( $pm_info->version('SiMpLe'), '0.03', 'version for mixed-case package' );
625}