=pod

=encoding UTF-8

=head1 NAME

Test::Stream::Architecture - overview of how the Test-More dist works.

=head1 DESCRIPTION

This document explains the Test::More architecture from top to bottom.

=head1 KEY COMPONENTS

This is the list of primary components and their brief description, the most
critical ones will have more details in later sections.

=over 4

=item Test::More

=item Test::Simple

These contain the public subroutines for anyone who wishes to write tests.

=item Test::More::Tools

All of the tools that L<Test::More> provided have been relocated into
L<Test::More::Tools> and refactored to make them generic and reusable.

This means you can use them without inadvertently firing off events. In many
cases this is what tool builders actually want but instead they settle for
bumping C<$Level> and calling is(), like(), or ok() and producing extra
events.

=item Test::Builder

This was the B<old> under-the-hood module for anyone who wished to write
a L<Test::More>-compatible test library. It still works and should be fully
functional and backwards compatible. It is, however, discouraged as it is
mostly a compatibility wrapper.

=item Test::Stream

This is the B<new> heart and soul of the Test::* architecture. It is not the
primary interface that a unit-test author will use. This module is responsible
for collecting all events from all threads and processes and then forwarding
them to TAP and any other added listeners.

=item Test::Stream::IOSets

This manages the IO handles to which all TAP is sent.

In the old days, L<Test::Builder> cloned STDERR and STDOUT and applied various
magic to them.

This module provides that legacy support while also adding support for L<utf8>
and other encodings. By default, all TAP goes to the 'legacy' outputs, which
mimick what Test::Builder has always done. The 'legacy' outputs are also
what get altered if someone uses the C<Test::Builder-E<gt>output> interface.

=item Test::Stream::Toolset

This is the primary interface a test module author should use. It ties together
some key functions you should use. It provides 3 critical functions:

    is_tester($package)

    init_tester($package)

    my $ctx = context();

=item Test::Stream::Context

A context is used to generate events in test functions.

Once a context object is created (the normal way) it is remembered and
anything that requests a context object will obtain the same instance.

After the context instance is destroyed (at end of your test function) it is
forgotten. The next test function to run must obtain a new context instance.

=item Test::Stream::Event

=item Test::Stream::Event::Ok

=item Test::Stream::Event::Diag

=item Test::Stream::Event::Note

=item Test::Stream::Event::*

All events generated by L<Test::More> and other test tools now boil down to a
proper object. All event subclasses must use L<Test::Stream::Event> as a base.

=item Test::Stream::ArrayBase

This is the L<Moose> of L<Test::Stream>. It is responsible for generating
accessors and similar work. Unlike Moose, it uses an arrayref as the
underlying object to improve performance. Performance was a real problem in
some early alphas and the speed gains from this decision are huge.

=item Test::Stream::Tester

This module can validate testing tools and their events.

=back

=head1 THE STREAM OBJECT

=over 4

=item L<Test::Stream>

=back

=head2 HISTORY

L<Test::Builder> was (and still is) a singleton. The singleton model was
chosen to solve the problem of synchronizing everything to a central location.
Ultimately, all test results needed to make their way to a central place that
could assign each test a number and create output in the correct order.

The singleton model proved to be a major headache.

Intercepting events typically meant replacing the singleton permanently
(L<Test::Tester>) or for a limited scope. Another option people took
(L<Test::Builder::Tester>) was to simply replace the IO handles
Test::Builder was tracking.

Test::Builder did not provide any real mechanisms for altering events
before processing them, or for intercepting them before they were turned into
TAP. As a result many modules have monkeypatched Test::Builder, particularily
the C<ok()> method.

=head2 CURRENT DESIGN

L<Test::Stream> unfortunately must still act as a singleton (mostly). This
time, the design put as little logic as possible into the singleton.

=head3 RESPONSIBILITIES OF TEST::STREAM

Test::Stream has 4 main jobs:

=over 4

=item Collect events from all threads and processes into 1 place

    $stream->send($event);

The send() method will ensure that the event gets to the right place, no
matter which thread or process your code is in. (Forking support must be turned
on. It is off by default).

B<Note:> This method is key to performance. C<send()> and everything it calls
must remain as lean and tight as possible.

=item Provide a pre-output hook to alter events

    $stream->munge(sub { my ($stream, $event) = @_; ... })

C<munge()> lets you modify events before they are turned into output. It cannot
remove the event, nor can it add events. Mungers are additive and proceessed
in the order they are added.

There is not currently any way to remove a munger.

B<Note:> each munger is called in a loop in the C<send()> method, so keep them
as fast and small as possible.

=item Forward all events to all listeners (including TAP output)

    $stream->listen(sub { my ($stream, $event) = @_; .... })

C<listen()> adds a listener. All events that come from the stream object will
be sent to all listeners.

There is not currently any way to remove a listener.

B<Note:> each listener is called in a loop in the C<send()> method, so keep
them as fast and small as possible.

=item Maintaining the legacy exit behavior from Test::Builder

This is sets C<$?> to the number of tests that failed (up to 255). It also
provides some other output such as when a test file is missing a plan.

=back

=head3 SEMI-SINGLETON MODEL

L<Test::Stream> has a semi-singleton model. Instead of 1 singleton, it has a
singleton stack. Anything that wants to send an event to the B<current> acting
stream should send it to the stream returned by C<Test::Stream-E<gt>shared>.
Nothing should ever cache this result as the B<current> stream may change.

This mechanism is primarily used for intercepting and hiding all events for a
limited scope. L<Test::Stream::Tester> uses this to push a stream onto the
stack so that events can be generated that do not go to the listeners or TAP.
Once the stack is popped, the previous stream is restored, which allows real
events to be generated.

You can also create new Test::Stream objects at-will that are not present in
the stack. This lets you create alternate streams for any purpose you want.

=head1 THE CONTEXT OBJECT

=over 4

=item L<Test::Stream::Context>

=back

This module is responsible for 2 things: knowing where to report errors and
making it easy to issue events.

=head2 ERROR REPORTING

Use the C<context()> function to get the current context.

    sub ok {
        my $context = context();
        ...
    }

    ok() # Errors are reported here.

If there is a context already in play, that instance will be returned.
Otherwise, a new context will be returned.

The context assumes that the stack level just above your call is where errors
should be reported.

You can optionally provide an integer as the only argument, in which case that
number will be added to the C<caller()> call to find the correct frame for
reporting.

B<Note:> The integer argument will be completely ignored if there is already
an active context.

    sub ok {
        my $context = context();
        ...
    }

    sub my_ok {
        my $context = context();
        ok(...);
    }

    my_ok();

In the example above, c<my_ok()> generates a new context and then it calls
C<ok()>. In this case, both functions will have the same context object (the
one generated by C<my_ok()>). The result is that C<ok> will report errors to
the correct place.

=head3 IMPLEMENTATION

There is a lexical variable C<$CURRENT> in C<Test::Stream::Context> that can
not be directly touched. When the C<context()> function is called, it first
checks if $CURRENT is set, and if so, returns that. If there is no current
context, it generates a new one.

When a new context is generated, it is assigned to C<$CURRENT>, but then the
reference is weakened. This means that once the returned copy falls out of
scope, or is otherwise removed, C<$CURRENT> will vanish on its own. This means
that so long as you hold on to your context object, anything you call will find
it.

B<The caveat> here is that if you decide to hold on to your context beyond
your scope, you could sabatoge any future test functions. If you need to hold
on to a context you need to call C<$context-E<gt>snapshot>, and store the
cloned object it returns. In general you should not need to do this. Event
objects all store the context but do so using a snapshot.

B<Note> I am open to changing this to remove the weak-reference magic and
instead require someone to call C<$context-E<gt>release> or similar when they
are done with a context but that seems more likely to result in rogue
contexts. This method would also require its own form of reference counting.
This decision will need to be made before we go stable.

=head2 GENERATING EVENTS

All event subclasses should use L<Test::Stream::Event> to set them up as
proper event objects. They should also add a method to
L<Test::Stream::Context> to be used as a shortcut for generating that event
type. That will let you can fire off an event directly from your context
object using the lowercase name of the event class.

    my $ctx = context;
    $ctx->ok(1, "pass");
    $ctx->ok(0, "fail, ["This test failed, here is some diag ..."]);
    $ctx->note("I am a teapot");

All events take a context and 2 other arguments as the first 3 arguments of
their constructor, these shortcut methods handle those first 3 arguments for
you, making life much easier.

The other arguments are:

=over 4

=item created

an arrayref with caller information for where the event was generated.

=item in_subtest

True if the event belongs in a subtest, false otherwise.

=back

=head1 EVENT OBJECTS

Here are the primary public events. There are other events, but they are used
internally.

=over 4

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

This is just a base class. Do not use it directly.

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

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

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

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

These are fairly simple and obvious event types.

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

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

B<Note:> C<Subtest> is a subclass of C<Ok>.

C<Ok> can contain diag objects related to that specific ok. C<Subtest>
contains all the events that went into the final subtest result.

=back

All events have the context in which they were created, which includes the
file and line number where errors should be reported. They also have details
on where and how they were generated. All other details are event-specific.

The subclass event should never be generated on its own. In fact, just use the
subtest helpers provided by L<Test::More>, or L<Test::Stream::Context>. Under
the hood, a L<Child> event is started which adds a subtest to a stack in
Test::Stream, and then all events get intercepted by that subtest. When the
subtest is done, issue another Child event to close it out. Once closed, a
Subtest event will be generated for you and sent to the stream.

=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
