Delving the depths of computing,
hoping not to get eaten by a wumpus

By Timm Murray

Underappreciated Perl Code: TAP's YAMLish Syntax

2013-10-07


If you write tests using Test::More, you may have seen the cmp_ok() sub output something like:

$ perl -MTest::More -E 'plan tests => 1; cmp_ok( 1, "==", 2, "fail" )'
1..1
not ok 1 - fail
#   Failed test 'fail'
#   at -e line 1.
#          got: 1
#     expected: 2
# Looks like you failed 1 test of 1.

This is a textual output of the file and line number of the tests, as well as what failed. If you wanted to write a TAP parser for a report, you could parse the comments and get that file location. But then you’d be parsing comments, and those aren’t supposed to be parsed by computers (SKIP and TODO being exceptions in TAP for hysterical raisins). Plus, Test::More makes no guarantees about the format of those comments, nor should it.

Fortunately, the TAP protocol has an official extension for parsable information about a test, called “YAMLish“. As the name implies, it’s a small subset of YAML, specifically the one supported by YAML::Tiny. This makes it easy to implement in other languages.

Test::More doesn’t seem to support outputting YAMLish, but we can get the functionality with TAP::Parser::YAMLish::Writer. We can write up a subroutine for a tests to handle YAMLish:

#!/usr/bin/perl
use v5.14;
use warnings;
use Test::More tests => 1;
use TAP::Parser::YAMLish::Writer;
use DateTime;


# Need to have write_yaml() on the same line so its line number output is correct
cmp_ok( 1, '==', 2, "Fail" ); write_yaml( 1, 2, { foo => 'bar' } );


my $yw = undef;
sub write_yaml
{
    my ($expected, $actual, $extensions) = @_;
    $yw = TAP::Parser::YAMLish::Writer->new
        unless defined $yw;
    my ($pack, $filename, $line) = caller;

    my $dt = DateTime->now;
    my $date = $dt->iso8601();

    my %fields = (
        datetime   => $date,
        file       => $filename,
        line       => $line,
        expected   => $expected,
        actual     => $actual,
        extensions => $extensions,
    );

    $yw->write( \%fields, \*STDOUT );
    return 1;
}

The keys datetime, file, line, expected, actual, and extensions are defined directly on the wiki page for YAMLish. The extensions key is a hashref that can hold custom information. The datetime key is in either ISO8601 or HTTP date format.

Output:

$ perl yamlish_example.pl 
1..1
not ok 1 - Fail
#   Failed test 'Fail'
#   at yamlish_example.pl line 9.
#          got: 1
#     expected: 2
---
actual: 2
datetime: 2013-10-06T16:55:14
expected: 1
extensions:
  foo: bar
file: yamlish_example.pl
line: 9
...
# Looks like you failed 1 test of 1.

But this is awkward and ought to be wrapped up by a CPAN module. The requirement for write_yaml() to be on the same line is particularly bad. Duplicating your actual/expected values in the call to write_yaml() is no good, either.

It’d be nice if Test::More did this for us, or barring that, a drop-in replacement. After a quick search, I can’t seem to find anything like that. Any takers? :)



Copyright © 2024 Timm Murray
CC BY-NC

Opinions expressed are solely my own and do not express the views or opinions of my employer.