Nested TAP on Github

Ovid on 2009-03-28T15:30:15

Yesterday I realized how we can finally have nested TAP and make it backwards compatible. Today I've forked Schwern's Test::More and hacked in nested TAP.

#!/usr/bin/env perl

use strict;
use warnings;

use lib '../lib';

# Gotta have a plan!
use Test::More tests => 3;

ok 1;
subtest 'some name' => sub {
    my $num_tests = 2 + int( rand(3) );

    # random plans!
    plan tests => $num_tests;
    ok 1 for 1 .. $num_tests - 1;
    subtest 'some name' => sub {

        # or no plans!
        plan 'no_plan';
        ok 1 for 1 .. 2 + int( rand(3) );
    };
};
ok 1;

Note how we have random plans and no plans, but we can still have a top-level assertion of the number of tests. The output looks something like this:

1..3
ok 1
   1..3
   ok 1
   ok 2
      ok 1
      ok 2
      ok 3
      ok 4
      1..4
   ok 3 - some name
ok 2 - some name
ok 3
ok
All tests successful.
Files=1, Tests=3,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.02 cusr  0.00 csys =  0.04 CPU)
Result: PASS

Note that due to how TAP is specified, that's backwards-compatible with older versions of TAP and the current Test::Harness handles this just fine. Andy Armstrong is now working on being able to offer better parsing tools to understand nested TAP.

There is a Test::Builder interface for this, too.

my $builder = Test::Builder->new;
$builder->plan(tests => 7);
for( 1 .. 3 ) {
    $builder->ok( $_, "We're on $_" );
    $builder->diag("We ran $_");
}
{
    my $indented = $builder->child;
    $indented->plan('no_plan');
    for( 1 .. 1+int(rand(5))  ) {
        $indented->ok( 1, "We're on $_" );
    }
    $indented->finalize;
}
for( 7, 8, 9 ) {
    $builder->ok( $_, "We're on $_" );
}

Eventually we'll add support for being able to compose nested TAP from external sources, but that might require a "TAP envelope" (long story). For now, though, we're ignoring that and focusing on this drool-worthy feature.

So far the Hackathon has been very profitable.