The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Test::Stream - A modern infrastructure for writing test tools.

SYNOPSIS

    use Test::Stream qw/context/;

    use Test::Stream::Exporter;
    default_exports qw/my_ok/; # Export 'my_ok' by default
    exports qw/my_is/;         # Export 'my_is' by request

    sub my_ok {
        my ($bool, $name) = @_;
        my $ctx = context(); // Get the current context
        $ctx->ok($bool, $name);
        return $bool;
    }

    sub my_is {
        my ($got, $want, $name) = @_;
        my $ctx = context();
        my $bool = $got eq $want;  # This does not account for undef, numerics, or refs
        $ctx->ok($bool, $name);
        return $bool;
    }

    1;

DESCRIPTION

Test::Stream is a testing framework designed to replace Test::Builder. To be precise the project forked Test::Builder and refactored it into its current design. The framework focuses on backwords compatability with Test::Builder, and ease of use for testing tool authors.

Most tools written with Test::Builder will work fine and play nicely with Test::Stream based tools. Test::More gives you everything Test::Builder does, and a whole lot more. If you are looking to write a new testing tool, or update an old one, this is the framework for you!

IMPORT ARGUMENTS

Any import argument not recognised will be treated as an export, if it is not a valid export an exception will be thrown.

use_subtest_buffering => $BOOL

Enable or disable buffering of subtest results. Buffering the results causes the subtest 'ok' to be displayed before the results inside the subtest. This is primarily useful when using threads or fork.

use_subtest_spec => 'legacy'
use_subtest_spec => 'block'

This is used to set the specification used to render subtests. Currenly there is no TAP standard way to render subtests, all current methods are hacks that take advantage of various TAP parsing loopholes.

The 'legacy' spec is the default, it uses indentation for subtest results:

    ok 1 - a result
    # Starting subtest X
        ok 1 - subtest X result 1
        ok 2 - subtest X result 2
        1..2
    ok 2 - subtest X final result

The 'block' spec forces buffering, it wraps results in a block:

    ok 1 - a result
    ok 2 - subtest X final result {
        ok 1 - subtest X result 1
        ok 2 - subtest X result 2
        1..2
    # }
'enable_fork'

Turns on support for code that forks. This is not activated by default because it adds ~30ms to the Test::More compile-time, which can really add up in large test suites. Turn it on only when needed.

'utf8'

Set the TAP encoding to utf8

encoding => '...'

Set the TAP encoding.

COMMON TASKS

MODIFYING EVENTS

    use Test::Stream qw/ munge /;

    munge {
        my ($hub, $event, @subevents) = @_;

        if($event->isa('Test::Stream::Diag')) {
            $event->set_message( "KILROY WAS HERE: " . $event->message );
        }
    };

REPLACING TAP WITH ALTERNATIVE OUTPUT

    use Test::Stream qw/ disable_tap listen /;

    disable_tap();

    listen {
        my $hub = shift;
        my ($event, @subevents) = @_;

        # Tracking results in a db?
        my $id = log_event_to_db($e);
        log_subevent_to_db($id, $_) for @subevents;
    }

END OF TEST BEHAVIORS

    use Test::Stream qw/ follow_up is_passing /;

    follow_up {
        my ($context) = @_;

        if (is_passing()) {
            print "KILROY Says the test file passed!\n";
        }
        else {
            print "KILROY is not happy with you!\n";
        }
    };

ENABLING FORKING SUPPORT

    use Test::Stream 'enable_fork';
    use Test::More;

    # This all just works!
    my $pid = fork();
    if ($pid) { # Parent
        ok(1, "From Parent");
    }
    else { # child
        ok(1, "From Child");
        exit 0;
    }

    done_testing;

or:

    use Test::Stream qw/ enable_forking /;
    use Test::More;

    enable_forking();

    # This all just works now!
    my $pid = fork();
    if ($pid) { # Parent
        ok(1, "From Parent");
    }
    else { # child
        ok(1, "From Child");
        exit 0;
    }

    done_testing;

Note: Result order between processes is not guarenteed, but the test number is handled for you meaning you don't need to care.

Results:

    ok 1 - From Child
    ok 2 - From Parent

Or:

    ok 1 - From Parent
    ok 2 - From Child

REDIRECTING TAP OUTPUT

You may omit any arguments to leave a specific handle unchanged. It is not possible to set a handle to undef or 0 or any other false value.

    use Test::Stream qw/ set_tap_outputs /;

    set_tap_outputs(
        encoding => 'legacy',           # Default,
        std      => $STD_IO_HANDLE,     # equivilent to $TB->output()
        err      => $ERR_IO_HANDLE,     # equivilent to $TB->failure_output()
        todo     => $TODO_IO_HANDLE,    # equivilent to $TB->todo_output()
    );

Note: Each encoding has independant filehandles.

GENERATING EVENTS

EASY WAY

The best way to generate an event is through a Test::Stream::Context object. All events have a method associated with them on the context object. The method will be the last part of the evene package name lowercased, for example Test::Stream::Event::Ok can be issued via $context->ok(...).

    use Test::Stream qw/ context /;
    my $context = context();
    $context->send_event('EVENT_TYPE', ...);

The 5 primary event types each have a shortcut method on Test::Stream::Context:

$context->ok($bool, $name, \@diag)

Issue an Test::Stream::Event::Ok event.

$context->diag($msg)

Issue an Test::Stream::Event::Diag event.

$context->note($msg)

Issue an Test::Stream::Event::Note event.

$context->plan($max, $directive, $reason)

Issue an Test::Stream::Event::Plan event. $max is the number of expected tests. $directive is a plan directive such as 'no_plan' or 'skip_all'. $reason is the reason for the directive (only applicable to skip_all).

$context->bail($reason)

Issue an Test::Stream::Event::Bail event.

HARD WAY

This is not recommended, but it demonstrates just how much the context shortcut methods do for you.

    # First make a context
    my $context = Test::Stream::Context->new(
        frame     => ..., # Where to report errors
        hub       => ..., # Test::Stream object to use
        encoding  => ..., # encoding from test package meta-data
        in_todo   => ..., # Are we in a todo?
        todo      => ..., # Which todo message should be used?
        modern    => ..., # Is the test package modern?
        pid       => ..., # Current PID
        skip      => ..., # Are we inside a 'skip' state?
        provider  => ..., # What tool created the context?
    );

    # Make the event
    my $ok = Test::Stream::Event::Ok->new(
        # Should reflect where the event was produced, NOT WHERE ERRORS ARE REPORTED
        created => [__PACKAGE__, __FILE__,              __LINE__],
        context => $context,     # A context is required
        in_subtest => 0,

        pass => $bool,
        name => $name,
        diag => \@diag,
    );

    # Send the event to the hub.
    Test::Stream->shared->send($ok);

DEFAULT EXPORTS

All of these are functions. These functions all effect the current-shared Test::Stream object only.

$context = context()
$context = context($add_level)

This will get the correct Test::Stream::Context object. This may be one that was previously initialized, or it may generate a new one. Read the Test::Stream::Context documentation for more info.

Note, context() assumes you are at the lowest level of your tool, and looks at the current caller. If you need it to look further you can call it with a numeric argument which is added to the level. To clarify, calling context() is the same as calling context(0).

AVAILABLE EXPORTS

All of these are functions. These functions all effect the current-shared Test::Stream object only.

EVENT MANAGEMENT

These let you install a callback that is triggered for all primary events. The first argument is the Test::Stream object, the second is the primary Test::Stream::Event, any additional arguments are subevents. All subevents are Test::Stream::Event objects which are directly tied to the primary one. The main example of a subevent is the failure Test::Stream::Event::Diag object associated with a failed Test::Stream::Event::Ok, events within a subtest are another example.

listen { my ($hub, $event, @subevents) = @_; ... }

Listen callbacks happen just after TAP is rendered (or just after it would be rendered if TAP is disabled).

munge { my ($hub, $event, @subevents) = @_; ... }

Muinspect_todonge callbacks happen just before TAP is rendered (or just before it would be rendered if TAP is disabled).

POST-TEST BEHAVIOR

follow_up { my ($context) = @_; ... }

A followup callback allows you to install behavior that happens either when done_testing() is called, or when the test file completes.

CAVEAT: If done_testing is not used, the callback will happen in the END {...} block used by Test::Stream to enact magic at the end of the test.

CONCURRENCY

enable_forking()

Turns forking support on. This turns on a synchronization method that *just works* when you fork inside a test. This must be turned on prior to any forking.

cull()

This can only be called in the main process or thread. This is a way to manually pull in results from other processes or threads. Typically this happens automatically, but this allows you to ensure results have been gathered by a specific point.

CONTROL OVER TAP

enable_tap()

Turn TAP on (on by default).

disable_tap()

Turn TAP off.

enable_numbers()

Show test numbers when rendering TAP.

disable_numbers()

Do not show test numbers when rendering TAP.

subtest_buffering($BOOL)

Turn subtest buffering on/off.

subtest_spec($NAME)

Set the subtest specification to use.

Available options: 'legacy', 'block'

The 'legacy' spec is the default, it uses indentation for subtest results:

    ok 1 - a result
    # Starting subtest X
        ok 1 - subtest X result 1
        ok 2 - subtest X result 2
        1..2
    ok 2 - subtest X final result

The 'block' spec forces buffering, it wraps results in a block:

    ok 1 - a result
    ok 2 - subtest X final result {
        ok 1 - subtest X result 1
        ok 2 - subtest X result 2
        1..2
    # }
tap_encoding($ENCODING)

This lets you change the encoding for TAP output. This only effects the current test package.

set_tap_outputs(encoding => 'legacy', std => $IO, err => $IO, todo => $IO)

This lets you replace the filehandles used to output TAP for any specific encoding. All fields are optional, any handles not specified will not be changed. The encoding parameter defaults to 'legacy'.

Note: The todo handle is used for failure output inside subtests where the subtest was started already in todo.

$hashref = get_tap_outputs($encoding)

'legacy' is used when encoding is not specified.

Returns a hashref with the output handles:

    {
        encoding => $encoding,
        std      => $STD_HANDLE,
        err      => $ERR_HANDLE,
        todo     => $TODO_HANDLE,
    }

Note: The todo handle is used for failure output inside subtests where the subtest was started already in todo.

TEST PACKAGE METADATA

$bool = is_modern($package)

Check if a test package has the 'modern' flag.

Note: Throws an exception if $package is not already a test package.

set_modern($package, $value)

Turn on the modern flag for the specified test package.

Note: Throws an exception if $package is not already a test package.

TODO MANAGEMENT

push_todo($todo)
$todo = pop_todo()
$todo = peek_todo()

These can be used to manipulate a global todo state. When a true value is at the top of the todo stack it will effect any events generated via an Test::Stream::Context object. Typically all events are generated this way.

set_todo($package, $todo)

This lets you set the todo state for the specified test package. This will throw an exception if the package is not a test package.

$todo_hashref = inspect_todo($package)
$todo_hashref = inspect_todo()

This lets you inspect the TODO state. Optionally you can specify a package to inspect. The return is a hashref with several keys:

    {
        TODO => $TODO_STACK_ARRAYREF,
        TB   => $TEST_BUILDER_TODO_STATE,
        META => $PACKAGE_METADATA_TODO_STATE,
        PKG  => $package::TODO,
    }

This lets you see what todo states are set where. This is primarily useful when debugging to see why something is unexpectedly TODO, or when something is not TODO despite expectations.

TEST PACKAGE MANAGEMENT

$meta = is_tester($package)

Check if a package is a tester, if it is the meta-object for the tester is returned.

$meta = init_tester($package)

Set the package as a tester and return the meta-object. If the package is already a tester it will return the existing meta-object.

CONTEXTUAL INFORMATION

$hub = current_hub()

This will return the current Test::Stream Object. Test::Stream objects typically live on a global stack, the topmost item on the stack is the one that is normally used.

TEST STATE

$num = state_count()

Check how many tests have been run.

$num = state_failed()

Check how many tests have failed.

$plan_event = state_plan()

Check if a plan has been issued, if so the Test::Stream::Event::Plan instance will be returned.

$bool = state_ended()

True if the test is complete (after done_testing).

$bool = is_passing()

Check if the test state is passing.

HUB STACK FUNCTIONS

At any point there can be any number of hubs. Most hubs will be present in the hub stack. The stack is managed via a collection of class methods. You can always access the "current" or "central" hub using Test::Stream->shared. If you want your events to go where they are supposed to then you should always send them to the shared hub.

It is important to note that any toogle, control, listener, munger, etc. applied to a hub will effect only that hub. Independant hubs, hubs down the stack, and hubs added later will not get any settings from other hubs. Keep this in mind if you take it upon yourself to modify the hub stack.

$hub = Test::Stream::shared
$hub = Test::Stream->shared

Get the current shared hub. The shared hub is the hub at the top of the stack.

Test::Stream::clear
Test::Stream->clear

Completely remove the hub stack. It is very unlikely you will ever want to do this.

($new, $old) = Test::Stream->intercept_start($new)
($new, $old) = Test::Stream->intercept_start

Push a new hub to the top of the stack. If you do not provide a stack a new one will be created for you. If you have one created for you it will have the following differences from a default stack:

    $new->set_exit_on_disruption(0);
    $new->set_use_tap(0);
    $new->set_use_legacy(0);
Test::Stream->intercept_stop($top)

Pop the stack, you must pass in the instance you expect to be popped, there will be an exception if they do not match.

Test::Stream->intercept(sub { ... })
    Test::Stream->intercept(sub {
        my ($new, $old) = @_;

        ...
    });

Temporarily push a new hub to the top of the stack. The codeblock you pass in will be run. Once your codeblock returns the stack will be popped and restored to the previous state.

SOURCE

The source code repository for Test::More can be found at http://github.com/Test-More/test-more/.

MAINTAINER

Chad Granum <exodist@cpan.org>

AUTHORS

The following people have all contributed to the Test-More dist (sorted using VIM's sort function).

Chad Granum <exodist@cpan.org>
Fergal Daly <fergal@esatclear.ie>>
Mark Fowler <mark@twoshortplanks.com>
Michael G Schwern <schwern@pobox.com>
唐鳳

COPYRIGHT

There has been a lot of code migration between modules, here are all the original copyrights together:

Test::Stream
Test::Stream::Tester

Copyright 2015 Chad Granum <exodist7@gmail.com>.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html

Test::Simple
Test::More
Test::Builder

Originally authored by Michael G Schwern <schwern@pobox.com> with much inspiration from Joshua Pritikin's Test module and lots of help from Barrie Slaymaker, Tony Bowden, blackstar.co.uk, chromatic, Fergal Daly and the perl-qa gang.

Idea by Tony Bowden and Paul Johnson, code by Michael G Schwern <schwern@pobox.com>, wardrobe by Calvin Klein.

Copyright 2001-2008 by Michael G Schwern <schwern@pobox.com>.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html

Test::use::ok

To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to Test-use-ok.

This work is published from Taiwan.

http://creativecommons.org/publicdomain/zero/1.0

Test::Tester

This module is copyright 2005 Fergal Daly <fergal@esatclear.ie>, some parts are based on other people's work.

Under the same license as Perl itself

See http://www.perl.com/perl/misc/Artistic.html

Test::Builder::Tester

Copyright Mark Fowler <mark@twoshortplanks.com> 2002, 2004.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.