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