16fb12b70Safresh1package TestBridge; 26fb12b70Safresh1 36fb12b70Safresh1use strict; 46fb12b70Safresh1use warnings; 5*b8851fccSafresh1use lib 't/lib'; 6*b8851fccSafresh1use Test::More 0.88; 7*b8851fccSafresh1use SubtestCompat; 86fb12b70Safresh1use TestUtils; 96fb12b70Safresh1use TestML::Tiny; 106fb12b70Safresh1 116fb12b70Safresh1BEGIN { 126fb12b70Safresh1 $| = 1; 136fb12b70Safresh1 binmode(Test::More->builder->$_, ":utf8") 146fb12b70Safresh1 for qw/output failure_output todo_output/; 156fb12b70Safresh1} 166fb12b70Safresh1 176fb12b70Safresh1use CPAN::Meta::YAML; 186fb12b70Safresh1 196fb12b70Safresh1use Exporter (); 206fb12b70Safresh1our @ISA = qw{ Exporter }; 216fb12b70Safresh1our @EXPORT = qw{ 226fb12b70Safresh1 run_all_testml_files 236fb12b70Safresh1 run_testml_file 246fb12b70Safresh1 test_yaml_roundtrip 256fb12b70Safresh1 test_perl_to_yaml 266fb12b70Safresh1 test_dump_error 276fb12b70Safresh1 test_load_error 28*b8851fccSafresh1 test_load_warning 296fb12b70Safresh1 test_yaml_json 306fb12b70Safresh1 test_code_point 316fb12b70Safresh1 error_like 326fb12b70Safresh1 cmp_deeply 336fb12b70Safresh1 _testml_has_points 346fb12b70Safresh1}; 356fb12b70Safresh1 366fb12b70Safresh1# regular expressions for checking error messages; incomplete, but more 376fb12b70Safresh1# can be added as more error messages get test coverage 386fb12b70Safresh1my %ERROR = ( 396fb12b70Safresh1 E_CIRCULAR => qr{\QCPAN::Meta::YAML does not support circular references}, 406fb12b70Safresh1 E_FEATURE => qr{\QCPAN::Meta::YAML does not support a feature}, 416fb12b70Safresh1 E_PLAIN => qr{\QCPAN::Meta::YAML found illegal characters in plain scalar}, 426fb12b70Safresh1 E_CLASSIFY => qr{\QCPAN::Meta::YAML failed to classify the line}, 436fb12b70Safresh1); 446fb12b70Safresh1 45*b8851fccSafresh1my %WARN = ( 46*b8851fccSafresh1 E_DUPKEY => qr{\QCPAN::Meta::YAML found a duplicate key}, 47*b8851fccSafresh1); 48*b8851fccSafresh1 496fb12b70Safresh1# use XXX -with => 'YAML::XS'; 506fb12b70Safresh1 516fb12b70Safresh1#--------------------------------------------------------------------------# 526fb12b70Safresh1# run_all_testml_files 536fb12b70Safresh1# 546fb12b70Safresh1# Iterate over all .tml files in a directory using a particular test bridge 55*b8851fccSafresh1# code # reference. Each file is wrapped in a subtest. 566fb12b70Safresh1#--------------------------------------------------------------------------# 576fb12b70Safresh1 586fb12b70Safresh1sub run_all_testml_files { 596fb12b70Safresh1 my ($label, $dir, $bridge, @args) = @_; 606fb12b70Safresh1 616fb12b70Safresh1 my $code = sub { 626fb12b70Safresh1 my ($file, $blocks) = @_; 636fb12b70Safresh1 subtest "$label: $file" => sub { 646fb12b70Safresh1 $bridge->($_, @args) for @$blocks; 656fb12b70Safresh1 }; 666fb12b70Safresh1 }; 676fb12b70Safresh1 686fb12b70Safresh1 my @files = find_tml_files($dir); 696fb12b70Safresh1 706fb12b70Safresh1 run_testml_file($_, $code) for sort @files; 716fb12b70Safresh1} 726fb12b70Safresh1 736fb12b70Safresh1sub run_testml_file { 746fb12b70Safresh1 my ($file, $code) = @_; 756fb12b70Safresh1 766fb12b70Safresh1 my $blocks = TestML::Tiny->new( 776fb12b70Safresh1 testml => $file, 786fb12b70Safresh1 version => '0.1.0', 796fb12b70Safresh1 )->{function}{data}; 806fb12b70Safresh1 816fb12b70Safresh1 $code->($file, $blocks); 826fb12b70Safresh1} 836fb12b70Safresh1 84*b8851fccSafresh1# retrieves all the keys in @point from the $block hash, returning them in 85*b8851fccSafresh1# order, along with $block->{Label}. 86*b8851fccSafresh1# returns false if any keys cannot be found 876fb12b70Safresh1sub _testml_has_points { 886fb12b70Safresh1 my ($block, @points) = @_; 896fb12b70Safresh1 my @values; 906fb12b70Safresh1 for my $point (@points) { 916fb12b70Safresh1 defined $block->{$point} or return; 926fb12b70Safresh1 push @values, $block->{$point}; 936fb12b70Safresh1 } 946fb12b70Safresh1 push @values, $block->{Label}; 956fb12b70Safresh1 return @values; 966fb12b70Safresh1} 976fb12b70Safresh1 986fb12b70Safresh1#--------------------------------------------------------------------------# 996fb12b70Safresh1# test_yaml_roundtrip 1006fb12b70Safresh1# 1016fb12b70Safresh1# two blocks: perl, yaml 1026fb12b70Safresh1# 1036fb12b70Safresh1# Tests that a YAML string loads to the expected perl data. Also, tests 1046fb12b70Safresh1# roundtripping from perl->YAML->perl. 1056fb12b70Safresh1# 1066fb12b70Safresh1# We can't compare the YAML for roundtripping because CPAN::Meta::YAML doesn't 1076fb12b70Safresh1# preserve order and comments. Therefore, all we can test is that given input 1086fb12b70Safresh1# YAML we can produce output YAML that produces the same Perl data as the 1096fb12b70Safresh1# input. 1106fb12b70Safresh1# 1116fb12b70Safresh1# The perl must be an array reference of data to serialize: 1126fb12b70Safresh1# 1136fb12b70Safresh1# [ $thing1, $thing2, ... ] 1146fb12b70Safresh1# 1156fb12b70Safresh1# However, if a test point called 'serializes' exists, the output YAML is 1166fb12b70Safresh1# expected to match the input YAML and will be checked for equality. 1176fb12b70Safresh1#--------------------------------------------------------------------------# 1186fb12b70Safresh1 1196fb12b70Safresh1sub test_yaml_roundtrip { 1206fb12b70Safresh1 my ($block) = @_; 1216fb12b70Safresh1 1226fb12b70Safresh1 my ($yaml, $perl, $label) = 1236fb12b70Safresh1 _testml_has_points($block, qw(yaml perl)) or return; 1246fb12b70Safresh1 1256fb12b70Safresh1 my %options = (); 1266fb12b70Safresh1 for (qw(serializes)) { 1276fb12b70Safresh1 if (defined($block->{$_})) { 1286fb12b70Safresh1 $options{$_} = 1; 1296fb12b70Safresh1 } 1306fb12b70Safresh1 } 1316fb12b70Safresh1 1326fb12b70Safresh1 my $expected = eval $perl; die $@ if $@; 1336fb12b70Safresh1 bless $expected, 'CPAN::Meta::YAML'; 1346fb12b70Safresh1 1356fb12b70Safresh1 subtest $label, sub { 1366fb12b70Safresh1 # Does the string parse to the structure 1376fb12b70Safresh1 my $yaml_copy = $yaml; 1386fb12b70Safresh1 my $got = eval { CPAN::Meta::YAML->read_string( $yaml_copy ); }; 1396fb12b70Safresh1 is( $@, '', "CPAN::Meta::YAML parses without error" ); 1406fb12b70Safresh1 is( $yaml_copy, $yaml, "CPAN::Meta::YAML does not modify the input string" ); 1416fb12b70Safresh1 SKIP: { 1426fb12b70Safresh1 skip( "Shortcutting after failure", 2 ) if $@; 1436fb12b70Safresh1 isa_ok( $got, 'CPAN::Meta::YAML' ); 1446fb12b70Safresh1 cmp_deeply( $got, $expected, "CPAN::Meta::YAML parses correctly" ) 1456fb12b70Safresh1 or diag "ERROR: $CPAN::Meta::YAML::errstr\n\nYAML:$yaml"; 1466fb12b70Safresh1 } 1476fb12b70Safresh1 1486fb12b70Safresh1 # Does the structure serialize to the string. 1496fb12b70Safresh1 # We can't test this by direct comparison, because any 1506fb12b70Safresh1 # whitespace or comments would be lost. 1516fb12b70Safresh1 # So instead we parse back in. 1526fb12b70Safresh1 my $output = eval { $expected->write_string }; 1536fb12b70Safresh1 is( $@, '', "CPAN::Meta::YAML serializes without error" ); 1546fb12b70Safresh1 SKIP: { 1556fb12b70Safresh1 skip( "Shortcutting after failure", 5 ) if $@; 1566fb12b70Safresh1 ok( 1576fb12b70Safresh1 !!(defined $output and ! ref $output), 1586fb12b70Safresh1 "CPAN::Meta::YAML serializes to scalar", 1596fb12b70Safresh1 ); 1606fb12b70Safresh1 my $roundtrip = eval { CPAN::Meta::YAML->read_string( $output ) }; 1616fb12b70Safresh1 is( $@, '', "CPAN::Meta::YAML round-trips without error" ); 1626fb12b70Safresh1 skip( "Shortcutting after failure", 2 ) if $@; 1636fb12b70Safresh1 isa_ok( $roundtrip, 'CPAN::Meta::YAML' ); 1646fb12b70Safresh1 cmp_deeply( $roundtrip, $expected, "CPAN::Meta::YAML round-trips correctly" ); 1656fb12b70Safresh1 1666fb12b70Safresh1 # Testing the serialization 1676fb12b70Safresh1 skip( "Shortcutting perfect serialization tests", 1 ) unless $options{serializes}; 1686fb12b70Safresh1 is( $output, $yaml, 'Serializes ok' ); 1696fb12b70Safresh1 } 1706fb12b70Safresh1 1716fb12b70Safresh1 }; 1726fb12b70Safresh1} 1736fb12b70Safresh1 1746fb12b70Safresh1#--------------------------------------------------------------------------# 1756fb12b70Safresh1# test_perl_to_yaml 1766fb12b70Safresh1# 1776fb12b70Safresh1# two blocks: perl, yaml 1786fb12b70Safresh1# 1796fb12b70Safresh1# Tests that perl references serialize correctly to a specific YAML output 1806fb12b70Safresh1# 1816fb12b70Safresh1# The perl must be an array reference of data to serialize: 1826fb12b70Safresh1# 1836fb12b70Safresh1# [ $thing1, $thing2, ... ] 1846fb12b70Safresh1#--------------------------------------------------------------------------# 1856fb12b70Safresh1 1866fb12b70Safresh1sub test_perl_to_yaml { 1876fb12b70Safresh1 my ($block) = @_; 1886fb12b70Safresh1 1896fb12b70Safresh1 my ($perl, $yaml, $label) = 1906fb12b70Safresh1 _testml_has_points($block, qw(perl yaml)) or return; 1916fb12b70Safresh1 1926fb12b70Safresh1 my $input = eval "no strict; $perl"; die $@ if $@; 1936fb12b70Safresh1 1946fb12b70Safresh1 subtest $label, sub { 1956fb12b70Safresh1 my $result = eval { CPAN::Meta::YAML->new( @$input )->write_string }; 1966fb12b70Safresh1 is( $@, '', "write_string lives" ); 1976fb12b70Safresh1 is( $result, $yaml, "dumped YAML correct" ); 1986fb12b70Safresh1 }; 1996fb12b70Safresh1} 2006fb12b70Safresh1 2016fb12b70Safresh1#--------------------------------------------------------------------------# 2026fb12b70Safresh1# test_dump_error 2036fb12b70Safresh1# 2046fb12b70Safresh1# two blocks: perl, error 2056fb12b70Safresh1# 2066fb12b70Safresh1# Tests that perl references result in an error when dumped 2076fb12b70Safresh1# 2086fb12b70Safresh1# The perl must be an array reference of data to serialize: 2096fb12b70Safresh1# 2106fb12b70Safresh1# [ $thing1, $thing2, ... ] 2116fb12b70Safresh1# 2126fb12b70Safresh1# The error must be a key in the %ERROR hash in this file 2136fb12b70Safresh1#--------------------------------------------------------------------------# 2146fb12b70Safresh1 2156fb12b70Safresh1sub test_dump_error { 2166fb12b70Safresh1 my ($block) = @_; 2176fb12b70Safresh1 2186fb12b70Safresh1 my ($perl, $error, $label) = 2196fb12b70Safresh1 _testml_has_points($block, qw(perl error)) or return; 2206fb12b70Safresh1 2216fb12b70Safresh1 my $input = eval "no strict; $perl"; die $@ if $@; 2226fb12b70Safresh1 chomp $error; 2236fb12b70Safresh1 my $expected = $ERROR{$error}; 2246fb12b70Safresh1 2256fb12b70Safresh1 subtest $label, sub { 2266fb12b70Safresh1 my $result = eval { CPAN::Meta::YAML->new( @$input )->write_string }; 2276fb12b70Safresh1 ok( !$result, "returned false" ); 2286fb12b70Safresh1 error_like( $expected, "Got expected error" ); 2296fb12b70Safresh1 }; 2306fb12b70Safresh1} 2316fb12b70Safresh1 2326fb12b70Safresh1#--------------------------------------------------------------------------# 2336fb12b70Safresh1# test_load_error 2346fb12b70Safresh1# 2356fb12b70Safresh1# two blocks: yaml, error 2366fb12b70Safresh1# 2376fb12b70Safresh1# Tests that a YAML string results in an error when loaded 2386fb12b70Safresh1# 2396fb12b70Safresh1# The error must be a key in the %ERROR hash in this file 2406fb12b70Safresh1#--------------------------------------------------------------------------# 2416fb12b70Safresh1 2426fb12b70Safresh1sub test_load_error { 2436fb12b70Safresh1 my ($block) = @_; 2446fb12b70Safresh1 2456fb12b70Safresh1 my ($yaml, $error, $label) = 2466fb12b70Safresh1 _testml_has_points($block, qw(yaml error)) or return; 2476fb12b70Safresh1 2486fb12b70Safresh1 chomp $error; 2496fb12b70Safresh1 my $expected = $ERROR{$error}; 2506fb12b70Safresh1 2516fb12b70Safresh1 subtest $label, sub { 2526fb12b70Safresh1 my $result = eval { CPAN::Meta::YAML->read_string( $yaml ) }; 2536fb12b70Safresh1 is( $result, undef, 'read_string returns undef' ); 2546fb12b70Safresh1 error_like( $expected, "Got expected error" ) 2556fb12b70Safresh1 or diag "YAML:\n$yaml"; 2566fb12b70Safresh1 }; 2576fb12b70Safresh1} 2586fb12b70Safresh1 2596fb12b70Safresh1#--------------------------------------------------------------------------# 260*b8851fccSafresh1# test_load_warning 261*b8851fccSafresh1# 262*b8851fccSafresh1# two blocks: yaml, warning 263*b8851fccSafresh1# 264*b8851fccSafresh1# Tests that a YAML string results in warning when loaded 265*b8851fccSafresh1# 266*b8851fccSafresh1# The warning must be a key in the %WARN hash in this file 267*b8851fccSafresh1#--------------------------------------------------------------------------# 268*b8851fccSafresh1sub test_load_warning { 269*b8851fccSafresh1 my ($block) = @_; 270*b8851fccSafresh1 271*b8851fccSafresh1 my ($yaml, $warning, $label) = 272*b8851fccSafresh1 _testml_has_points($block, qw(yaml warning)) or return; 273*b8851fccSafresh1 274*b8851fccSafresh1 chomp $warning; 275*b8851fccSafresh1 my $expected = $WARN{$warning}; 276*b8851fccSafresh1 277*b8851fccSafresh1 subtest $label, sub { 278*b8851fccSafresh1 # this is not in a sub like warning_like because of the danger of 279*b8851fccSafresh1 # matching the regex parameter against something earlier in the stack 280*b8851fccSafresh1 my @warnings; 281*b8851fccSafresh1 local $SIG{__WARN__} = sub { push @warnings, shift; }; 282*b8851fccSafresh1 283*b8851fccSafresh1 my $result = eval { CPAN::Meta::YAML->read_string( $yaml ) }; 284*b8851fccSafresh1 285*b8851fccSafresh1 is(scalar(@warnings), 1, 'got exactly one warning'); 286*b8851fccSafresh1 like( 287*b8851fccSafresh1 $warnings[0], 288*b8851fccSafresh1 $expected, 289*b8851fccSafresh1 'Got expected warning', 290*b8851fccSafresh1 ) or diag "YAML:\n$yaml\n", 'warning: ', explain(\@warnings); 291*b8851fccSafresh1 }; 292*b8851fccSafresh1} 293*b8851fccSafresh1 294*b8851fccSafresh1#--------------------------------------------------------------------------# 2956fb12b70Safresh1# test_yaml_json 2966fb12b70Safresh1# 2976fb12b70Safresh1# two blocks: yaml, json 2986fb12b70Safresh1# 2996fb12b70Safresh1# Tests that a YAML string can be loaded to Perl and dumped to JSON and 3006fb12b70Safresh1# match an expected JSON output. The expected JSON is loaded and dumped 3016fb12b70Safresh1# to ensure similar JSON dump options. 3026fb12b70Safresh1#--------------------------------------------------------------------------# 3036fb12b70Safresh1 3046fb12b70Safresh1sub test_yaml_json { 3056fb12b70Safresh1 my ($block, $json_lib) = @_; 3066fb12b70Safresh1 $json_lib ||= do { require JSON::PP; 'JSON::PP' }; 3076fb12b70Safresh1 3086fb12b70Safresh1 my ($yaml, $json, $label) = 3096fb12b70Safresh1 _testml_has_points($block, qw(yaml json)) or return; 3106fb12b70Safresh1 3116fb12b70Safresh1 subtest "$label", sub { 3126fb12b70Safresh1 # test YAML Load 3136fb12b70Safresh1 my $object = eval { 3146fb12b70Safresh1 CPAN::Meta::YAML::Load($yaml); 3156fb12b70Safresh1 }; 3166fb12b70Safresh1 my $err = $@; 3176fb12b70Safresh1 ok !$err, "YAML loads"; 3186fb12b70Safresh1 return if $err; 3196fb12b70Safresh1 3206fb12b70Safresh1 # test YAML->Perl->JSON 3216fb12b70Safresh1 # N.B. round-trip JSON to decode any \uNNNN escapes and get to 3226fb12b70Safresh1 # characters 3236fb12b70Safresh1 my $want = $json_lib->new->encode( 3246fb12b70Safresh1 $json_lib->new->decode($json) 3256fb12b70Safresh1 ); 3266fb12b70Safresh1 my $got = $json_lib->new->encode($object); 3276fb12b70Safresh1 is $got, $want, "Load is accurate"; 3286fb12b70Safresh1 }; 3296fb12b70Safresh1} 3306fb12b70Safresh1 3316fb12b70Safresh1#--------------------------------------------------------------------------# 3326fb12b70Safresh1# test_code_point 3336fb12b70Safresh1# 3346fb12b70Safresh1# two blocks: code, yaml 3356fb12b70Safresh1# 3366fb12b70Safresh1# Tests that a Unicode codepoint is correctly dumped to YAML as both 3376fb12b70Safresh1# key and value. 3386fb12b70Safresh1# 3396fb12b70Safresh1# The code test point must be a non-negative integer 3406fb12b70Safresh1# 3416fb12b70Safresh1# The yaml code point is the expected output of { $key => $value } where 3426fb12b70Safresh1# both key and value are the character represented by the codepoint. 3436fb12b70Safresh1#--------------------------------------------------------------------------# 3446fb12b70Safresh1 3456fb12b70Safresh1sub test_code_point { 3466fb12b70Safresh1 my ($block) = @_; 3476fb12b70Safresh1 3486fb12b70Safresh1 my ($code, $yaml, $label) = 3496fb12b70Safresh1 _testml_has_points($block, qw(code yaml)) or return; 3506fb12b70Safresh1 3516fb12b70Safresh1 subtest "$label - Unicode map key/value test" => sub { 3526fb12b70Safresh1 my $data = { chr($code) => chr($code) }; 3536fb12b70Safresh1 my $dump = CPAN::Meta::YAML::Dump($data); 3546fb12b70Safresh1 $dump =~ s/^---\n//; 3556fb12b70Safresh1 is $dump, $yaml, "Dump key and value of code point char $code"; 3566fb12b70Safresh1 3576fb12b70Safresh1 my $yny = CPAN::Meta::YAML::Dump(CPAN::Meta::YAML::Load($yaml)); 3586fb12b70Safresh1 $yny =~ s/^---\n//; 3596fb12b70Safresh1 is $yny, $yaml, "YAML for code point $code YNY roundtrips"; 3606fb12b70Safresh1 3616fb12b70Safresh1 my $nyn = CPAN::Meta::YAML::Load(CPAN::Meta::YAML::Dump($data)); 3626fb12b70Safresh1 cmp_deeply( $nyn, $data, "YAML for code point $code NYN roundtrips" ); 3636fb12b70Safresh1 } 3646fb12b70Safresh1} 3656fb12b70Safresh1 3666fb12b70Safresh1#--------------------------------------------------------------------------# 3676fb12b70Safresh1# error_like 3686fb12b70Safresh1# 3696fb12b70Safresh1# Test CPAN::Meta::YAML->errstr against a regular expression and clear the 3706fb12b70Safresh1# errstr afterwards 3716fb12b70Safresh1#--------------------------------------------------------------------------# 3726fb12b70Safresh1 3736fb12b70Safresh1sub error_like { 3746fb12b70Safresh1 my ($regex, $label) = @_; 3756fb12b70Safresh1 $label = "Got expected error" unless defined $label; 3766fb12b70Safresh1 local $Test::Builder::Level = $Test::Builder::Level + 1; 3776fb12b70Safresh1 my $ok = like( $@, $regex, $label ); 3786fb12b70Safresh1 return $ok; 3796fb12b70Safresh1} 3806fb12b70Safresh1 3816fb12b70Safresh1#--------------------------------------------------------------------------# 3826fb12b70Safresh1# cmp_deeply 3836fb12b70Safresh1# 3846fb12b70Safresh1# is_deeply with some better diagnostics 3856fb12b70Safresh1#--------------------------------------------------------------------------# 3866fb12b70Safresh1sub cmp_deeply { 3876fb12b70Safresh1 my ($got, $want, $label) = @_; 3886fb12b70Safresh1 local $Test::Builder::Level = $Test::Builder::Level + 1; 3896fb12b70Safresh1 is_deeply( $got, $want, $label ) 3906fb12b70Safresh1 or diag "GOT:\n", explain($got), "\nWANTED:\n", explain($want); 3916fb12b70Safresh1} 3926fb12b70Safresh1 3936fb12b70Safresh11; 394