=pod

=encoding UTF-8

=head1 NAME

Test::Tutorial::WritingTools - How to write testing tools.

=head1 Examples

=over 4

=item Complete Example

    package My::Tool;
    use strict;
    use warnings;

    use Test::Stream::Toolset;
    use Test::Stream::Exporter;

    # Export 'validate_widget' by default.
    default_exports qw/validate_widget/;

    sub validate_widget {
        my ($widget, $produces, $name) = @_;
        my $ctx = context(); # Do this early as possible

        my $value = $widget->produce;
        my $ok = $value eq $produces;

        if ($ok) {
            # On success generate an ok event
            $ctx->ok($ok, $name);
        }
        else {
            # On failure generate an OK event with some diagnostics
            $ctx->ok($ok, $name, ["Widget produced '$value'\n Wanted '$produces'"]);
        }

        # It is usually polite to return a true/false value.
        return $ok ? 1 : 0;
    }

    1;

=item Alternate using Exporter.pm

    package My::Tool;
    use strict;
    use warnings;

    use Test::Stream::Toolset;

    # Export 'validate_widget' by default.
    use base 'Exporter';
    our @EXPORT = qw/validate_widget/;

    sub validate_widget {
        my ($widget, $produces, $name) = @_;
        my $ctx = context(); # Do this early as possible

        my $value = $widget->produce;
        my $ok = $value eq $produces;

        if ($ok) {
            # On success generate an ok event
            $ctx->ok($ok, $name);
        }
        else {
            # On failure generate an OK event with some diagnostics
            $ctx->ok($ok, $name, ["Widget produced '$value'\n Wanted '$produces'"]);
        }

        # It is usually polite to return a true/false value.
        return $ok ? 1 : 0;
    }

    1;

=back

=head2 Explanation

L<Test::Stream> is event based. Whenever you want to produce a result you will
generate an event for it. The most common event is L<Test::Stream::Event::Ok>.
Events require some extra information such as where and how they were produced.
In general you do not need to worry about these extra details, they can be
filled in by C<Test::Stream::Context>.

To get a context object you call C<context()> which can be imported from
L<Test::Stream::Context> itself, or from L<Test::Stream::Toolset>. Once you
have a context object you can ask it to issue events for you. All event types
C<Test::Stream::Event::*> get helper methods on the context object.

=head2 IMPORTANT NOTE ON CONTEXTS

The context object has some magic to it. Essentially it is a semi-singleton.
That is if you generate a context object in one place, then try to generate
another one in another place, you will just get the first one again so long as
it still has a reference. If however the first one has fallen out of scope or
been undefined, a new context is generated.

The idea here is that if you nest functions that use contexts, all levels of
depth will get the same initial context. On the other hand 2 functions run in
sequence will get independant context objects. What this means is that you
should NEVER store a context object in a package variable or object attribute.
You should also never assign it to a variable in a higher scope.

C<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 C<context()> is the
same as calling C<context(0)>.

=head1 Nesting calls to other tools

    use Test::More;
    use Test::Stream::Toolset;

    sub compound_check {
        my ($object, $name) = @_;

        # Grab the context now for nested tools to find
        my $ctx = context;

        my $ok = $object ? 1 : 0;
        $ok &&= isa_ok($object, 'Some::Class');
        $ok &&= can_ok($object, qw/foo bar baz/);
        $ok &&= is($object->foo, 'my foo', $name);

        $ctx->ok($ok, $name, $ok ? () : ['Not all object checks passed!']);

        return $ok;
    }

    1;

Nesting tools just works as expected so long as you grab the context BEFORE you
call them. Errors will be reported to the correct file and line number.

=head1 Useful toolsets to look at

=over 4

=item L<Test::More::Tools>

This is the collection of tools used by L<Test::More> under the hood. You can
use these instead of L<Test::More> exports to duplicate functionality without
generating extra events.

=back

=head1 Available Events

Anyone can add an event by shoving it in the C<Test::Stream::Event::*>
namespace. It will autoload if C<< $context->event_name >> is called. But here
is the list of events that come with L<Test::Stream>.

=over 4

=item L<Test::Stream::Event::Ok>

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

Generate an Ok event.

=item L<Test::Stream::Event::Diag>

    $ctx->diag("Diag Message");

Generate a diagniostics (stderr) message

=item L<Test::Stream::Event::Note>

    $ctx->note("Note Message");

Generate a note (stdout) message

=item L<Test::Stream::Event::Bail>

    $ctx->bail("Reason we are bailing");

Stop the entire test file, something is very wrong!

=item L<Test::Stream::Event::Plan>

    $ctx->plan($max);
    $ctx->plan(0, $directive, $reason);

Set the plan.

=back

=head1 Testing your tools

See L<Test::Stream::Tester>, which lets you intercept and validate events.

B<DO NOT SEE> C<Test::Tester> and C<Test::Builder::Tester> which are both
deprecated. They were once the way everyone tested their testers, but they do
not allow you to test all events, and they are very fragile when upstream libs
change.

=head1 SOURCE

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

=head1 MAINTAINER

=over 4

=item Chad Granum E<lt>exodist@cpan.orgE<gt>

=back

=head1 AUTHORS

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

=over 4

=item Chad Granum E<lt>exodist@cpan.orgE<gt>

=item Fergal Daly E<lt>fergal@esatclear.ie>E<gt>

=item Mark Fowler E<lt>mark@twoshortplanks.comE<gt>

=item Michael G Schwern E<lt>schwern@pobox.comE<gt>

=item 唐鳳

=back

=head1 COPYRIGHT

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

=over 4

=item Test::Stream

=item Test::Stream::Tester

Copyright 2014 Chad Granum E<lt>exodist7@gmail.comE<gt>.

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

See F<http://www.perl.com/perl/misc/Artistic.html>

=item Test::Simple

=item Test::More

=item Test::Builder

Originally authored by Michael G Schwern E<lt>schwern@pobox.comE<gt> 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
E<lt>schwern@pobox.comE<gt>, wardrobe by Calvin Klein.

Copyright 2001-2008 by Michael G Schwern E<lt>schwern@pobox.comE<gt>.

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

See F<http://www.perl.com/perl/misc/Artistic.html>

=item Test::use::ok

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

This work is published from Taiwan.

L<http://creativecommons.org/publicdomain/zero/1.0>

=item 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

=item Test::Builder::Tester

Copyright Mark Fowler E<lt>mark@twoshortplanks.comE<gt> 2002, 2004.

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

=back
