diff options
Diffstat (limited to 'cpan/Test-Simple/lib/Test/Stream/Architecture.pod')
-rw-r--r-- | cpan/Test-Simple/lib/Test/Stream/Architecture.pod | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/cpan/Test-Simple/lib/Test/Stream/Architecture.pod b/cpan/Test-Simple/lib/Test/Stream/Architecture.pod new file mode 100644 index 0000000000..b98ce503ed --- /dev/null +++ b/cpan/Test-Simple/lib/Test/Stream/Architecture.pod @@ -0,0 +1,444 @@ +=head1 NAME + +Test::Stream::Architecture - Overview of how the Test-More dist works. + +=head1 DESCRIPTION + +This is the document that explains the architecture of Test::More and all the +stuff driving it under the hood. + +=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 are the primary public interfaces for anyone who wishes to write tests. + +=item Test::More::Tools + +All of the tools Test::More provides have been relocated and refactored into +Test::More::Tools in such a way as to make them generic and reusable. This +means you can use them without firing off events, you can then fire off your +own events compiled from multiple tools. In many cases this is what tool +builders actually want, but instead they settle for bumping C<$Level> and +calling is/like/ok and producing extra events. + +=item Test::Builder + +This B<used> to be the main 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 compatability wrapper. + +=item Test::Stream + +This is the B<new> heart and soul of the Test::* architecture. However it is +not the primary interface. This module is responsible for collecting all events +from all threads and processes, then forwarding them to TAP and any added +listeners. + +=item Test::Stream::IOSets + +This module is used to manage the IO handles to which all TAP is sent. +Test::Builder cloned STDERR and STDOUT, then applied various magic to them. +This module provides that legacy support while also adding support for 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 Test::Builder->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 proved 3 critical functions: + + is_tester($package) + + init_tester($package) + + my $ctx = context(); + +=item Test::Stream::Context + +This is the primary interface as far as generating events goes. Every test +function should grab a context, and use it to generate events. + +Once a context object is created (the normal way) it is remembered, and +anything that requests a context object will obtain the same instance. However +once the instance is destroyed (end of your test function) it is forgotten, the +next test function to run will then 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 Test::More and other test tools now boil down to a +proper object. All events must use Test::Stream::Event as a base. + +=item Test::Stream::ArrayBase + +This is the L<Moose> of Test::Stream. It is responsible for generating +accessors and similar work. Unlike moose and others it uses an arrayref as the +underlying object. This design decision was made to improve performance. +Performance was a real problem in some early alphas, the gains from the +decision are huge. + +=item Test::Stream::Tester + +This is actually what spawned the ideas for the new Test::Stream work. This is +a module that lets you validate your testing tools. + +=back + +=head1 THE STREAM OBJECT + +=over 4 + +=item L<Test::Stream> + +=back + +=head2 HISTORY + +L<Test::Builder> is/was a singleton. The singleton model was chosen to solve +the problem of synchronizing everything to a central location. Ultimately all +results need to make their way to a central place that can assign them a +number, and shove them through the correct output. + +The singleton model proved to be a major headache. + +Intercepting events typically meant replacing the singleton permanently +(Test::Tester) or for a limited scope. Another option people took +(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 + +Test::Stream unfortunately must still act as a singleton (mostly). But this +time the design was to put as little 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 +what thread or process you are in. (Forking support must be turned on, it is +off by default). + +B<Note:> This method is key to performance. This method and everything it calls +must remain as lean and tight as possible. + +=item Provide a pre-output hook for altering events + + $stream->munge(sub { my ($stream, $event) = @_; ... }) + +This lets you modify events before they are turned into output. You cannot +remove the event, nor can you 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 it as +fast and small as possible. + +=item Forward all events to listeners (including TAP output) + + $stream->listen(sub { my ($stream, $event) = @_; .... }) + +This lets you add a listener. All events that come to 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 it is +fast and small as possible. + +=item Maintaining the legacy exit behavior from Test::Builder + +This is primarily setting $? to the number of tests that failed, up to 255, as +well as providing other output such as missing a plan. + +=back + +=head3 SEMI-SINGLETON MODEL + +Test::Stream has a semi-singleton model. Instead of 1 singleton, it is 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->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 you can generate events that do not go to the listeners or TAP. Once the +stack is popped the previous stream is restored allowing you to generate real +events. + +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 responsbile for 2 things, knowing where to report errors, and +making it easy to issue events. + +=head2 ERROR REPORTING + +To get the context you use the C<context()> function. + + 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. This 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, then it calls C<ok()>, +in this case both function will have the same context object, the one generated +by my_ok. The result is that C<ok> will report errors to the correct place. + +=head3 IMPLEMENTATION + +There is a variable C<$CURRENT> in C<Test::Stream::Context>, it is a lexical, +so you can not touch it directly. When the C<context()> function is called, it +first checks if $CURRENT is set, if so it 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->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->release >> or similar when they +are done with a context, but that seems more likely to result in rougue +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 objects should use L<Test::Stream::Event> which will set them up as a +proper event object, as well as add a method to L<Test::Stream::Context> which +is a shortcut for generating that event type. As such 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 + +Should be 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, you 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 faily 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>. + +Ok can contain diag objects related to that specific ok. Subtest contains all +the events that went into the final subtest result. + +=back + +All events have a context in which they were created, which includes the file +and line number where errors should be reported. They also have details on +where/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 Test::More, or Test::Stream::Context. Under the +hood a Child event is started which adds a subtest to a stack in Test::Stream, +all events then get intercepted by that subtest. When the subtest is done you +issue another Child event to close it out. Once closed a Subtest event will be +generated for you and sent to the stream. + +=encoding utf8 + +=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 |