=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 provided have been relocated into L 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 under-the-hood module for anyone who wished to write a L-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 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 cloned STDERR and STDOUT and applied various magic to them. This module provides that legacy support while also adding support for L 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 Coutput> 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 and other test tools now boil down to a proper object. All event subclasses must use L as a base. =item Test::Stream::ArrayBase This is the L of L. 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 =back =head2 HISTORY L 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) or for a limited scope. Another option people took (L) 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 method. =head2 CURRENT DESIGN L 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 This method is key to performance. C 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 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 each munger is called in a loop in the C 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 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 each listener is called in a loop in the C 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 has a semi-singleton model. Instead of 1 singleton, it has a singleton stack. Anything that wants to send an event to the B acting stream should send it to the stream returned by Cshared>. Nothing should ever cache this result as the B stream may change. This mechanism is primarily used for intercepting and hiding all events for a limited scope. L 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 =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 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 call to find the correct frame for reporting. B 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 generates a new context and then it calls C. In this case, both functions will have the same context object (the one generated by C). The result is that C will report errors to the correct place. =head3 IMPLEMENTATION There is a lexical variable C<$CURRENT> in C that can not be directly touched. When the C 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 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-Esnapshot>, 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 I am open to changing this to remove the weak-reference magic and instead require someone to call C<$context-Erelease> 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 to set them up as proper event objects. They should also add a method to L 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 This is just a base class. Do not use it directly. =item L =item L =item L =item L These are fairly simple and obvious event types. =item L =item L B C is a subclass of C. C can contain diag objects related to that specific ok. C 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, or L. Under the hood, a L 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. =head1 MAINTAINER =over 4 =item Chad Granum Eexodist@cpan.orgE =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 Eexodist@cpan.orgE =item Fergal Daly Efergal@esatclear.ie>E =item Mark Fowler Emark@twoshortplanks.comE =item Michael G Schwern Eschwern@pobox.comE =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 Eexodist7@gmail.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See F =item Test::Simple =item Test::More =item Test::Builder Originally authored by Michael G Schwern Eschwern@pobox.comE 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 Eschwern@pobox.comE, wardrobe by Calvin Klein. Copyright 2001-2008 by Michael G Schwern Eschwern@pobox.comE. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See F =item Test::use::ok To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to L. This work is published from Taiwan. L =item Test::Tester This module is copyright 2005 Fergal Daly , 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 Emark@twoshortplanks.comE 2002, 2004. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =back