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