1BEGIN {
2    unshift @INC, 't/lib';
3}
4
5use strict;
6use warnings;
7use Test::More;
8BEGIN {
9  eval { require CPAN::Meta; CPAN::Meta->VERSION(2.143240) }
10    or plan skip_all => 'CPAN::Meta 2.143240 required for this test';
11  eval { require CPAN::Meta::Converter; }
12    or plan skip_all => 'CPAN::Meta::Converter required for this test';
13  eval { require Parse::CPAN::Meta; }
14    or plan skip_all => 'Parse::CPAN::Meta required for this test';
15}
16use Data::Dumper;
17use File::Temp;
18use Cwd;
19use MakeMaker::Test::Utils;
20
21plan tests => 35;
22require ExtUtils::MM_Any;
23
24sub mymeta_ok {
25    my($have, $want, $name) = @_;
26    local $Test::Builder::Level = $Test::Builder::Level + 1;
27    my $have_gen = delete $have->{generated_by};
28    my $want_gen = delete $want->{generated_by};
29    my $have_url = delete $have->{'meta-spec'}->{url};
30    my $want_url = delete $want->{'meta-spec'}->{url};
31    is_deeply $have, $want, $name;
32    like $have_gen, qr{CPAN::Meta}, "CPAN::Meta mentioned in the generated_by";
33    like $have_url, qr{CPAN::Meta::Spec}, "CPAN::Meta::Spec mentioned in meta-spec URL";
34    return;
35}
36
37my $new_mm = sub {
38    return bless { ARGS => {@_}, @_ }, 'ExtUtils::MM_Any';
39};
40my @METASPEC14 = (
41    'meta-spec'  => {
42        url => 'http://module-build.sourceforge.net/META-spec-v1.4.html',
43        version => 1.4
44    },
45);
46my @METASPEC20 = (
47    'meta-spec'  => {
48        url => 'https://metacpan.org/pod/CPAN::Meta::Spec',
49        version => 2
50    },
51);
52my @REQ20 = (
53    configure => { requires => { 'ExtUtils::MakeMaker' => 0, }, },
54    build => { requires => { 'ExtUtils::MakeMaker' => 0, }, },
55);
56my @GENERIC_IN = (
57    DISTNAME => 'Foo-Bar',
58    VERSION  => 1.23,
59    PM       => { "Foo::Bar" => 'lib/Foo/Bar.pm', },
60);
61my @GENERIC_OUT = (
62    # mandatory
63    abstract          => 'unknown',
64    author            => [qw(unknown)],
65    dynamic_config    => 1,
66    generated_by      => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
67    license           => ['unknown'],
68    @METASPEC20,
69    name              => 'Foo-Bar',
70    release_status    => 'stable',
71    version           => 1.23,
72    # optional
73    no_index          => { directory => [qw(t inc)], },
74);
75
76{
77    my $mm = $new_mm->(@GENERIC_IN);
78    is_deeply $mm->metafile_data, {
79        @GENERIC_OUT,
80        prereqs => { @REQ20, },
81    };
82    is_deeply $mm->metafile_data({}, { no_index => { directory => [qw(foo)] } }), {
83        @GENERIC_OUT,
84        prereqs => { @REQ20, },
85        no_index        => { directory => [qw(t inc foo)], },
86    }, 'rt.cpan.org 39348';
87}
88
89{
90    my $mm = $new_mm->(
91        DISTNAME        => 'Foo-Bar',
92        VERSION         => 1.23,
93        AUTHOR          => ['Some Guy'],
94        PREREQ_PM       => { Foo => 2.34, Bar => 4.56, },
95    );
96    is_deeply $mm->metafile_data(
97        {
98            configure_requires => { Stuff   => 2.34 },
99            wobble      => 42
100        },
101        {
102            no_index    => { package => "Thing" },
103            wibble      => 23
104        },
105    ),
106    {
107        @GENERIC_OUT, # some overridden, which is fine
108        author          => ['Some Guy'],
109        prereqs => {
110            @REQ20,
111            configure => { requires => { Stuff => 2.34, }, },
112            runtime => { requires => { Foo => 2.34, Bar => 4.56, }, },
113        },
114        no_index        => {
115            directory           => [qw(t inc)],
116            package             => ['Thing'],
117        },
118        x_wibble  => 23,
119        x_wobble  => 42,
120    }, '_add vs _merge';
121}
122
123# Test MIN_PERL_VERSION meta-spec 1.4
124{
125    my $mm = $new_mm->(
126        @GENERIC_IN,
127        MIN_PERL_VERSION => 5.006,
128    );
129    is_deeply $mm->metafile_data( {}, { @METASPEC14 }, ), {
130        @GENERIC_OUT,
131        prereqs => {
132            @REQ20,
133            runtime => { requires => { perl => 5.006, }, },
134        },
135    }, 'MIN_PERL_VERSION meta-spec 1.4';
136}
137
138# Test MIN_PERL_VERSION meta-spec 2.0
139{
140    my $mm = $new_mm->(
141        @GENERIC_IN,
142        MIN_PERL_VERSION => 5.006,
143    );
144    is_deeply $mm->metafile_data, {
145        prereqs => {
146            @REQ20,
147            runtime => { requires => { 'perl' => '5.006', }, },
148        },
149        @GENERIC_OUT,
150    }, 'MIN_PERL_VERSION meta-spec 2.0';
151}
152
153# Test MIN_PERL_VERSION meta-spec 1.4
154{
155    my $mm = $new_mm->(
156        @GENERIC_IN,
157        MIN_PERL_VERSION => 5.006,
158        PREREQ_PM => { 'Foo::Bar' => 1.23, },
159    );
160    is_deeply $mm->metafile_data, {
161        @GENERIC_OUT,
162        prereqs => {
163            @REQ20,
164            runtime         => {
165                requires    => {
166                    'Foo::Bar'  => 1.23,
167                    'perl'  => '5.006',
168                },
169            },
170        },
171    }, 'MIN_PERL_VERSION and PREREQ_PM meta-spec 1.4';
172}
173
174# Test CONFIGURE_REQUIRES meta-spec 1.4
175{
176    my $mm = $new_mm->(
177        @GENERIC_IN,
178        CONFIGURE_REQUIRES => { "Fake::Module1" => 1.01, },
179    );
180    is_deeply $mm->metafile_data( {}, { @METASPEC14 }, ), {
181        prereqs => {
182            @REQ20,
183            configure => { requires => { 'Fake::Module1' => 1.01, }, },
184        },
185        @GENERIC_OUT,
186    },'CONFIGURE_REQUIRES meta-spec 1.4';
187}
188
189# Test CONFIGURE_REQUIRES meta-spec 2.0
190{
191    my $mm = $new_mm->(
192        @GENERIC_IN,
193        CONFIGURE_REQUIRES => { "Fake::Module1" => 1.01, },
194    );
195    is_deeply $mm->metafile_data, {
196        prereqs => {
197            @REQ20,
198            configure => { requires => { 'Fake::Module1' => 1.01, }, },
199        },
200        @GENERIC_OUT,
201    },'CONFIGURE_REQUIRES meta-spec 2.0';
202}
203
204# Test BUILD_REQUIRES meta-spec 1.4
205{
206    my $mm = $new_mm->(
207        @GENERIC_IN,
208        BUILD_REQUIRES => { "Fake::Module1" => 1.01, },
209        META_MERGE => { "meta-spec" => { version => 1.4 }},
210    );
211    is_deeply $mm->metafile_data( {}, { @METASPEC14 }, ), {
212        prereqs => {
213            @REQ20,
214            build => { requires => { 'Fake::Module1' => 1.01, }, },
215        },
216        @GENERIC_OUT,
217    },'BUILD_REQUIRES meta-spec 1.4';
218}
219
220# Test BUILD_REQUIRES meta-spec 2.0
221{
222    my $mm = $new_mm->(
223        @GENERIC_IN,
224        BUILD_REQUIRES => { "Fake::Module1" => 1.01, },
225    );
226    is_deeply $mm->metafile_data, {
227        prereqs => {
228            @REQ20,
229            build => { requires => { 'Fake::Module1' => 1.01, }, },
230        },
231        @GENERIC_OUT,
232    },'BUILD_REQUIRES meta-spec 2.0';
233}
234
235# Test TEST_REQUIRES meta-spec 1.4
236{
237    my $mm = $new_mm->(
238        @GENERIC_IN,
239        TEST_REQUIRES => { "Fake::Module1" => 1.01, },
240        META_MERGE => { "meta-spec" => { version => 1.4 }},
241    );
242    is_deeply $mm->metafile_data( {}, { @METASPEC14 }, ), {
243        prereqs => {
244            @REQ20,
245            test => { requires => { "Fake::Module1" => 1.01, }, },
246        },
247        @GENERIC_OUT,
248    },'TEST_REQUIRES meta-spec 1.4';
249}
250
251# Test TEST_REQUIRES meta-spec 2.0
252{
253    my $mm = $new_mm->(
254        @GENERIC_IN,
255        TEST_REQUIRES => { "Fake::Module1" => 1.01, },
256    );
257    is_deeply $mm->metafile_data, {
258        prereqs => {
259            @REQ20,
260            test => { requires => { "Fake::Module1" => 1.01, }, },
261        },
262        @GENERIC_OUT,
263    },'TEST_REQUIRES meta-spec 2.0';
264}
265
266{
267    my $mm = $new_mm->(
268        @GENERIC_IN,
269    );
270    is_deeply $mm->metafile_data(
271        {
272            resources => {
273                homepage => "https://metacpan.org/release/ExtUtils-MakeMaker",
274                repository => "http://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker",
275            },
276        },
277        { @METASPEC14 },
278    ), {
279        prereqs => { @REQ20 },
280        resources => {
281            homepage => "https://metacpan.org/release/ExtUtils-MakeMaker",
282            repository => {
283                url => "http://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker",
284            },
285        },
286        @GENERIC_OUT,
287    }, 'META_ADD takes meta version 1.4 from META_MERGE';
288}
289
290{
291    my $mm = $new_mm->(
292        @GENERIC_IN,
293    );
294    is_deeply $mm->metafile_data(
295        { @METASPEC14 },
296        {
297            resources => {
298                homepage => "https://metacpan.org/release/ExtUtils-MakeMaker",
299                repository => "http://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker",
300            },
301        },
302    ), {
303        prereqs => { @REQ20 },
304        resources => {
305            homepage => "https://metacpan.org/release/ExtUtils-MakeMaker",
306            repository => {
307                url => "http://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker",
308            },
309        },
310        @GENERIC_OUT,
311    }, 'META_MERGE takes meta version 1.4 from META_ADD';
312}
313
314{
315    my $mm = $new_mm->(
316        @GENERIC_IN,
317    );
318    is_deeply $mm->metafile_data(
319        {
320            'configure_requires' => {
321                'Fake::Module1' => 1,
322            },
323            'prereqs' => {
324                @REQ20,
325                'test' => {
326                    'requires' => {
327                        'Fake::Module2' => 2,
328                    },
329                },
330            },
331        },
332        { @METASPEC20 },
333    ), {
334        prereqs => {
335            @REQ20,
336            test => { requires => { "Fake::Module2" => 2, }, },
337        },
338        @GENERIC_OUT,
339    }, 'META_ADD takes meta version 2 from META_MERGE';
340}
341
342{
343    my $mm = $new_mm->(
344        @GENERIC_IN,
345    );
346    is_deeply $mm->metafile_data(
347        { @METASPEC20 },
348        {
349            'configure_requires' => {
350                'Fake::Module1' => 1,
351            },
352            'prereqs' => {
353                @REQ20,
354                'test' => {
355                    'requires' => {
356                        'Fake::Module2' => 2,
357                    },
358                },
359            },
360        },
361    ), {
362        prereqs => {
363            @REQ20,
364            test => { requires => { "Fake::Module2" => 2, }, },
365        },
366        @GENERIC_OUT,
367    }, 'META_MERGE takes meta version 2 from META_ADD';
368}
369
370# Test _REQUIRES key priority over META_ADD
371{
372    my $mm = $new_mm->(
373        @GENERIC_IN,
374        BUILD_REQUIRES => { "Fake::Module1" => 1.01, },
375        META_ADD => (my $meta_add = { build_requires => {}, configure_requires => {} }),
376    );
377    is_deeply $mm->metafile_data($meta_add), {
378        prereqs => {
379            configure => { requires => { }, },
380            build => { requires => { }, },
381        },
382        @GENERIC_OUT,
383    },'META.yml data (META_ADD wins)';
384    # Yes, this is all hard coded.
385
386    my $want_mymeta = {
387        name            => 'ExtUtils-MakeMaker',
388        version         => '6.57_07',
389        abstract        => 'Create a module Makefile',
390        author          => ['Michael G Schwern <schwern@pobox.com>'],
391        license         => ['perl_5'],
392        dynamic_config  => 0,
393        prereqs => {
394            runtime => {
395                requires => {
396                    "DirHandle"         => 0,
397                    "File::Basename"    => 0,
398                    "File::Spec"        => "0.8",
399                    "Pod::Man"          => 0,
400                    "perl"              => "5.006",
401                },
402            },
403            @REQ20,
404            build => { requires => { 'Fake::Module1' => 1.01, }, },
405        },
406        release_status => 'testing',
407        resources => {
408            license     =>  [ 'http://dev.perl.org/licenses/' ],
409            homepage    =>  'http://makemaker.org',
410            bugtracker  =>  { web => 'http://rt.cpan.org/NoAuth/Bugs.html?Dist=ExtUtils-MakeMaker' },
411            repository  =>  { url => 'http://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker' },
412            x_MailingList => 'makemaker@perl.org',
413        },
414        no_index        => {
415            directory           => [qw(t inc)],
416            package             => ["DynaLoader", "in"],
417        },
418        generated_by => "ExtUtils::MakeMaker version 6.5707, CPAN::Meta::Converter version 2.110580",
419        @METASPEC20,
420    };
421    mymeta_ok $mm->mymeta("t/META_for_testing.json"),
422              $want_mymeta,
423              'MYMETA JSON data (BUILD_REQUIRES wins)';
424    mymeta_ok $mm->mymeta("t/META_for_testing.yml"),
425              $want_mymeta,
426              'MYMETA YAML data (BUILD_REQUIRES wins)';
427}
428
429{
430    my $mm = $new_mm->(
431        @GENERIC_IN,
432        CONFIGURE_REQUIRES  => { "Fake::Module0" => 0.99 },
433        BUILD_REQUIRES      => { "Fake::Module1" => 1.01 },
434        TEST_REQUIRES       => { "Fake::Module2" => 1.23 },
435    );
436    my $meta = $mm->mymeta('t/META_for_testing.json');
437    is($meta->{configure_requires}, undef, "no configure_requires in v2 META");
438    is($meta->{build_requires}, undef, "no build_requires in v2 META");
439    is_deeply(
440        $meta->{prereqs}{configure}{requires},
441        { "Fake::Module0" => 0.99 },
442        "configure requires are one thing in META v2...",
443    );
444    is_deeply(
445        $meta->{prereqs}{build}{requires},
446        { "Fake::Module1" => 1.01 },
447        "build requires are one thing in META v2...",
448    );
449    is_deeply(
450        $meta->{prereqs}{test}{requires},
451        { "Fake::Module2" => 1.23 },
452        "...and test requires are another",
453    );
454}
455
456note "CPAN::Meta bug using the module version instead of the meta spec version";
457{
458    my $mm = $new_mm->(
459        NAME      => 'GD::Barcode::Code93',
460        AUTHOR    => 'Chris DiMartino',
461        ABSTRACT  => 'Code 93 implementation of GD::Barcode family',
462        PREREQ_PM => {
463            'GD::Barcode' => 0,
464            'GD'          => 0
465        },
466        VERSION   => '1.4',
467    );
468    my $meta = $mm->mymeta("t/META_for_testing_tricky_version.yml");
469    is $meta->{'meta-spec'}{version}, 2, "internally, our MYMETA struct is v2";
470    in_dir {
471        $mm->write_mymeta($meta);
472        ok -e "MYMETA.yml";
473        ok -e "MYMETA.json";
474        my $meta_yml = Parse::CPAN::Meta->load_file("MYMETA.yml");
475        is $meta_yml->{'meta-spec'}{version}, 1.4, "MYMETA.yml correctly downgraded to 1.4";
476        my $meta_json = Parse::CPAN::Meta->load_file("MYMETA.json");
477        cmp_ok $meta_json->{'meta-spec'}{version}, ">=", 2, "MYMETA.json at 2 or better";
478    };
479}
480
481note "A bad license string";
482{
483    my $mm = $new_mm->(
484        @GENERIC_IN,
485        LICENSE   => 'death and retribution',
486    );
487    in_dir {
488        my $meta = $mm->mymeta;
489        {
490            local $SIG{__WARN__} = sub {}; # suppress "Invalid" warning
491            $mm->write_mymeta($meta);
492        }
493        my $meta_yml = Parse::CPAN::Meta->load_file("MYMETA.yml");
494        is $meta_yml->{license}, "unknown", "in yaml";
495        my $meta_json = Parse::CPAN::Meta->load_file("MYMETA.json");
496        is_deeply $meta_json->{license}, ["unknown"], "in json";
497    };
498}
499