On 2012.7.11 2:39 PM, Daniel Perrett wrote:
> I may have missed the point here, but would it be sufficient to have
> two flavours of diagnostic calls, distinguishing between pre-test
> diagnostics (`forewarn()`) and post-test diagnostics (`reflect()`), or
> is the problem that ok() must be a single function call?

Rather than tell you what I think the solution should be, let me frame the
problem.  I'm going to use a fictional XML format for illustration, but the
problem applies to a broad class of formats which are different than TAP.

Consider this test...

    #line 12
    ok( 0, "something" );

and the output in our fictional XML format might look like this...

<result>
    <status>fail</status>
    <name>something</name>
    <line>12</line>
</result>

The important thing to note is that the result has a clear start and end.

Now, if all information about a result has to go inside the <result> tag, how
does this code...

    #line 12
    ok( 0, "something" );
    info( { have => "this", want => "that" } );

Know to produce this output...

<result>
    <status>fail</status>
    <name>something</name>
    <line>12</line>
    <attr key="have">this</attr>
    <attr key="want">that</attr>
</result>

...and yet still work when there is no tap_diag() call after the ok()?

There are a number of alternative interfaces to solve the problem.  Making
each assert a single function call is the "best" from the point of view of
ease of formatting, but requires every assert to take an extra argument.  I
feel this is getting bulky from an interface perspective, but maybe it's ok.

    ok( 0, "something", {
        have => "this", want => "that"
    });

Another one would be to turn results into objects and only format when they go
out of scope...

    ok( 0, "something" )->info({ have => "this", want => "that" });

...but that goes pear shaped if somebody does this.

    $results{$test} = is( $this, $that );

You could do some clever tricks where the formatter waits until the next
result to display a result, in case extra info comes in.

    # store the result.
    ok( 0, "something" );

    # attach this to the previous result.
    info( { have => "this", want => "that" } );

    # format and display the previous result and info.
    # store this result.
    ok( 0, "something else" );

    # format and display the previous result with no extra info.
    # store this result.
    ok( 0, "something more" );

    # format and display the previous result.
    # end the test.
    done_testing();

...but that significantly complicates the formatters and puts streamed output
on a delay.  Very confusing if you're stepping through the code.

Right now the "all in one" version seems best.  It's explicit.  It's simple.


> If that's possible, maybe we can extend it to guess at what the
> various messages mean: most diags can be assumed to be of the
> `reflect()` type, as that's typical behaviour, e.g. Test::More, while
> more perlish warnings is most likely to be of the `forewarn()`
> variety.

I think we don't have to guess at that.  Structured diagnostics are only
associated with test results (and possibly start/end of test info).  They're
not used like diag() is now as both a warning mechanism and a test result
information system.

Since this is a new interface, we can deal with that by making different
functions for each different intent.  One for "this goes with the previous
result".  One for "this is general test information".  And one for "this is
just a diagnostic dump for and not associated with anything".


-- 
You know what the chain of command is? It's the chain I go get and beat you
with 'til you understand who's in ruttin' command here.
        -- Jayne Cobb, "Firefly"

Reply via email to