1use strict; 2use warnings; 3use Test::More 0.88; 4use utf8; 5 6use CPAN::Meta; 7use CPAN::Meta::Validator; 8use CPAN::Meta::Converter; 9use File::Spec; 10use File::Basename qw/basename/; 11use IO::Dir; 12use Parse::CPAN::Meta; 13 14delete $ENV{PERL_YAML_BACKEND}; 15delete $ENV{PERL_JSON_BACKEND}; 16delete $ENV{CPAN_META_JSON_BACKEND}; 17delete $ENV{CPAN_META_JSON_DECODER}; 18 19# mock file object 20package 21 File::StringObject; 22 23use overload q{""} => sub { ${$_[0]} }, fallback => 1; 24 25sub new { 26 my ($class, $file) = @_; 27 bless \$file, $class; 28} 29 30package main; 31 32my $data_dir = IO::Dir->new( 't/data-test' ); 33my @files = sort grep { /^\w/ } $data_dir->read; 34 35*_spec_version = \&CPAN::Meta::Converter::_extract_spec_version; 36 37#use Data::Dumper; 38 39for my $f ( reverse sort @files ) { 40 note ''; 41 my $path = File::Spec->catfile('t','data-test',$f); 42 my $original = Parse::CPAN::Meta->load_file( $path ); 43 ok( $original, "loaded $f" ); 44 my $original_v = _spec_version($original); 45 # UPCONVERSION 46 { 47 my $cmc = CPAN::Meta::Converter->new( $original ); 48 my $converted = $cmc->convert( version => 2 ); 49 is ( _spec_version($converted), 2, "up converted spec version $original_v to spec version 2"); 50 my $cmv = CPAN::Meta::Validator->new( $converted ); 51 ok ( $cmv->is_valid, "up converted META is valid" ) 52 or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) 53# . "\nMETA:\n" . Dumper($converted) 54 ); 55 } 56 # UPCONVERSION - partial 57 if ( _spec_version( $original ) < 2 ) { 58 my $cmc = CPAN::Meta::Converter->new( $original ); 59 my $converted = $cmc->convert( version => '1.4' ); 60 is ( _spec_version($converted), 1.4, "up converted spec version $original_v to spec version 1.4"); 61 my $cmv = CPAN::Meta::Validator->new( $converted ); 62 ok ( $cmv->is_valid, "up converted META is valid" ) 63 or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) 64# . "\nMETA:\n" . Dumper($converted) 65 ); 66 } 67 # DOWNCONVERSION - partial 68 if ( _spec_version( $original ) >= 1.2 ) { 69 my $cmc = CPAN::Meta::Converter->new( $original ); 70 my $converted = $cmc->convert( version => '1.2' ); 71 is ( _spec_version($converted), '1.2', "down converted spec version $original_v to spec version 1.2"); 72 my $cmv = CPAN::Meta::Validator->new( $converted ); 73 ok ( $cmv->is_valid, "down converted META is valid" ) 74 or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) 75# . "\nMETA:\n" . Dumper($converted) 76 ); 77 78 if (_spec_version( $original ) == 2) { 79 is_deeply( 80 $converted->{build_requires}, 81 { 82 'Test::More' => '0.88', 83 'Build::Requires' => '1.1', 84 'Test::Requires' => '1.2', 85 }, 86 "downconversion from 2 merge test and build requirements", 87 ); 88 } 89 } 90 # DOWNCONVERSION 91 { 92 my $cmc = CPAN::Meta::Converter->new( $original ); 93 my $converted = $cmc->convert( version => '1.0' ); 94 is ( _spec_version($converted), '1.0', "down converted spec version $original_v to spec version 1.0"); 95 my $cmv = CPAN::Meta::Validator->new( $converted ); 96 ok ( $cmv->is_valid, "down converted META is valid" ) 97 or diag( "ERRORS:\n" . join( "\n", $cmv->errors ) 98# . "\nMETA:\n" . Dumper($converted) 99 ); 100 101 unless ($original_v eq '1.0') { 102 like ( $converted->{generated_by}, 103 qr(\Q$original->{generated_by}\E, CPAN::Meta::Converter version \S+$), 104 "added converter mark to generated_by", 105 ); 106 } 107 } 108} 109 110# specific test for custom key handling 111{ 112 my $path = File::Spec->catfile('t','data-test','META-1_4.yml'); 113 my $original = Parse::CPAN::Meta->load_file( $path ); 114 ok( $original, "loaded META-1_4.yml" ); 115 my $cmc = CPAN::Meta::Converter->new( $original ); 116 my $up_converted = $cmc->convert( version => 2 ); 117 ok ( $up_converted->{x_whatever} && ! $up_converted->{'x-whatever'}, 118 "up converted 'x-' to 'x_'" 119 ); 120 ok ( $up_converted->{x_whatelse}, 121 "up converted 'x_' as 'x_'" 122 ); 123 ok ( $up_converted->{x_WhatNow} && ! $up_converted->{XWhatNow}, 124 "up converted 'XFoo' to 'x_Foo'" 125 ) or diag join("\n", keys %$up_converted); 126} 127 128# specific test for custom key handling 129{ 130 my $path = File::Spec->catfile('t','data-test','META-2.json'); 131 my $original = Parse::CPAN::Meta->load_file( $path ); 132 ok( $original, "loaded META-2.json" ); 133 my $cmc = CPAN::Meta::Converter->new( $original ); 134 my $down_converted = $cmc->convert( version => 1.4 ); 135 ok ( $down_converted->{x_whatever}, 136 "down converted 'x_' as 'x_'" 137 ); 138} 139 140# specific test for generalization of unclear licenses 141{ 142 my $path = File::Spec->catfile('t','data-test','gpl-1_4.yml'); 143 my $original = Parse::CPAN::Meta->load_file( $path ); 144 ok( $original, "loaded gpl-1_4.yml" ); 145 my $cmc = CPAN::Meta::Converter->new( $original ); 146 my $up_converted = $cmc->convert( version => 2 ); 147 is_deeply ( $up_converted->{license}, 148 [ "open_source" ], 149 "up converted 'gpl' to 'open_source'" 150 ); 151} 152 153# specific test for upconverting resources 154{ 155 my $path = File::Spec->catfile('t','data-test','resources.yml'); 156 my $original = Parse::CPAN::Meta->load_file( $path ); 157 ok( $original, "loaded resources.yml" ); 158 my $cmc = CPAN::Meta::Converter->new( $original ); 159 my $converted = $cmc->convert( version => 2 ); 160 is_deeply( 161 $converted->{resources}, 162 { x_MailingList => 'http://groups.google.com/group/www-mechanize-users', 163 x_Repository => 'http://code.google.com/p/www-mechanize/source', 164 homepage => 'http://code.google.com/p/www-mechanize/', 165 bugtracker => {web => 'http://code.google.com/p/www-mechanize/issues/list',}, 166 license => ['http://dev.perl.org/licenses/'], 167 }, 168 "upconversion of resources" 169 ); 170} 171 172# specific test for round-tripping resources 173{ 174 my $path = File::Spec->catfile('t','data-test','resources.yml'); 175 my $original = Parse::CPAN::Meta->load_file( $path ); 176 ok( $original, "loaded resources.yml" ); 177 my $cmc1 = CPAN::Meta::Converter->new( $original ); 178 my $converted = $cmc1->convert( version => 2 ); 179 my $cmc2 = CPAN::Meta::Converter->new( $converted ); 180 my $roundtrip = $cmc2->convert( version => 1.4 ); 181 is_deeply( 182 $roundtrip->{resources}, 183 $original->{resources}, 184 "round-trip of resources (1.4->2->1.4)" 185 ); 186} 187 188# specific test for object conversion 189{ 190 my $path = File::Spec->catfile('t','data-test','resources.yml'); 191 my $original = Parse::CPAN::Meta->load_file( $path ); 192 ok( $original, "loaded resources.yml" ); 193 $original->{version} = version->new("1.64"); 194 $original->{no_index}{file} = File::StringObject->new(".gitignore"); 195 pass( "replaced some data fields with objects" ); 196 my $cmc = CPAN::Meta::Converter->new( $original ); 197 ok( my $converted = $cmc->convert( version => 2 ), "conversion successful" ); 198} 199 200# specific test for UTF-8 handling 201{ 202 my $path = File::Spec->catfile('t','data-test','unicode.yml'); 203 my $original = CPAN::Meta->load_file( $path ) 204 or die "Couldn't load $path"; 205 ok( $original, "unicode.yml" ); 206 my @authors = $original->authors; 207 like( $authors[0], qr/Williåms/, "Unicode characters preserved in authors" ); 208} 209 210# specific test for version ranges 211{ 212 my @prereq_keys = qw( 213 prereqs requires build_requires configure_requires 214 recommends conflicts 215 ); 216 for my $case ( qw/ 2 1_4 / ) { 217 my $suffix = $case eq 2 ? "$case.json" : "$case.yml"; 218 my $version = $case; 219 $version =~ tr[_][.]; 220 my $path = File::Spec->catfile('t','data-test','version-ranges-' . $suffix); 221 my $original = Parse::CPAN::Meta->load_file( $path ); 222 ok( $original, "loaded " . basename $path ); 223 my $cmc = CPAN::Meta::Converter->new( $original ); 224 my $converted = $cmc->convert( version => $version ); 225 for my $h ( $original, $converted ) { 226 delete $h->{generated_by}; 227 delete $h->{'meta-spec'}{url}; 228 for my $k ( @prereq_keys ) { 229 _normalize_reqs($h->{$k}) if exists $h->{$k}; 230 } 231 } 232 is_deeply( $converted, $original, "version ranges preserved in conversion" ); 233 } 234} 235 236# specific test for version numbers 237{ 238 my $path = File::Spec->catfile('t','data-test','version-not-normal.json'); 239 my $original = Parse::CPAN::Meta->load_file( $path ); 240 ok( $original, "loaded " . basename $path ); 241 my $cmc = CPAN::Meta::Converter->new( $original ); 242 my $converted = $cmc->convert( version => 2 ); 243 is( $converted->{prereqs}{runtime}{requires}{'File::Find'}, "v0.1.0", "normalize v0.1"); 244 is( $converted->{prereqs}{runtime}{requires}{'File::Path'}, "v1.0.0", "normalize v1.0.0"); 245} 246 247# specific test for missing provides version 248{ 249 my $path = File::Spec->catfile('t','data-test','provides-version-missing.json'); 250 my $original = Parse::CPAN::Meta->load_file( $path ); 251 ok( $original, "loaded " . basename $path ); 252 my $cmc = CPAN::Meta::Converter->new( $original ); 253 my $converted = $cmc->convert( version => 2 ); 254 is_deeply( $converted->{provides}{"Foo::Bar"}, { file => "lib/Foo/Bar.pm", version => "0.27_02" }, 255 "Foo::Bar provides correct" 256 ); 257 is_deeply( $converted->{provides}{"Foo::Bar::Blah"}, { file => "lib/Foo/Bar/Blah.pm" }, 258 "Foo::Bar::Blah provides correct" 259 ); 260 is_deeply( $converted->{provides}{"Foo::Bar::Baz"}, { file => "lib/Foo/Bar/Baz.pm", version => "0.3" }, 261 "Foo::Bar provides correct" 262 ); 263} 264 265# CMR standardizes stuff in a way that makes it hard to test original vs final 266# so we remove spaces and >= to make them compare the same 267sub _normalize_reqs { 268 my $hr = shift; 269 for my $k ( keys %$hr ) { 270 if (ref $hr->{$k} eq 'HASH') { 271 _normalize_reqs($hr->{$k}); 272 } 273 elsif ( ! ref $hr->{$k} ) { 274 $hr->{$k} =~ s{\s+}{}g; 275 $hr->{$k} =~ s{>=\s*}{}g; 276 } 277 } 278} 279 280# specific test for multiple licenses 281{ 282 my $path = File::Spec->catfile('t','data-test','META-2.json'); 283 my $original = Parse::CPAN::Meta->load_file( $path ); 284 ok( $original, "loaded META-2.json" ); 285 my $cmc = CPAN::Meta::Converter->new( $original ); 286 my $cleaned_up = $cmc->convert( version => "2" ); 287 is_deeply( 288 $cleaned_up->{license}, 289 [ 'perl_5', 'bsd' ], 290 "multiple license preserved (v2)" 291 ); 292 293 $cleaned_up = $cmc->convert( version => "1.4" ); 294 is( 295 $cleaned_up->{license}, 296 'open_source', 297 "multiple license converted to open_source (v1.4)" 298 ); 299} 300 301# specific test for preserving release_status on upconversion 302{ 303 my $path = File::Spec->catfile('t','data-test','preserve-release-status.yml'); 304 my $original = Parse::CPAN::Meta->load_file( $path ); 305 ok( $original, "loaded META-2.json" ); 306 my $cmc = CPAN::Meta::Converter->new( $original ); 307 my $cleaned_up = $cmc->convert( version => "2" ); 308 is( $cleaned_up->{release_status}, 'unstable', "release_status preserved" ); 309} 310 311done_testing; 312# vim: ts=2 sts=2 sw=2 et: 313