set v2 metadata (RT#88028)
[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
8e4bef01 215my @pkg_names = (
216 [ 'Simple' ] => <<'---', # package NAME
217package Simple;
218---
219 [ 'Simple::Edward' ] => <<'---', # package NAME::SUBNAME
220package Simple::Edward;
221---
222 [ 'Simple::Edward::' ] => <<'---', # package NAME::SUBNAME::
223package Simple::Edward::;
224---
225 [ "Simple'Edward" ] => <<'---', # package NAME'SUBNAME
226package Simple'Edward;
227---
228 [ "Simple'Edward::" ] => <<'---', # package NAME'SUBNAME::
229package Simple'Edward::;
230---
231 [ 'Simple::::Edward' ] => <<'---', # package NAME::::SUBNAME
232package Simple::::Edward;
233---
234 [ '::Simple::Edward' ] => <<'---', # package ::NAME::SUBNAME
235package ::Simple::Edward;
236---
237 [ 'main' ] => <<'---', # package NAME:SUBNAME (fail)
238package Simple:Edward;
239---
240 [ 'main' ] => <<'---', # package NAME' (fail)
241package Simple';
242---
243 [ 'main' ] => <<'---', # package NAME::SUBNAME' (fail)
244package Simple::Edward';
245---
246 [ 'main' ] => <<'---', # package NAME''SUBNAME (fail)
247package Simple''Edward;
248---
249 [ 'main' ] => <<'---', # package NAME-SUBNAME (fail)
250package Simple-Edward;
251---
252);
253my %pkg_names = reverse @pkg_names;
254
255plan tests => 54 + (2 * keys( %modules )) + (2 * keys( %pkg_names ));
7a4e305a 256
257require_ok('Module::Metadata');
258
1abfcc9a 259# class method C<find_module_by_name>
260my $module = Module::Metadata->find_module_by_name(
261 'Module::Metadata' );
262ok( -e $module, 'find_module_by_name() succeeds' );
263
264#########################
265
7a4e305a 266my $tmp = MBTest->tmpdir;
267
268use DistGen;
269my $dist = DistGen->new( dir => $tmp );
270$dist->regen;
271
272$dist->chdir_in;
273
7a4e305a 274
275# fail on invalid module name
276my $pm_info = Module::Metadata->new_from_module(
277 'Foo::Bar', inc => [] );
278ok( !defined( $pm_info ), 'fail if can\'t find module by module name' );
279
280
281# fail on invalid filename
282my $file = File::Spec->catfile( 'Foo', 'Bar.pm' );
283$pm_info = Module::Metadata->new_from_file( $file, inc => [] );
284ok( !defined( $pm_info ), 'fail if can\'t find module by file name' );
285
286
287# construct from module filename
288$file = File::Spec->catfile( 'lib', split( /::/, $dist->name ) ) . '.pm';
289$pm_info = Module::Metadata->new_from_file( $file );
290ok( defined( $pm_info ), 'new_from_file() succeeds' );
291
f33c0a6c 292# construct from filehandle
293my $handle = IO::File->new($file);
294$pm_info = Module::Metadata->new_from_handle( $handle, $file );
295ok( defined( $pm_info ), 'new_from_handle() succeeds' );
296$pm_info = Module::Metadata->new_from_handle( $handle );
297is( $pm_info, undef, "new_from_handle() without filename returns undef" );
02a3d478 298close($handle);
f33c0a6c 299
7a4e305a 300# construct from module name, using custom include path
301$pm_info = Module::Metadata->new_from_module(
302 $dist->name, inc => [ 'lib', @INC ] );
303ok( defined( $pm_info ), 'new_from_module() succeeds' );
304
305
306foreach my $module ( sort keys %modules ) {
307 my $expected = $modules{$module};
308 SKIP: {
309 skip( "No our() support until perl 5.6", 2 )
310 if $] < 5.006 && $module =~ /\bour\b/;
311 skip( "No package NAME VERSION support until perl 5.11.1", 2 )
312 if $] < 5.011001 && $module =~ /package\s+[\w\:\']+\s+v?[0-9._]+/;
313
314 $dist->change_file( 'lib/Simple.pm', $module );
315 $dist->regen;
316
317 my $warnings = '';
318 local $SIG{__WARN__} = sub { $warnings .= $_ for @_ };
319 my $pm_info = Module::Metadata->new_from_file( $file );
320
321 # Test::Builder will prematurely numify objects, so use this form
322 my $errs;
975132cb 323 my $got = $pm_info->version;
324 if ( defined $expected ) {
325 ok( $got eq $expected,
326 "correct module version (expected '$expected')" )
327 or $errs++;
328 } else {
329 ok( !defined($got),
330 "correct module version (expected undef)" )
331 or $errs++;
332 }
7a4e305a 333 is( $warnings, '', 'no warnings from parsing' ) or $errs++;
975132cb 334 diag "Got: '$got'\nModule contents:\n$module" if $errs;
7a4e305a 335 }
336}
337
338# revert to pristine state
8e4bef01 339$dist->regen( clean => 1 );
340
341foreach my $pkg_name ( sort keys %pkg_names ) {
342 my $expected = $pkg_names{$pkg_name};
343
344 $dist->change_file( 'lib/Simple.pm', $pkg_name );
345 $dist->regen;
346
347 my $warnings = '';
348 local $SIG{__WARN__} = sub { $warnings .= $_ for @_ };
349 my $pm_info = Module::Metadata->new_from_file( $file );
350
351 # Test::Builder will prematurely numify objects, so use this form
352 my $errs;
353 my @got = $pm_info->packages_inside();
354 is_deeply( \@got, $expected,
355 "correct package names (expected '" . join(', ', @$expected) . "')" )
356 or $errs++;
357 is( $warnings, '', 'no warnings from parsing' ) or $errs++;
358 diag "Got: '" . join(', ', @got) . "'\nModule contents:\n$pkg_name" if $errs;
359}
360
361# revert to pristine state
7a4e305a 362$dist->regen( clean => 1 );
363
364# Find each package only once
365$dist->change_file( 'lib/Simple.pm', <<'---' );
366package Simple;
367$VERSION = '1.23';
368package Error::Simple;
369$VERSION = '2.34';
370package Simple;
371---
372
373$dist->regen;
374
375$pm_info = Module::Metadata->new_from_file( $file );
376
377my @packages = $pm_info->packages_inside;
378is( @packages, 2, 'record only one occurence of each package' );
379
380
381# Module 'Simple.pm' does not contain package 'Simple';
382# constructor should not complain, no default module name or version
383$dist->change_file( 'lib/Simple.pm', <<'---' );
384package Simple::Not;
385$VERSION = '1.23';
386---
387
388$dist->regen;
389$pm_info = Module::Metadata->new_from_file( $file );
390
391is( $pm_info->name, undef, 'no default package' );
392is( $pm_info->version, undef, 'no version w/o default package' );
393
394# Module 'Simple.pm' contains an alpha version
395# constructor should report first $VERSION found
396$dist->change_file( 'lib/Simple.pm', <<'---' );
397package Simple;
398$VERSION = '1.23_01';
399$VERSION = eval $VERSION;
400---
401
402$dist->regen;
403$pm_info = Module::Metadata->new_from_file( $file );
404
405is( $pm_info->version, '1.23_01', 'alpha version reported');
406
407# NOTE the following test has be done this way because Test::Builder is
408# too smart for our own good and tries to see if the version object is a
409# dual-var, which breaks with alpha versions:
410# Argument "1.23_0100" isn't numeric in addition (+) at
411# /usr/lib/perl5/5.8.7/Test/Builder.pm line 505.
412
413ok( $pm_info->version > 1.23, 'alpha version greater than non');
414
415# revert to pristine state
416$dist->regen( clean => 1 );
417
418# parse $VERSION lines scripts for package main
419my @scripts = (
420 <<'---', # package main declared
421#!perl -w
422package main;
423$VERSION = '0.01';
424---
425 <<'---', # on first non-comment line, non declared package main
426#!perl -w
427$VERSION = '0.01';
428---
429 <<'---', # after non-comment line
430#!perl -w
431use strict;
432$VERSION = '0.01';
433---
434 <<'---', # 1st declared package
435#!perl -w
436package main;
437$VERSION = '0.01';
438package _private;
439$VERSION = '999';
440---
441 <<'---', # 2nd declared package
442#!perl -w
443package _private;
444$VERSION = '999';
445package main;
446$VERSION = '0.01';
447---
448 <<'---', # split package
449#!perl -w
450package main;
451package _private;
452$VERSION = '999';
453package main;
454$VERSION = '0.01';
455---
456 <<'---', # define 'main' version from other package
457package _private;
458$::VERSION = 0.01;
459$VERSION = '999';
460---
461 <<'---', # define 'main' version from other package
462package _private;
463$VERSION = '999';
464$::VERSION = 0.01;
465---
466);
467
468my ( $i, $n ) = ( 1, scalar( @scripts ) );
469foreach my $script ( @scripts ) {
470 $dist->change_file( 'bin/simple.plx', $script );
471 $dist->regen;
472 $pm_info = Module::Metadata->new_from_file(
473 File::Spec->catfile( 'bin', 'simple.plx' ) );
474
475 is( $pm_info->version, '0.01', "correct script version ($i of $n)" );
476 $i++;
477}
478
479
480# examine properties of a module: name, pod, etc
481$dist->change_file( 'lib/Simple.pm', <<'---' );
482package Simple;
483$VERSION = '0.01';
484package Simple::Ex;
485$VERSION = '0.02';
388bf282 486
7a4e305a 487=head1 NAME
488
489Simple - It's easy.
490
491=head1 AUTHOR
492
493Simple Simon
494
81ce8c82 495You can find me on the IRC channel
496#simon on irc.perl.org.
497
7a4e305a 498=cut
499---
500$dist->regen;
501
502$pm_info = Module::Metadata->new_from_module(
503 $dist->name, inc => [ 'lib', @INC ] );
504
505is( $pm_info->name, 'Simple', 'found default package' );
506is( $pm_info->version, '0.01', 'version for default package' );
507
508# got correct version for secondary package
509is( $pm_info->version( 'Simple::Ex' ), '0.02',
510 'version for secondary package' );
511
512my $filename = $pm_info->filename;
513ok( defined( $filename ) && -e $filename,
514 'filename() returns valid path to module file' );
515
516@packages = $pm_info->packages_inside;
517is( @packages, 2, 'found correct number of packages' );
518is( $packages[0], 'Simple', 'packages stored in order found' );
519
520# we can detect presence of pod regardless of whether we are collecting it
521ok( $pm_info->contains_pod, 'contains_pod() succeeds' );
522
523my @pod = $pm_info->pod_inside;
524is_deeply( \@pod, [qw(NAME AUTHOR)], 'found all pod sections' );
525
526is( $pm_info->pod('NONE') , undef,
527 'return undef() if pod section not present' );
528
529is( $pm_info->pod('NAME'), undef,
530 'return undef() if pod section not collected' );
531
532
533# collect_pod
534$pm_info = Module::Metadata->new_from_module(
535 $dist->name, inc => [ 'lib', @INC ], collect_pod => 1 );
536
617f8754 537{
538 my %pod;
539 for my $section (qw(NAME AUTHOR)) {
540 my $content = $pm_info->pod( $section );
541 if ( $content ) {
542 $content =~ s/^\s+//;
543 $content =~ s/\s+$//;
544 }
545 $pod{$section} = $content;
546 }
81ce8c82 547 my %expected = (
548 NAME => q|Simple - It's easy.|,
549 AUTHOR => <<'EXPECTED'
550Simple Simon
551
552You can find me on the IRC channel
553#simon on irc.perl.org.
554EXPECTED
555 );
556 for my $text (values %expected) {
557 $text =~ s/^\s+//;
558 $text =~ s/\s+$//;
559 }
560 is( $pod{NAME}, $expected{NAME}, 'collected NAME pod section' );
561 is( $pod{AUTHOR}, $expected{AUTHOR}, 'collected AUTHOR pod section' );
7a4e305a 562}
7a4e305a 563
564{
a4aafbc2 565 # test things that look like POD, but aren't
566$dist->change_file( 'lib/Simple.pm', <<'---' );
567package Simple;
a4aafbc2 568
cfedad89 569=YES THIS STARTS POD
570
571our $VERSION = '999';
a4aafbc2 572
a4aafbc2 573=cute
a4aafbc2 574
cfedad89 575our $VERSION = '666';
576
577=cut
578
579*foo
580=*no_this_does_not_start_pod;
581
582our $VERSION = '1.23';
a4aafbc2 583
584---
585 $dist->regen;
586 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
587 is( $pm_info->name, 'Simple', 'found default package' );
588 is( $pm_info->version, '1.23', 'version for default package' );
589}
590
591{
7a4e305a 592 # Make sure processing stops after __DATA__
593 $dist->change_file( 'lib/Simple.pm', <<'---' );
594package Simple;
595$VERSION = '0.01';
596__DATA__
597*UNIVERSAL::VERSION = sub {
598 foo();
599};
600---
601 $dist->regen;
602
603 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
604 is( $pm_info->name, 'Simple', 'found default package' );
605 is( $pm_info->version, '0.01', 'version for default package' );
606 my @packages = $pm_info->packages_inside;
607 is_deeply(\@packages, ['Simple'], 'packages inside');
608}
609
610{
611 # Make sure we handle version.pm $VERSIONs well
612 $dist->change_file( 'lib/Simple.pm', <<'---' );
613package Simple;
614$VERSION = version->new('0.60.' . (qw$Revision: 128 $)[1]);
615package Simple::Simon;
616$VERSION = version->new('0.61.' . (qw$Revision: 129 $)[1]);
617---
618 $dist->regen;
619
620 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
621 is( $pm_info->name, 'Simple', 'found default package' );
622 is( $pm_info->version, '0.60.128', 'version for default package' );
623 my @packages = $pm_info->packages_inside;
624 is_deeply([sort @packages], ['Simple', 'Simple::Simon'], 'packages inside');
625 is( $pm_info->version('Simple::Simon'), '0.61.129', 'version for embedded package' );
626}
627
388bf282 628# check that package_versions_from_directory works
629
630$dist->change_file( 'lib/Simple.pm', <<'---' );
631package Simple;
632$VERSION = '0.01';
633package Simple::Ex;
634$VERSION = '0.02';
635{
636 package main; # should ignore this
637}
638{
639 package DB; # should ignore this
640}
641{
642 package Simple::_private; # should ignore this
643}
644
645=head1 NAME
646
647Simple - It's easy.
648
649=head1 AUTHOR
650
651Simple Simon
652
653=cut
654---
655$dist->regen;
656
657my $exp_pvfd = {
658 'Simple' => {
659 'file' => 'Simple.pm',
660 'version' => '0.01'
661 },
662 'Simple::Ex' => {
663 'file' => 'Simple.pm',
664 'version' => '0.02'
665 }
666};
667
668my $got_pvfd = Module::Metadata->package_versions_from_directory('lib');
669
ca33f3bd 670is_deeply( $got_pvfd, $exp_pvfd, "package_version_from_directory()" )
388bf282 671 or diag explain $got_pvfd;
ca33f3bd 672
673{
c06d0187 674 my $got_provides = Module::Metadata->provides(dir => 'lib', version => 2);
ca33f3bd 675 my $exp_provides = {
676 'Simple' => {
677 'file' => 'lib/Simple.pm',
678 'version' => '0.01'
679 },
680 'Simple::Ex' => {
681 'file' => 'lib/Simple.pm',
682 'version' => '0.02'
683 }
684 };
685
686 is_deeply( $got_provides, $exp_provides, "provides()" )
687 or diag explain $got_provides;
688}
689
690{
c06d0187 691 my $got_provides = Module::Metadata->provides(dir => 'lib', prefix => 'other', version => 1.4);
ca33f3bd 692 my $exp_provides = {
693 'Simple' => {
694 'file' => 'other/Simple.pm',
695 'version' => '0.01'
696 },
697 'Simple::Ex' => {
698 'file' => 'other/Simple.pm',
699 'version' => '0.02'
700 }
701 };
702
703 is_deeply( $got_provides, $exp_provides, "provides()" )
704 or diag explain $got_provides;
705}
3c614865 706
707# Check package_versions_from_directory with regard to case-sensitivity
708{
709 $dist->change_file( 'lib/Simple.pm', <<'---' );
710package simple;
711$VERSION = '0.01';
712---
713 $dist->regen;
714
715 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
716 is( $pm_info->name, undef, 'no default package' );
717 is( $pm_info->version, undef, 'version for default package' );
718 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
719 is( $pm_info->version('Simple'), undef, 'version for capitalized package' );
720
721 $dist->change_file( 'lib/Simple.pm', <<'---' );
722package simple;
723$VERSION = '0.01';
724package Simple;
725$VERSION = '0.02';
726package SiMpLe;
727$VERSION = '0.03';
728---
729 $dist->regen;
730
731 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
732 is( $pm_info->name, 'Simple', 'found default package' );
733 is( $pm_info->version, '0.02', 'version for default package' );
734 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
735 is( $pm_info->version('Simple'), '0.02', 'version for capitalized package' );
736 is( $pm_info->version('SiMpLe'), '0.03', 'version for mixed-case package' );
737}