Don't skip lines beginning by # in POD
[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
617f8754 215plan tests => 52 + 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
81ce8c82 432You can find me on the IRC channel
433#simon on irc.perl.org.
434
7a4e305a 435=cut
436---
437$dist->regen;
438
439$pm_info = Module::Metadata->new_from_module(
440 $dist->name, inc => [ 'lib', @INC ] );
441
442is( $pm_info->name, 'Simple', 'found default package' );
443is( $pm_info->version, '0.01', 'version for default package' );
444
445# got correct version for secondary package
446is( $pm_info->version( 'Simple::Ex' ), '0.02',
447 'version for secondary package' );
448
449my $filename = $pm_info->filename;
450ok( defined( $filename ) && -e $filename,
451 'filename() returns valid path to module file' );
452
453@packages = $pm_info->packages_inside;
454is( @packages, 2, 'found correct number of packages' );
455is( $packages[0], 'Simple', 'packages stored in order found' );
456
457# we can detect presence of pod regardless of whether we are collecting it
458ok( $pm_info->contains_pod, 'contains_pod() succeeds' );
459
460my @pod = $pm_info->pod_inside;
461is_deeply( \@pod, [qw(NAME AUTHOR)], 'found all pod sections' );
462
463is( $pm_info->pod('NONE') , undef,
464 'return undef() if pod section not present' );
465
466is( $pm_info->pod('NAME'), undef,
467 'return undef() if pod section not collected' );
468
469
470# collect_pod
471$pm_info = Module::Metadata->new_from_module(
472 $dist->name, inc => [ 'lib', @INC ], collect_pod => 1 );
473
617f8754 474{
475 my %pod;
476 for my $section (qw(NAME AUTHOR)) {
477 my $content = $pm_info->pod( $section );
478 if ( $content ) {
479 $content =~ s/^\s+//;
480 $content =~ s/\s+$//;
481 }
482 $pod{$section} = $content;
483 }
81ce8c82 484 my %expected = (
485 NAME => q|Simple - It's easy.|,
486 AUTHOR => <<'EXPECTED'
487Simple Simon
488
489You can find me on the IRC channel
490#simon on irc.perl.org.
491EXPECTED
492 );
493 for my $text (values %expected) {
494 $text =~ s/^\s+//;
495 $text =~ s/\s+$//;
496 }
497 is( $pod{NAME}, $expected{NAME}, 'collected NAME pod section' );
498 is( $pod{AUTHOR}, $expected{AUTHOR}, 'collected AUTHOR pod section' );
7a4e305a 499}
7a4e305a 500
501{
502 # Make sure processing stops after __DATA__
503 $dist->change_file( 'lib/Simple.pm', <<'---' );
504package Simple;
505$VERSION = '0.01';
506__DATA__
507*UNIVERSAL::VERSION = sub {
508 foo();
509};
510---
511 $dist->regen;
512
513 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
514 is( $pm_info->name, 'Simple', 'found default package' );
515 is( $pm_info->version, '0.01', 'version for default package' );
516 my @packages = $pm_info->packages_inside;
517 is_deeply(\@packages, ['Simple'], 'packages inside');
518}
519
520{
521 # Make sure we handle version.pm $VERSIONs well
522 $dist->change_file( 'lib/Simple.pm', <<'---' );
523package Simple;
524$VERSION = version->new('0.60.' . (qw$Revision: 128 $)[1]);
525package Simple::Simon;
526$VERSION = version->new('0.61.' . (qw$Revision: 129 $)[1]);
527---
528 $dist->regen;
529
530 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
531 is( $pm_info->name, 'Simple', 'found default package' );
532 is( $pm_info->version, '0.60.128', 'version for default package' );
533 my @packages = $pm_info->packages_inside;
534 is_deeply([sort @packages], ['Simple', 'Simple::Simon'], 'packages inside');
535 is( $pm_info->version('Simple::Simon'), '0.61.129', 'version for embedded package' );
536}
537
388bf282 538# check that package_versions_from_directory works
539
540$dist->change_file( 'lib/Simple.pm', <<'---' );
541package Simple;
542$VERSION = '0.01';
543package Simple::Ex;
544$VERSION = '0.02';
545{
546 package main; # should ignore this
547}
548{
549 package DB; # should ignore this
550}
551{
552 package Simple::_private; # should ignore this
553}
554
555=head1 NAME
556
557Simple - It's easy.
558
559=head1 AUTHOR
560
561Simple Simon
562
563=cut
564---
565$dist->regen;
566
567my $exp_pvfd = {
568 'Simple' => {
569 'file' => 'Simple.pm',
570 'version' => '0.01'
571 },
572 'Simple::Ex' => {
573 'file' => 'Simple.pm',
574 'version' => '0.02'
575 }
576};
577
578my $got_pvfd = Module::Metadata->package_versions_from_directory('lib');
579
ca33f3bd 580is_deeply( $got_pvfd, $exp_pvfd, "package_version_from_directory()" )
388bf282 581 or diag explain $got_pvfd;
ca33f3bd 582
583{
c06d0187 584 my $got_provides = Module::Metadata->provides(dir => 'lib', version => 2);
ca33f3bd 585 my $exp_provides = {
586 'Simple' => {
587 'file' => 'lib/Simple.pm',
588 'version' => '0.01'
589 },
590 'Simple::Ex' => {
591 'file' => 'lib/Simple.pm',
592 'version' => '0.02'
593 }
594 };
595
596 is_deeply( $got_provides, $exp_provides, "provides()" )
597 or diag explain $got_provides;
598}
599
600{
c06d0187 601 my $got_provides = Module::Metadata->provides(dir => 'lib', prefix => 'other', version => 1.4);
ca33f3bd 602 my $exp_provides = {
603 'Simple' => {
604 'file' => 'other/Simple.pm',
605 'version' => '0.01'
606 },
607 'Simple::Ex' => {
608 'file' => 'other/Simple.pm',
609 'version' => '0.02'
610 }
611 };
612
613 is_deeply( $got_provides, $exp_provides, "provides()" )
614 or diag explain $got_provides;
615}
3c614865 616
617# Check package_versions_from_directory with regard to case-sensitivity
618{
619 $dist->change_file( 'lib/Simple.pm', <<'---' );
620package simple;
621$VERSION = '0.01';
622---
623 $dist->regen;
624
625 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
626 is( $pm_info->name, undef, 'no default package' );
627 is( $pm_info->version, undef, 'version for default package' );
628 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
629 is( $pm_info->version('Simple'), undef, 'version for capitalized package' );
630
631 $dist->change_file( 'lib/Simple.pm', <<'---' );
632package simple;
633$VERSION = '0.01';
634package Simple;
635$VERSION = '0.02';
636package SiMpLe;
637$VERSION = '0.03';
638---
639 $dist->regen;
640
641 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
642 is( $pm_info->name, 'Simple', 'found default package' );
643 is( $pm_info->version, '0.02', 'version for default package' );
644 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
645 is( $pm_info->version('Simple'), '0.02', 'version for capitalized package' );
646 is( $pm_info->version('SiMpLe'), '0.03', 'version for mixed-case package' );
647}