xref: /openbsd-src/gnu/usr.bin/perl/cpan/CPAN-Meta-YAML/t/lib/TestBridge.pm (revision b8851fcc53cbe24fd20b090f26dd149e353f6174)
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