xref: /openbsd-src/gnu/usr.bin/perl/cpan/ExtUtils-MakeMaker/t/basic.t (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1#!/usr/bin/perl -w
2
3# This test puts MakeMaker through the paces of a basic perl module
4# build, test and installation of the Big::Fat::Dummy module.
5
6# Module::Install relies on being able to patch the generated Makefile
7# to add flags to $(PERL)
8# This test includes adding ' -Iinc' to $(PERL), and checking 'make install'
9# after that works. Done here as back-compat is considered basic.
10
11BEGIN {
12    unshift @INC, 't/lib';
13}
14
15use strict;
16use Config;
17use ExtUtils::MakeMaker;
18use utf8;
19
20use MakeMaker::Test::Utils;
21use MakeMaker::Test::Setup::BFD;
22use Config;
23use ExtUtils::MM;
24use Test::More
25    !MM->can_run(make()) && $ENV{PERL_CORE} && $Config{'usecrosscompile'}
26    ? (skip_all => "cross-compiling and make not available")
27    : (tests => 188);
28use File::Find;
29use File::Spec;
30use File::Path;
31use File::Temp qw[tempdir];
32
33my $perl = which_perl();
34my $Is_VMS = $^O eq 'VMS';
35my $OLD_CP; # crude but...
36my $w32worked; # or whether we had to fallback to chcp
37if ($^O eq "MSWin32") {
38    eval { require Win32; $w32worked = $OLD_CP = Win32::GetConsoleCP() };
39    $OLD_CP = $1 if !$w32worked and qx(chcp) =~ /(\d+)$/ and $? == 0;
40    if (defined $OLD_CP) {
41        if ($w32worked) {
42            Win32::SetConsoleCP(1252)
43        } else {
44            qx(chcp 1252);
45        }
46    }
47}
48END {
49    if ($^O eq "MSWin32" and defined $OLD_CP) {
50        if ($w32worked) {
51            Win32::SetConsoleCP($OLD_CP)
52        } else {
53            qx(chcp $OLD_CP);
54        }
55    }
56}
57
58chdir 't';
59perl_lib; # sets $ENV{PERL5LIB} relative to t/
60
61my $tmpdir = tempdir( DIR => '../t', CLEANUP => 1 );
62use Cwd; my $cwd = getcwd; END { chdir $cwd } # so File::Temp can cleanup
63chdir $tmpdir;
64
65my $Touch_Time = calibrate_mtime();
66
67$| = 1;
68
69ok( setup_recurs(), 'setup' );
70
71ok( chdir('Big-Dummy'), "chdir'd to Big-Dummy" ) ||
72  diag("chdir failed: $!");
73
74sub extrachar {
75  return 's'
76    if 1; # until Perl gains native support for Unicode filenames
77#    if $] <= 5.008 || $ENV{PERL_CORE}
78#      || $^O =~ /bsd|dragonfly|mswin32/i;
79  'š';
80}
81my $DUMMYINST = '../dummy-in'.extrachar().'tall';
82my @mpl_out = run(qq{$perl Makefile.PL "PREFIX=$DUMMYINST"});
83
84cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) ||
85  diag(@mpl_out);
86
87my $makefile = makefile_name();
88ok( grep(/^Writing $makefile for Big::Dummy/,
89         @mpl_out) == 1,
90                                           'Makefile.PL output looks right');
91
92ok( grep(/^Current package is: main$/,
93         @mpl_out) == 1,
94                                           'Makefile.PL run in package main');
95
96ok( -e $makefile,       'Makefile exists' );
97
98# -M is flakey on VMS
99my $mtime = (stat($makefile))[9];
100cmp_ok( $Touch_Time, '<=', $mtime,  '  been touched' );
101
102my $make = make_run();
103
104{
105    # Suppress 'make manifest' noise
106    local $ENV{PERL_MM_MANIFEST_VERBOSE} = 0;
107    my $manifest_out = run("$make manifest");
108    ok( -e 'MANIFEST',      'make manifest created a MANIFEST' );
109    ok( -s 'MANIFEST',      '  not empty' );
110}
111
112my $ppd_out = run("$make ppd");
113is( $?, 0,                      '  exited normally' ) || diag $ppd_out;
114ok( open(PPD, 'Big-Dummy.ppd'), '  .ppd file generated' );
115my $ppd_html;
116{ local $/; $ppd_html = <PPD> }
117close PPD;
118like( $ppd_html, qr{^<SOFTPKG NAME="Big-Dummy" VERSION="0.01">}m,
119                                                           '  <SOFTPKG>' );
120like( $ppd_html,
121      qr{^\s*<ABSTRACT>Try "our" hot dog's, \$andwiche\$ and \$\(ub\)\$!</ABSTRACT>}m,
122                                                           '  <ABSTRACT>');
123like( $ppd_html,
124      qr{^\s*<AUTHOR>Michael G Schwern &lt;schwern\@pobox.com&gt;</AUTHOR>}m,
125                                                           '  <AUTHOR>'  );
126like( $ppd_html, qr{^\s*<IMPLEMENTATION>}m,          '  <IMPLEMENTATION>');
127like( $ppd_html, qr{^\s*<REQUIRE NAME="strict::" />}m,  '  <REQUIRE>' );
128unlike( $ppd_html, qr{^\s*<REQUIRE NAME="warnings::" />}m,  'no <REQUIRE> for build_require' );
129
130my $archname = $Config{archname};
131if( $] >= 5.008 ) {
132    # XXX This is a copy of the internal logic, so it's not a great test
133    $archname .= "-$Config{PERL_REVISION}.$Config{PERL_VERSION}";
134}
135like( $ppd_html, qr{^\s*<ARCHITECTURE NAME="$archname" />}m,
136                                                           '  <ARCHITECTURE>');
137like( $ppd_html, qr{^\s*<CODEBASE HREF="" />}m,            '  <CODEBASE>');
138like( $ppd_html, qr{^\s*</IMPLEMENTATION>}m,           '  </IMPLEMENTATION>');
139like( $ppd_html, qr{^\s*</SOFTPKG>}m,                      '  </SOFTPKG>');
140
141my $test_out = run("$make test");
142like( $test_out, qr/All tests successful/, 'make test' );
143is( $?, 0,                                 '  exited normally' ) ||
144    diag $test_out;
145
146# Test 'make test TEST_VERBOSE=1'
147my $make_test_verbose = make_macro($make, 'test', TEST_VERBOSE => 1);
148$test_out = run("$make_test_verbose");
149like( $test_out, qr/ok \d+ - TEST_VERBOSE/, 'TEST_VERBOSE' );
150like( $test_out, qr/ok \d+ - testing test.pl/, 'test.pl' ); # in test.pl
151like( $test_out, qr/ok \d+ - testing t\/\*.t/, 't/*.t' ); # in *.t
152like( $test_out, qr/All tests successful/,  '  successful' );
153is( $?, 0,                                  '  exited normally' ) ||
154    diag $test_out;
155
156# Test 'make testdb TEST_FILE=t/compile.t'
157# TESTDB_SW override is because perl -d is too clever for me to outwit
158my $make_testdb_file = make_macro(
159    $make,
160    'testdb',
161    TEST_FILE => 't/compile.t',
162    TESTDB_SW => '-Ixyzzy',
163);
164$test_out = run($make_testdb_file);
165unlike( $test_out, qr/harness/, 'no harness' );
166unlike( $test_out, qr/sanity\.t/, 'no wrong test' );
167like( $test_out, qr/compile\.t/, 'get right test' );
168like( $test_out, qr/xyzzy/, 'signs of TESTDB_SW' );
169is( $?, 0,                                  '  exited normally' ) ||
170    diag $test_out;
171
172# now simulate what Module::Install does, and edit $(PERL) to add flags
173open my $fh, '<', $makefile;
174my $mtext = join '', <$fh>;
175close $fh;
176$mtext =~ s/^(\s*PERL\s*=.*)$/$1 -Iinc/m;
177open $fh, '>', $makefile;
178print $fh $mtext;
179close $fh;
180
181my $install_out = run("$make install");
182is( $?, 0, 'install' ) || diag $install_out;
183like( $install_out, qr/^Installing /m );
184
185sub check_dummy_inst {
186    my ($loc, $skipsubdir) = @_;
187    my %files = ();
188    find( sub {
189	# do it case-insensitive for non-case preserving OSs
190	my $file = lc $_;
191	# VMS likes to put dots on the end of things that don't have them.
192	$file =~ s/\.$// if $Is_VMS;
193	$files{$file} = $File::Find::name;
194    }, $loc );
195    ok( $files{'dummy.pm'},     '  Dummy.pm installed' );
196    ok( $files{'liar.pm'},      '  Liar.pm installed'  ) unless $skipsubdir;
197    ok( $files{'program'},      '  program installed'  );
198    ok( $files{'.packlist'},    '  packlist created'   );
199    ok( $files{'perllocal.pod'},'  perllocal.pod created' );
200    \%files;
201}
202
203SKIP: {
204    ok( -r $DUMMYINST,     '  install dir created' )
205	or skip "$DUMMYINST doesn't exist", 5;
206    check_dummy_inst($DUMMYINST);
207}
208
209SKIP: {
210    skip 'VMS install targets do not preserve $(PREFIX)', 8 if $Is_VMS;
211
212    $install_out = run("$make install PREFIX=elsewhere");
213    is( $?, 0, 'install with PREFIX override' ) || diag $install_out;
214    like( $install_out, qr/^Installing /m );
215
216    ok( -r 'elsewhere',     '  install dir created' );
217    check_dummy_inst('elsewhere');
218    rmtree('elsewhere');
219}
220
221
222SKIP: {
223    skip 'VMS install targets do not preserve $(DESTDIR)', 10 if $Is_VMS;
224
225    $install_out = run("$make install PREFIX= DESTDIR=other");
226    is( $?, 0, 'install with DESTDIR' ) ||
227        diag $install_out;
228    like( $install_out, qr/^Installing /m );
229
230    ok( -d 'other',  '  destdir created' );
231    my $files = check_dummy_inst('other');
232
233    ok( open(PERLLOCAL, $files->{'perllocal.pod'} ) ) ||
234        diag("Can't open $files->{'perllocal.pod'}: $!");
235    { local $/;
236      unlike(<PERLLOCAL>, qr/other/, 'DESTDIR should not appear in perllocal');
237    }
238    close PERLLOCAL;
239
240# TODO not available in the min version of Test::Harness we require
241#    ok( open(PACKLIST, $files{'.packlist'} ) ) ||
242#        diag("Can't open $files{'.packlist'}: $!");
243#    { local $/;
244#      local $TODO = 'DESTDIR still in .packlist';
245#      unlike(<PACKLIST>, qr/other/, 'DESTDIR should not appear in .packlist');
246#    }
247#    close PACKLIST;
248
249    rmtree('other');
250}
251
252
253SKIP: {
254    skip 'VMS install targets do not preserve $(PREFIX)', 9 if $Is_VMS;
255
256    $install_out = run("$make install PREFIX=elsewhere DESTDIR=other/");
257    is( $?, 0, 'install with PREFIX override and DESTDIR' ) ||
258        diag $install_out;
259    like( $install_out, qr/^Installing /m );
260
261    ok( !-d 'elsewhere',       '  install dir not created' );
262    ok( -d 'other/elsewhere',  '  destdir created' );
263    check_dummy_inst('other/elsewhere');
264    rmtree('other');
265}
266
267my ($dist_test_out, $distdir, $meta_yml, $mymeta_yml, $meta_json, $mymeta_json);
268SKIP: {
269    skip 'disttest depends on metafile, which is not run in core', 1 if $ENV{PERL_CORE};
270    $dist_test_out = run("$make disttest");
271    is( $?, 0, 'disttest' ) || diag($dist_test_out);
272
273    # Test META.yml generation
274    use ExtUtils::Manifest qw(maniread);
275
276    $distdir  = 'Big-Dummy-0.01';
277    $distdir =~ s/\./_/g if $Is_VMS;
278    $meta_yml = "$distdir/META.yml";
279    $mymeta_yml = "$distdir/MYMETA.yml";
280    $meta_json = "$distdir/META.json";
281    $mymeta_json = "$distdir/MYMETA.json";
282}
283
284note "META file validity"; SKIP: {
285    skip 'disttest depends on metafile, which is not run in core', 104 if $ENV{PERL_CORE};
286
287    eval { require CPAN::Meta; };
288    skip 'Loading CPAN::Meta failed', 104 if $@;
289
290    ok( !-f 'META.yml',  'META.yml not written to source dir' );
291    ok( -f $meta_yml,    'META.yml written to dist dir' );
292    ok( !-e "META_new.yml", 'temp META.yml file not left around' );
293
294    ok( -f 'MYMETA.yml',  'MYMETA.yml is written to source dir' );
295    ok( -f $mymeta_yml,    'MYMETA.yml is written to dist dir on disttest' );
296
297    ok( !-f 'META.json',  'META.json not written to source dir' );
298    ok( -f $meta_json,    'META.json written to dist dir' );
299    ok( !-e "META_new.json", 'temp META.json file not left around' );
300
301    ok( -f 'MYMETA.json',  'MYMETA.json is written to source dir' );
302    ok( -f $mymeta_json,    'MYMETA.json is written to dist dir on disttest' );
303
304    for my $case (
305      ['META.yml', $meta_yml],
306      ['MYMETA.yml', $mymeta_yml],
307      ['META.json', $meta_json],
308      ['MYMETA.json', $mymeta_json],
309      ['MYMETA.yml', 'MYMETA.yml'],
310      ['MYMETA.json', 'MYMETA.json'],
311    ) {
312      my ($label, $meta_name) = @$case;
313      ok(
314        my $obj = eval {
315          CPAN::Meta->load_file($meta_name, {lazy_validation => 0})
316        },
317        "$label validates"
318      );
319      my $is = sub {
320        my ($m,$e) = @_;
321        is($obj->$m, $e, "$label -> $m")
322      };
323      my $is_list = sub {
324        my ($m,$e) = @_;
325        is_deeply([$obj->$m], $e, "$label -> $m")
326      };
327      my $is_map = sub {
328        my ($m,$e) = @_;
329        is_deeply($obj->$m, $e, "$label -> $m")
330      };
331      $is->( name => "Big-Dummy" );
332      $is->( version => "0.01" );
333      $is->( abstract => q{Try "our" hot dog's, $andwiche$ and $(ub)$!} );
334      $is_list->( licenses => [q{unknown}] );
335      $is_list->( authors => [ q{Michael G Schwern <schwern@pobox.com>} ] );
336      $is_map->( prereqs => {
337          configure => {
338            requires => {
339              'ExtUtils::MakeMaker' => 0
340            },
341          },
342          build => {
343            requires => {
344              'warnings' => 0
345            }
346          },
347          runtime => {
348            requires => {
349              'strict' => 0
350            }
351          },
352        }
353      );
354      $is_map->(
355        no_index => {
356          directory => [qw/t inc/],
357        }
358      );
359      $is->( dynamic_config => ($label =~ /MYMETA/) ? 0 : 1 );
360    }
361
362    my $manifest = maniread("$distdir/MANIFEST");
363    # VMS is non-case preserving, so we can't know what the MANIFEST will
364    # look like. :(
365    _normalize($manifest);
366    is( $manifest->{'meta.yml'}, 'Module YAML meta-data (added by MakeMaker)',
367      "MANIFEST has META.yml"
368    );
369    is( $manifest->{'meta.json'}, 'Module JSON meta-data (added by MakeMaker)',
370      "MANIFEST has META.json"
371    );
372
373    # Test NO_META META.yml suppression
374    for my $f ( $meta_yml, $meta_json, 'MYMETA.yml', 'MYMETA.json' ) {
375      1 while unlink $f;
376    }
377    ok( !-f $meta_yml,   'META.yml deleted' );
378    ok( !-f 'MYMETA.yml','MYMETA.yml deleted' );
379    ok( !-f $meta_json,   'META.json deleted' );
380    ok( !-f 'MYMETA.json','MYMETA.json deleted' );
381
382    @mpl_out = run(qq{$perl Makefile.PL "NO_META=1"});
383    ok( -f 'MYMETA.yml', 'MYMETA.yml generation not suppressed by NO_META' );
384    ok( -f 'MYMETA.json', 'MYMETA.json generation not suppressed by NO_META' );
385    cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) || diag(@mpl_out);
386    ok( !-f $meta_yml,   'META.yml generation suppressed by NO_META' );
387    ok( !-f $meta_json,   'META.json generation suppressed by NO_META' );
388    my $distdir_out = run("$make distdir");
389    is( $?, 0, 'distdir' ) || diag($distdir_out);
390    ok( !-f $meta_yml,   'META.yml generation suppressed by NO_META' );
391    ok( !-f $meta_json,   'META.json generation suppressed by NO_META' );
392
393    for my $f ( 'MYMETA.yml', 'MYMETA.json' ) {
394      1 while unlink $f;
395    }
396    ok( !-f 'MYMETA.yml','MYMETA.yml deleted' );
397    ok( !-f 'MYMETA.json','MYMETA.json deleted' );
398
399    @mpl_out = run(qq{$perl Makefile.PL "NO_MYMETA=1"});
400    cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) || diag(@mpl_out);
401    $distdir_out = run("$make distdir");
402    is( $?, 0, 'distdir' ) || diag($distdir_out);
403    ok( !-f 'MYMETA.yml','MYMETA.yml generation suppressed by NO_MYMETA' );
404    ok( !-f 'MYMETA.json','MYMETA.json generation suppressed by NO_MYMETA' );
405    ok( -f $meta_yml,    'META.yml generation not suppressed by NO_MYMETA' );
406    ok( -f $meta_json,    'META.json generation not suppressed by NO_MYMETA' );
407
408    # Test MYMETA really comes from META except for prereqs
409    for my $f ( $meta_yml, $meta_json, 'MYMETA.yml', 'MYMETA.json' ) {
410      1 while unlink $f;
411    }
412    @mpl_out = run(qq{$perl Makefile.PL});
413    cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) || diag(@mpl_out);
414    $distdir_out = run("$make distdir");
415    is( $?, 0, 'distdir' ) || diag($distdir_out);
416    ok( -f $meta_yml,    'META.yml generated in distdir' );
417    ok( -f $meta_json,    'META.json generated in distdir' );
418    ok( ! -f $mymeta_yml,    'MYMETA.yml not yet generated in distdir' );
419    ok( ! -f $mymeta_json,    'MYMETA.json generated in distdir' );
420    my $edit_meta = CPAN::Meta->load_file($meta_json)->as_struct;
421    $edit_meta->{abstract} = "New abstract";
422    my $meta_obj = CPAN::Meta->new($edit_meta);
423    is( $meta_obj->abstract, "New abstract", "MYMETA abstract from META, not Makefile.PL");
424    ok( $meta_obj->save($meta_json), "Saved edited META.json in distdir" );
425    ok( $meta_obj->save($meta_yml, {version => 1.4}), "Saved edited META.yml in distdir");
426    ok( chdir $distdir );
427    ok( -f 'META.yml',    'META.yml confirmed in distdir' );
428    ok( -f 'META.json',    'META.json confirmed in distdir' );
429    @mpl_out = run(qq{$perl Makefile.PL});
430    cmp_ok( $?, '==', 0, 'Makefile.PL in distdir exited with zero' ) || diag(@mpl_out);
431    ok( chdir File::Spec->updir );
432    ok( -f $mymeta_yml,    'MYMETA.yml generated in distdir' );
433    ok( -f $mymeta_json,    'MYMETA.json generated in distdir' );
434    $meta_obj = CPAN::Meta->load_file($meta_json);
435    is( $meta_obj->abstract, "New abstract", "META abstract is same as was saved");
436    $meta_obj = CPAN::Meta->load_file($mymeta_json);
437    is( $meta_obj->abstract, "New abstract", "MYMETA abstract from META, not Makefile.PL");
438}
439
440
441# Make sure init_dirscan doesn't go into the distdir
442# also with a "messup.PL" that will make a build fail
443open $fh, '>', 'messup.PL' or die "messup.PL: $!";
444print $fh 'print "Extracting messup (with variable substitutions)\n";' . "\n";
445print $fh 'die';
446close $fh;
447@mpl_out = run(qq{$perl Makefile.PL "PREFIX=$DUMMYINST"});
448
449cmp_ok( $?, '==', 0, 'Makefile.PL exited with zero' ) || diag(@mpl_out);
450
451ok( grep(/^Writing $makefile for Big::Dummy/, @mpl_out) == 1,
452                                'init_dirscan skipped distdir') ||
453  diag(@mpl_out);
454
455# "make test" straight after "perl Makefile.PL" is expected to work same as
456#   "make all test" so check that with "messup.PL" that will make the
457#   build step fail
458$test_out = run("$make test");
459unlike( $test_out, qr/All tests successful/, 'make test caused build' );
460isnt( $?, 0,                                 '  build should fail' ) ||
461    diag $test_out;
462
463# I know we'll get ignored errors from make here, that's ok.
464# Send STDERR off to oblivion.
465open(SAVERR, ">&STDERR") or die $!;
466open(STDERR, ">",File::Spec->devnull) or die $!;
467
468my $realclean_out = run("$make realclean");
469is( $?, 0, 'realclean' ) || diag($realclean_out);
4701 while unlink 'messup.PL'; # also zap deliberate build-breaker
471
472open(STDERR, ">&SAVERR") or die $!;
473close SAVERR;
474
475# test linkext=>{LINKTYPE=>''} still installs a pure-perl installation
476# warning, edits the Makefile.PL so either rewrite after this or do this last
477my $file = 'Makefile.PL';
478my $text = slurp $file;
479ok(($text =~ s#\);#    linkext=>{LINKTYPE=>''},\n$&#), 'successful M.PL edit');
480open $fh, '>', $file or die "$file: $!";
481print $fh $text;
482close $fh;
483# now do with "Liar" subdir still there
484rmtree $DUMMYINST; # so no false positive from before
485@mpl_out = run(qq{$perl Makefile.PL "PREFIX=$DUMMYINST"});
486$install_out = run("$make install");
487check_dummy_inst($DUMMYINST);
488# now clean, delete "Liar" subdir, do again
489$realclean_out = run("$make realclean");
490rmtree 'Liar';
491rmtree $DUMMYINST; # so no false positive from before
492@mpl_out = run(qq{$perl Makefile.PL "PREFIX=$DUMMYINST"});
493$install_out = run("$make install");
494check_dummy_inst($DUMMYINST, 1);
495
496sub _normalize {
497    my $hash = shift;
498
499    %$hash= map { lc($_) => $hash->{$_} } keys %$hash;
500}
501