add git repository metadata
[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
a4aafbc2 215plan tests => 54 + 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{
a4aafbc2 502 # test things that look like POD, but aren't
503$dist->change_file( 'lib/Simple.pm', <<'---' );
504package Simple;
a4aafbc2 505
cfedad89 506=YES THIS STARTS POD
507
508our $VERSION = '999';
a4aafbc2 509
a4aafbc2 510=cute
a4aafbc2 511
cfedad89 512our $VERSION = '666';
513
514=cut
515
516*foo
517=*no_this_does_not_start_pod;
518
519our $VERSION = '1.23';
a4aafbc2 520
521---
522 $dist->regen;
523 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
524 is( $pm_info->name, 'Simple', 'found default package' );
525 is( $pm_info->version, '1.23', 'version for default package' );
526}
527
528{
7a4e305a 529 # Make sure processing stops after __DATA__
530 $dist->change_file( 'lib/Simple.pm', <<'---' );
531package Simple;
532$VERSION = '0.01';
533__DATA__
534*UNIVERSAL::VERSION = sub {
535 foo();
536};
537---
538 $dist->regen;
539
540 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
541 is( $pm_info->name, 'Simple', 'found default package' );
542 is( $pm_info->version, '0.01', 'version for default package' );
543 my @packages = $pm_info->packages_inside;
544 is_deeply(\@packages, ['Simple'], 'packages inside');
545}
546
547{
548 # Make sure we handle version.pm $VERSIONs well
549 $dist->change_file( 'lib/Simple.pm', <<'---' );
550package Simple;
551$VERSION = version->new('0.60.' . (qw$Revision: 128 $)[1]);
552package Simple::Simon;
553$VERSION = version->new('0.61.' . (qw$Revision: 129 $)[1]);
554---
555 $dist->regen;
556
557 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
558 is( $pm_info->name, 'Simple', 'found default package' );
559 is( $pm_info->version, '0.60.128', 'version for default package' );
560 my @packages = $pm_info->packages_inside;
561 is_deeply([sort @packages], ['Simple', 'Simple::Simon'], 'packages inside');
562 is( $pm_info->version('Simple::Simon'), '0.61.129', 'version for embedded package' );
563}
564
388bf282 565# check that package_versions_from_directory works
566
567$dist->change_file( 'lib/Simple.pm', <<'---' );
568package Simple;
569$VERSION = '0.01';
570package Simple::Ex;
571$VERSION = '0.02';
572{
573 package main; # should ignore this
574}
575{
576 package DB; # should ignore this
577}
578{
579 package Simple::_private; # should ignore this
580}
581
582=head1 NAME
583
584Simple - It's easy.
585
586=head1 AUTHOR
587
588Simple Simon
589
590=cut
591---
592$dist->regen;
593
594my $exp_pvfd = {
595 'Simple' => {
596 'file' => 'Simple.pm',
597 'version' => '0.01'
598 },
599 'Simple::Ex' => {
600 'file' => 'Simple.pm',
601 'version' => '0.02'
602 }
603};
604
605my $got_pvfd = Module::Metadata->package_versions_from_directory('lib');
606
ca33f3bd 607is_deeply( $got_pvfd, $exp_pvfd, "package_version_from_directory()" )
388bf282 608 or diag explain $got_pvfd;
ca33f3bd 609
610{
c06d0187 611 my $got_provides = Module::Metadata->provides(dir => 'lib', version => 2);
ca33f3bd 612 my $exp_provides = {
613 'Simple' => {
614 'file' => 'lib/Simple.pm',
615 'version' => '0.01'
616 },
617 'Simple::Ex' => {
618 'file' => 'lib/Simple.pm',
619 'version' => '0.02'
620 }
621 };
622
623 is_deeply( $got_provides, $exp_provides, "provides()" )
624 or diag explain $got_provides;
625}
626
627{
c06d0187 628 my $got_provides = Module::Metadata->provides(dir => 'lib', prefix => 'other', version => 1.4);
ca33f3bd 629 my $exp_provides = {
630 'Simple' => {
631 'file' => 'other/Simple.pm',
632 'version' => '0.01'
633 },
634 'Simple::Ex' => {
635 'file' => 'other/Simple.pm',
636 'version' => '0.02'
637 }
638 };
639
640 is_deeply( $got_provides, $exp_provides, "provides()" )
641 or diag explain $got_provides;
642}
3c614865 643
644# Check package_versions_from_directory with regard to case-sensitivity
645{
646 $dist->change_file( 'lib/Simple.pm', <<'---' );
647package simple;
648$VERSION = '0.01';
649---
650 $dist->regen;
651
652 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
653 is( $pm_info->name, undef, 'no default package' );
654 is( $pm_info->version, undef, 'version for default package' );
655 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
656 is( $pm_info->version('Simple'), undef, 'version for capitalized package' );
657
658 $dist->change_file( 'lib/Simple.pm', <<'---' );
659package simple;
660$VERSION = '0.01';
661package Simple;
662$VERSION = '0.02';
663package SiMpLe;
664$VERSION = '0.03';
665---
666 $dist->regen;
667
668 $pm_info = Module::Metadata->new_from_file('lib/Simple.pm');
669 is( $pm_info->name, 'Simple', 'found default package' );
670 is( $pm_info->version, '0.02', 'version for default package' );
671 is( $pm_info->version('simple'), '0.01', 'version for lower-case package' );
672 is( $pm_info->version('Simple'), '0.02', 'version for capitalized package' );
673 is( $pm_info->version('SiMpLe'), '0.03', 'version for mixed-case package' );
674}