Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,88 @@
package Test2::Manual::Anatomy;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy - The hub for documentation of the inner workings of
Test2 components.
=head1 DESCRIPTION
This section covers internals of the Test2 architecture. This is useful
information for toolbuilder, but is essential information for maintainers of
Test2 itself.
=head1 END TO END
The L<Test2::Manual::Anatomy::EndToEnd> document is an overview of Test2 from load to finish.
=head1 EVENTS
The L<Test2::Manual::Anatomy::Event> document explains the internals of events.
=head1 THE CONTEXT
The L<Test2::Manual::Anatomy::Context> document explains how the
L<Test2::API::Context> object works.
=head1 THE API AND THE API INSTANCE
The L<Test2::Manual::Anatomy::API> document explains the inner workings of the
Test2 API.
=head1 HUBS
The L<Test2::Manual::Anatomy::Hubs> document explains the inner working of
the Test2 hub stack, and the hubs therein.
=head1 THE IPC SYSTEM
The L<Test2::Manual::Anatomy::IPC> document describes the IPC system.
=head1 INTERNAL UTILITIES
The L<Test2::Manual::Anatomy::Utilities> document describes various utilities
provided by the Test2 system.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,78 @@
package Test2::Manual::Anatomy::API;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::API - Internals documentation for the API.
=head1 DESCRIPTION
This document covers some of the internals of L<Test2::API>.
=head1 IMPLEMENTATION DETAILS
=head2 Test2::API
L<Test2::API> provides a functional interface to any test2 global state. This
API should be preserved regardless of internal details of how and where the
global state is stored.
This module itself does not store any state (with a few minor exceptions) but
instead relies on L<Test2::API::Instance> to store state. This module is really
intended to be the layer between the consumer and the implementation details.
Ideally the implementation details can change any way they like, and this
module can be updated to use the new details without breaking anything.
=head2 Test2::API::Instance
L<Test2::API::Instance> is where the global state is actually managed. This is
an implementation detail, and should not be relied upon. It is entirely
possible that L<Test2::API::Instance> could be removed completely, or changed
in incompatible ways. Really these details are free to change so long as
L<Test2::API> is not broken.
L<Test2::API::Instance> is fairly well documented, so no additionally
documentation is needed for this manual page.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,114 @@
package Test2::Manual::Anatomy::Context;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Context - Internals documentation for the Context
objects.
=head1 DESCRIPTION
This document explains how the L<Test2::API::Context> object works.
=head1 WHAT IS THE CONTEXT OBJECT?
The context object is one of the key components of Test2, and makes many
features possible that would otherwise be impossible. Every test tool starts by
getting a context, and ends by releasing the context. A test tool does all its
work between getting and releasing the context. The context instance is the
primary interface for sending events to the Test2 stack. Finally the context
system is responsible for tracking what file and line number a tool operates
on, which is critical for debugging.
=head2 PRIMARY INTERFACE FOR TEST TOOLS
Nearly every Test2 based tool should start by calling C<$ctx =
Test2::API::context()> in order to get a context object, and should end by
calling C<< $ctx->release() >>. Once a tool has its context object it can call
methods on the object to send events or have other effects. Nearly everything a
test tool needs to do should be done through the context object.
=head2 TRACK FILE AND LINE NUMBERS FOR ERROR REPORTING
When you call C<Test2::API::Context> a new context object will be returned. If
there is already a context object in effect (from a different point in the
stack) you will get a clone of the existing one. If there is not already a
current context then a completely new one will be generated. When a new context
is generated Test2 will determine the file name and line number for your test
code, these will be used when reporting any failures.
Typically the file and line number will be determined using C<caller()> to look
at your tools caller. The C<$Test::Builder::Level> will be respected if
detected, but is discouraged in favor of just using context objects at every
level.
When calling C<Test2::API::Context()> you can specify the
C<< level => $count >> arguments if you need to look at a deeper caller.
=head2 PRESERVE $?, $!, $^E AND $@
When you call C<Test2::API::context()> the current values of C<$?>, C<$!>,
C<$^E>, and C<$@> are stored in the context object itself. Whenever the context
is released the original values of these variables will be restored. This
protects the variables from any side effects caused by testing tools.
=head2 FINALIZE THE API STATE
L<Test2::API> works via a hidden singleton instance of L<Test2::API::Instance>.
The singleton has some state that is not set in stone until the last possible
minute. The last possible minute happens to be the first time a context is
acquired. State includes IPC instance, Formatter class, Root PID, etc.
=head2 FIND/CREATE THE CURRENT/ROOT HUB
L<Test2> has a stack of hubs, the stack can be accessed via
L<Test2::API::test2_stack>. When you get a context it will find the current
hub, if there is no current hub then the root one will be initialized.
=head2 PROVIDE HOOKS
There are hooks that run when contexts are created, found, and released. See
L<Test2::API> for details on these hooks and how to use them.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,376 @@
package Test2::Manual::Anatomy::EndToEnd;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::EndToEnd - Overview of Test2 from load to finish.
=head1 DESCRIPTION
This is a high level overview of everything from loading Test2 through the end
of a test script.
=head1 WHAT HAPPENS WHEN I LOAD THE API?
use Test2::API qw/context/;
=over 4
=item A singleton instance of Test2::API::Instance is created.
You have no access to this, it is an implementation detail.
=item Several API functions are defined that use the singleton instance.
You can import these functions, or use them directly.
=item Then what?
It waits...
The API intentionally does as little as possible. At this point something can
still change the formatter, load L<Test2::IPC>, or have other global effects
that need to be done before the first L<Test2::API::Context> is created. Once
the first L<Test2::API::Context> is created the API will finish initialization.
See L</"WHAT HAPPENS WHEN I ACQUIRE A CONTEXT?"> for more information.
=back
=head1 WHAT HAPPENS WHEN I USE A TOOL?
This section covers the basic workflow all tools such as C<ok()> must follow.
sub ok($$) {
my ($bool, $name) = @_;
my $ctx = context();
my $event = $ctx->send_event('Ok', pass => $bool, name => $name);
...
$ctx->release;
return $bool;
}
ok(1, "1 is true");
=over 4
=item A tool function is run.
ok(1, "1 is true");
=item The tool acquires a context object.
my $ctx = context();
See L</"WHAT HAPPENS WHEN I ACQUIRE A CONTEXT?"> for more information.
=item The tool uses the context object to create, send, and return events.
See L</"WHAT HAPPENS WHEN I SEND AN EVENT?"> for more information.
my $event = $ctx->send_event('Ok', pass => $bool, name => $name);
=item When done the tool MUST release the context.
See L</"WHAT HAPPENS WHEN I RELEASE A CONTEXT?"> for more information.
$ctx->release();
=item The tool returns.
return $bool;
=back
=head1 WHAT HAPPENS WHEN I ACQUIRE A CONTEXT?
my $ctx = context();
These actions may not happen exactly in this order, but that is an
implementation detail. For the purposes of this document this order is used to
help the reader understand the flow.
=over 4
=item $!, $@, $? and $^E are captured and preserved.
Test2 makes a point to preserve the values of $!, $@, $? and $^E such that the test
tools do not modify these variables unexpectedly. They are captured first thing
so that they can be restored later.
=item The API state is changed to 'loaded'.
The 'loaded' state means that test tools have already started running. This is
important as some plugins need to take effect before any tests are run. This
state change only happens the first time a context is acquired, and may trigger
some hooks defined by plugins to run.
=item The current hub is found.
A context attaches itself to the current L<Test2::Hub>. If there is no current
hub then the root hub will be initialized. This will also initialize the hub
stack if necessary.
=item Context acquire hooks fire.
It is possible to create global, or hub-specific hooks that fire whenever a
context is acquired, these hooks will fire now. These hooks fire even if there
is an existing context.
=item Any existing context is found.
If the current hub already has a context then a clone of it will be used
instead of a completely new context. This is important because it allows nested
tools to inherit the context used by parent tools.
=item Stack depth is measured.
Test2 makes a point to catch mistakes in how the context is used. The stack
depth is used to accomplish this. If there is an existing context the depth
will be checked against the one found here. If the old context has the same
stack depth, or a shallower one, it means a tool is misbehaving and did not
clean up the context when it was done, in which case the old context will be
cleaned up, and a warning issued.
=item A new context is created (if no existing context was found)
If there is no existing context, a new one will be created using the data
collected so far.
=item Context init hooks fire (if no existing context was found)
If a new context was created, context-creation hooks will fire.
=item $!, $@, $?, and $^E are restored.
We make sure $!, $@, $?, and $^E are unchanged at this point so that changes we
made will not effect anything else. This is done in case something inside the
context construction accidentally changed these vars.
=item The context is returned.
You have a shiney new context object, or a clone of the existing context.
=back
=head1 WHAT HAPPENS WHEN I SEND AN EVENT?
my $event = $ctx->send_event('Ok', pass => $bool, name => $name);
=over 4
=item The Test2::Event::Ok module is loaded.
The C<send_event()> method will automatically load any Event package necessary.
Normally C<send_event()> will assume the first argument is an event class
without the C<Test2::Event::> prefix, which it will add for you. If you want to
use an event class that is in a different namespace you can prefix the class
name with a C<+> to tell the tool that you are giving a fully qualified class
name:
my $event = $ctx->send_event('+Fully::Qualified::Event', pass => $bool, name => $name);
=item A new instance of Test2::Event::Ok is created.
The event object is instantiated using the provided parameters.
=item The event object is sent to the hub.
The hub takes over from here.
=item The hub runs the event through any filters.
Filters are able to modify or remove events. Filters are run first, before the
event can modify global test state.
=item The global test state is updated to reflect the event.
If the event effects test count then the count will be incremented. If the
event causes failure then the failure count will be incremented. There are a
couple other ways the global state can be effected as well.
=item The event is sent to the formatter
After the state is changed the hub will send the event to the formatter for
rendering. This is where TAP is normally produced.
=item The event is sent to all listeners.
There can be any number of listeners that take action when events are
processed, this happens now.
=back
=head1 WHAT HAPPENS WHEN I RELEASE A CONTEXT?
$ctx->release;
=over 4
=item The current context clone is released.
If your tool is nested inside another, then releasing will simply destroy the
copy of the context, nothing else will happen.
=item If this was the canonical context, it will actually release
When a context is created it is considered 'canon'. Any context obtained by a
nested tool will be considered a child context linked to the canonical one.
Releasing child contexts does not do anything of note (but is still required).
=item Release hooks are called
Release hooks are the main motivation behind making the C<release()> method,
and making it a required action on the part of test tools. These are hooks that
we can have called when a tool is complete. This is how plugins like
L<Test2::Plugin::DieOnFail> are implemented. If we simply had a destructor call
the hooks then we would be unable to write this plugin as a C<die> inside of a
destructor is useless.
=item The context is cleared
The main context data is cleared allowing the next tool to create a new
context. This is important as the next tool very likely has a new line number.
=item $!, $@, $?, and $^E are restored
When a Test2 tool is complete it will restore $@, $!, $? and $^E to avoid action at
a distance.
=back
=head1 WHAT HAPPENS WHEN I USE done_testing()?
done_testing();
=over 4
=item Any pending IPC events will be culled.
If IPC is turned on, a final culling will take place.
=item Follow-up hooks are run
The follow-up hooks are a way to run actions when a hub is complete. This is
useful for adding cleanup tasks, or final tests to the end of a test.
=item The final plan event is generated and processed.
The final plan event will be produced using the current test count as the
number of tests planned.
=item The current hub is finalized.
This will mark the hub is complete, and will not allow new events to be
processed.
=back
=head1 WHAT HAPPENS WHEN A TEST SCRIPT IS DONE?
Test2 has some behaviors it runs in an C<END { ... }> block after tests are
done running. This end block does some final checks to warn you if something
went wrong. This end block also sets the exit value of the script.
=over 4
=item API Versions are checked.
A warning will be produced if L<Test::Builder> is loaded, but has a different
version compared to L<Test2::API>. This situation can happen if you downgrade
to an older Test-Simple distribution, and is a bad situation.
=item Any remaining context objects are cleaned up.
If there are leftover context objects they will need to be cleaned up. A
leftover context is never a good thing, and usually requires a warning. A
leftover context could also be the result of an exception being thrown which
terminates the script, L<Test2> is fairly good at noticing this and not warning
in these cases as the warning would simply be noise.
=item Child processes are sent a 'waiting' event.
If IPC is active, a waiting event is sent to all child processes.
=item The script will wait for all child processes and/or threads to complete.
This happens only when IPC is loaded, but Test::Builder is not. This behavior
is useful, but would break compatibility for legacy tests.
=item The hub stack is cleaned up.
All hubs are finalized starting from the top. Leftover hubs are usually a bad
thing, so a warning is produced if any are found.
=item The root hub is finalized.
This step is a no-op if C<done_testing()> was used. If needed this will mark
the root hub as finished.
=item Exit callbacks are called.
This is a chance for plugins to modify the final exit value of the script.
=item The scripts exit value ($?) is set.
If the test encountered any failures this will be set to a non-zero value. If
possible this will be set to the number of failures, or 255 if the number is
larger than 255 (the max value allowed).
=item Broken module diagnostics
Test2 is aware of many modules which were broken by Test2's release. At this
point the script will check if any known-broken modules were loaded, and warn
you if they were.
B<Note:> This only happens if there were test failures. No broken module
warnings are produced on a success.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,416 @@
package Test2::Manual::Anatomy::Event;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Event - The internals of events
=head1 DESCRIPTION
Events are how tools effect global state, and pass information along to the
harness, or the human running the tests.
=head1 HISTORY
Before proceeding it is important that you know some history of events.
Initially there was an event API, and an event would implement the API to
produce an effect. This API proved to be lossy and inflexible. Recently the
'facet' system was introduced, and makes up for the shortcoming and
inflexibility of the old API.
All events must still implement the old API, but that can be largely automated
if you use the facet system effectively. Likewise essential facets can often be
deduced from events that only implement the old API, though their information
maybe less complete.
=head1 THE EVENT OBJECT
All event objects must subclass L<Test2::Event>. If you inherit from this base
class, and implement the old API properly, facets will be generated for you for
free. On the other hand you can inherit from this, and also import
L<Test2::Util::Facets2Legacy> which will instead rely on your facet data, and
deduce the old API from them.
All new events C<MUST> implement both APIs one way or the other. A common way
to do this is to simply implement both APIs directly in your event.
Here is a good template for a new event:
package Test2::Event::Mine;
use strict;
use warnings;
use parent 'Test2::Event';
use Test2::Util::Facets2Legacy ':ALL';
sub facet_data {
my $self = shift;
# Adds 'about', 'amnesty', and 'trace' facets
my $out = $self->common_facet_data;
# Add any additional facets to the $out hashref
...
return $out;
}
1;
=head1 THE FACET API
The new API is a single method: C<facet_data()>. This method must return a
hashref where each key is specific to a facet type, and the value is either a
facet hashref, or an array of hashrefs. Some facets C<MUST> be lone hashrefs,
others C<MUST> be hashrefs inside an arrayref.
The I<standard> facet types are as follows:
=over 4
=item assert => {details => $name, pass => $bool, no_debug => $bool, number => $maybe_int}
Documented in L<Test2::EventFacet::Assert>. An event may only have one.
The 'details' key is the name of the assertion.
The 'pass' key denotes a passing or failing assertion.
The 'no_debug' key tells any harness or formatter that diagnostics should not
be added automatically to a failing assertion (used when there are custom
diagnostics instead).
The 'number' key is for harness use, never set it yourself.
=item about => {details => $string, no_display => $bool, package => $pkg}
Documented in L<Test2::EventFacet::About>. An event may only have one.
'details' is a human readable string describing the overall event.
'no_display' means that a formatter/harness should hide the event.
'package' is the package of the event the facet describes (IE: L<Test2::Event::Ok>)
=item amnesty => [{details => $string, tag => $short_string, inherited => $bool}]
Documented in L<Test2::EventFacet::Amnesty>. An event may have multiple.
This event is how things like 'todo' are implemented. Amnesty prevents a
failing assertion from causing a global test failure.
'details' is a human readable description of why the failure is being granted
amnesty (IE The 'todo' reason)
'tag' is a short human readable string, or category for the amnesty. This is
typically 'TODO' or 'SKIP'.
'inherited' is true if the amnesty was applied in a parent context (true if
this test is run in a subtest that is marked todo).
=item control => {details => $string, global => $bool, terminate => $maybe_int, halt => $bool, has_callback => $bool, encoding => $enc}
Documented in L<Test2::EventFacet::Control>. An event may have one.
This facet is used to apply extra behavior when the event is processed.
'details' is a human readable explanation for the behavior.
'global' true if this event should be forwarded to, and processed by, all hubs
everywhere. (bail-out uses this)
'terminate' this should either be undef, or an integer. When defined this will
cause the test to exit with the specific exit code.
'halt' is used to signal any harness that no further test files should be run
(bail-out uses this).
'has_callback' is set to true if the event has a callback sub defined.
'encoding' used to tell the formatter what encoding to use.
=item errors => [{details => $string, tag => $short_string, fail => $bool}]
Documented in L<Test2::EventFacet::Error>. An event may have multiple.
'details' is a human readable explanation of the error.
'tag' is a short human readable category for the error.
'fail' is true if the error should cause test failure. If this is false the
error is simply informative, but not fatal.
=item info => [{details => $string, tag => $short_string, debug => $bool, important => $bool}]
Documented in L<Test2::EventFacet::Info>. An event may have multiple.
This is how diag and note are implemented.
'details' human readable message.
'tag' short category for the message, such as 'diag' or 'note'.
'debug' is true if the message is diagnostics in nature, this is the main
difference between a note and a diag.
'important' is true if the message is not diagnostics, but is important to have
it shown anyway. This is primarily used to communicate with a harness.
=item parent => {details => $string, hid => $hid, children => [...], buffered => 1}
Documented in L<Test2::EventFacet::Parent>. An event may have one.
This is used by subtests.
'details' human readable name of the subtest.
'hid' subtest hub id.
'children' an arrayref containing facet_data instances from all child events.
'buffered' true if it was a buffered subtest.
=item plan => {details => $string, count => $int, skip => $bool, none => $bool}
Documented in L<Test2::EventFacet::Plan>. An event may have one.
'details' is a human readable string describing the plan (for instance, why a
test is skipped)
'count' is the number of expected assertions (0 for skip)
'skip' is true if the plan is to skip the test.
'none' used for Test::More's 'no_plan' plan.
=item trace => {details => $string, frame => [$pkg, $file, $line, $sub], pid => $int, tid => $int, cid => $cid, hid => $hid, nested => $int, buffered => $bool}
Documented in L<Test2::EventFacet::Trace>. An event may have one.
This is how debugging information is tracked. This is taken from the context
object at event creation.
'details' human readable debug message (otherwise generated from frame)
'frame' first 4 fields returned by caller:
C<[$package, $file, $line, $subname]>.
'pid' the process id in which the event was created.
'tid' the thread is in which the event was created.
'cid' the id of the context used to create the event.
'hid' the id of the hub to which the event was sent.
'nest' subtest nesting depth of the event.
'buffered' is true if the event was generated inside a buffered subtest.
=back
Note that ALL facet types have a 'details' key that may have a string. This
string should always be human readable, and should be an explanation for the
facet. For an assertion this is the test name. For a plan this is the reason
for the plan (such as skip reason). For info it is the human readable
diagnostics message.
=head2 CUSTOM FACETS
You can write custom facet types as well, simply add a new key to the hash and
populated it. The general rule is that any code looking at the facets should
ignore any it does not understand.
Optionally you can also create a package to document your custom facet. The
package should be proper object, and may have additional methods to help work
with your facet.
package Test2::EventFacet::MyFacet;
use parent 'Test2::EventFacet';
sub facet_key { 'myfacet' }
sub is_list { 0 }
1;
Your facet package should always be under the Test2::EventFacet:: namespace if
you want any tools to automatically find it. The last part of the namespace
should be the non-plural name of your facet with only the first word
capitalized.
=over 4
=item $string = $facet_class->facet_key
The key for your facet should be the same as the last section of
the namespace, but all lowercase. You I<may> append 's' to the key if your
facet is a list type.
=item $bool = $facet_class->is_list
True if an event should put these facets in a list:
{ myfacet => [{}, {}] }
False if an event may only have one of this type of facet at a time:
{ myfacet => {} }
=back
=head3 EXAMPLES
The assert facet is not a list type, so its implementation would look like this:
package Test2::EventFacet::Assert;
sub facet_key { 'assert' }
sub is_list { 0 }
The amnesty facet is a list type, but amnesty does not need 's' appended to
make it plural:
package Test2::EventFacet::Amnesty;
sub facet_key { 'amnesty' }
sub is_list { 1 }
The error facet is a list type, and appending 's' makes error plural as errors.
This means the package name is '::Error', but the key is 'errors'.
package Test2::EventFacet::Error;
sub facet_key { 'errors' }
sub is_list { 1 }
B<Note> Do not worry too much about getting the key/pluralization wrong. Most
tools will use L<Module::Pluggable> to load all facet types and build a hash
linking keys to packages and so on, working backwards. This means, in general,
that even if you get it wrong any tool that NEEDS the package for the facet
will find it.
B<Note2:> In practice most tools completely ignore the facet packages, and work
with the facet data directly in its raw structure. This is by design and
recommended. The facet data is intended to be serialized frequently and passed
around. When facets are concerned, data is important, classes and methods are
not.
=head1 THE OLD API
The old API was simply a set of methods you were required to implement:
=over 4
=item $bool = $e->causes_fail
Returns true if this event should result in a test failure. In general this
should be false.
=item $bool = $e->increments_count
Should be true if this event should result in a test count increment.
=item $e->callback($hub)
If your event needs to have extra effects on the L<Test2::Hub> you can override
this method.
This is called B<BEFORE> your event is passed to the formatter.
=item $num = $e->nested
If this event is nested inside of other events, this should be the depth of
nesting. (This is mainly for subtests)
=item $bool = $e->global
Set this to true if your event is global, that is ALL threads and processes
should see it no matter when or where it is generated. This is not a common
thing to want, it is used by bail-out and skip_all to end testing.
=item $code = $e->terminate
This is called B<AFTER> your event has been passed to the formatter. This
should normally return undef, only change this if your event should cause the
test to exit immediately.
If you want this event to cause the test to exit you should return the exit
code here. Exit code of 0 means exit success, any other integer means exit with
failure.
This is used by L<Test2::Event::Plan> to exit 0 when the plan is
'skip_all'. This is also used by L<Test2::Event:Bail> to force the test
to exit with a failure.
This is called after the event has been sent to the formatter in order to
ensure the event is seen and understood.
=item $msg = $e->summary
This is intended to be a human readable summary of the event. This should
ideally only be one line long, but you can use multiple lines if necessary. This
is intended for human consumption. You do not need to make it easy for machines
to understand.
The default is to simply return the event package name.
=item ($count, $directive, $reason) = $e->sets_plan()
Check if this event sets the testing plan. It will return an empty list if it
does not. If it does set the plan it will return a list of 1 to 3 items in
order: Expected Test Count, Test Directive, Reason for directive.
=item $bool = $e->diagnostics
True if the event contains diagnostics info. This is useful because a
non-verbose harness may choose to hide events that are not in this category.
Some formatters may choose to send these to STDERR instead of STDOUT to ensure
they are seen.
=item $bool = $e->no_display
False by default. This will return true on events that should not be displayed
by formatters.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,120 @@
package Test2::Manual::Anatomy::Hubs;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Hubs - Internals documentation for the hub stack, and
hubs.
=head1 DESCRIPTION
This document describes the hub stack, and the hubs it contains. It explains
why we have a stack, and when to add/remove hubs from it.
=head1 WHAT IS A HUB?
Test2 is an event system, tools generate events, those events are then
processed to modify the testing state (number of tests, number of failures,
etc). The hub is responsible for receiving and processing events to record the
change in state. All events should eventually reach a destination hub.
The base hub is L<Test2::Hub>. All hub classes should inherit from the base hub
class. The base hub class provides several hooks that allow you to monitor or
modify events. Hubs are also responsible for forwarding events to the output
formatter.
=head1 WHY DO WE HAVE A HUB STACK?
There are cases where it makes sense to have more than one hub:
=over 4
=item subtests
In Test2 subtests are implemented using the hub stack. When you start a subtest
a new L<Test2::Hub::Subtest> instance is created and pushed to the stack. Once
this is done all calls to C<Test2::API::context> will find the new hub and send
all events to it. When the subtest tool is complete it will remove the new hub,
and send a final subtest event to the parent hub.
=item testing your test tools
C<Test2::API::intercept()> is implemented using the hub stack. The
C<Test2::API::intercept()> function will add an L<Test2::Hub::Interceptor>
instance to the stack, any calls to L<Test2::API::context()> will find the new
hub, and send it all events. The intercept hub is special in that is has no
connection to the parent hub, and usually does not have a formatter.
=back
=head1 WHEN SHOULD I ADD A HUB TO THE STACK?
Any time you want to intercept or block events from effecting the test state.
Adding a new hub is essentially a way to create a sandbox where you have
absolute control over what events do. Adding a new hub insures that the main
test state will not be effected.
=head1 WHERE IS THE STACK?
The stack is an instance of L<Test2::API::Stack>. You can access the global hub
stack using C<Test2::API::test2_stack>.
=head1 WHAT ABOUT THE ROOT HUB?
The root hub is created automatically as needed. A call to
C<< Test2::API::test2_stack->top() >> will create the root hub if it does not
already exist.
=head1 HOW DO HUBS HANDLE IPC?
If the IPC system (L<Test2::IPC>) was not loaded, then IPC is not handled at
all. Forking or creating new threads without the IPC system can cause
unexpected problems.
All hubs track the PID and Thread ID that was current when they were created.
If an event is sent to a hub in a new process/thread the hub will detect this
and try to forward the event along to the correct process/thread. This is
accomplished using the IPC system.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,90 @@
package Test2::Manual::Anatomy::IPC;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::IPC - Manual for the IPC system.
=head1 DESCRIPTION
This document describes the IPC system.
=head1 WHAT IS THE IPC SYSTEM
The IPC system is activated by loading L<Test2::IPC>. This makes hubs
process/thread aware, and makes them forward events along to the parent
process/thread as necessary.
=head1 HOW DOES THE IPC SYSTEM EFFECT EVERYTHING?
L<Test2::API> and L<Test2::API::Instance> have some behaviors that trigger if
L<Test2::IPC> is loaded before the global state is initialized. Mainly an IPC
driver will be initiated and stored in the global state.
If an IPC driver is initialized then all hubs will be initialized with a
reference to the driver instance. If a hub has an IPC driver instance it will
use it to forward events to parent processes and threads.
=head1 WHAT DOES AN IPC DRIVER DO?
An L<Test2::IPC::Driver> provides a way to send event data to a destination
process+thread+hub (or to all globally). The driver must also provide a way for
a process/thread/hub to read in any pending events that have been sent to it.
=head1 HOW DOES THE DEFAULT IPC DRIVER WORK?
The default IPC driver is L<Test2::API::Driver::Files>. This default driver,
when initialized, starts by creating a temporary directory. Any time an event
needs to be sent to another process/thread/hub, the event will be written to a
file using L<Storable>. The file is written with the destination process,
thread, and hub as part of the filename. All hubs will regularly check for
pending IPC events and will process them.
This driver is further optimized using a small chunk of SHM. Any time a new
event is sent via IPC the shm is updated to have a new value. Hubs will not
bother checking for new IPC events unless the shm value has changed since their
last poll. A result of this is that the IPC system is surprisingly fast, and
does not waste time polling the hard drive when there are no pending events.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,76 @@
package Test2::Manual::Anatomy::Utilities;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Anatomy::Utilities - Overview of utilities for Test2.
=head1 DESCRIPTION
This is a brief overview of the utilities provided by Test2.
=head1 Test2::Util
L<Test2::Util> provides functions to help you find out about the current
system, or to run generic tasks that tend to be Test2 specific.
This utility provides things like an internal C<try {...}> implementation, and
constants for things like threading and forking support.
=head1 Test2::Util::ExternalMeta
L<Test2::Util::ExternalMeta> allows you to quickly and easily attach meta-data
to an object class.
=head1 Test2::Util::Facets2Legacy
L<Test2::Util::Facets2Legacy> is a set of functions you can import into a more
recent event class to provide the classic event API.
=head1 Test2::Util::HashBase
L<Test2::Util::HashBase> is a local copy of L<Object::HashBase>. All object
classes provided by L<Test2> use this to generate methods and accessors.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,143 @@
package Test2::Manual::Concurrency;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Concurrency - Documentation for Concurrency support.
=head1 FORKING
=head2 Test2
Test2 supports forking. For forking to work you need to load L<Test2::IPC>.
=head2 Test::Builder
L<Test::Builder> Did not used to support forking, but now that it is based on
L<Test2> it does. L<Test2::IPC> must be loaded just as with L<Test2>.
=head2 Test2::Suite
L<Test2::Suite> tools should all work fine with I<true> forking unless
otherwise noted. Pseudo-fork via threads (Windows and a few others) is not
supported, but may work.
Patches will be accepted to repair any pseudo-fork issues, but for these to be
used or tested they must be requested. Fork tests should not run on pseudo-fork
systems unless they are requested with an environment var, or the
AUTHOR_TESTING var. Pseudo-fork is fragile, and we do not want to block install
due to a pseudo-fork flaw.
=head2 Test::SharedFork
L<Test::SharedFork> is currently support and maintained, though it is no longer
necessary thanks to L<Test2::IPC>. If usage ever drops off then the module may
be deprecated, but for now the policy is to not let it break. Currently it
simply loads L<Test2::IPC> if it can, and falls back to the old methods on
legacy installs.
=head2 Others
Individual authors are free to support or not support forking as they see fit.
=head1 THREADING
B<Note> This only applies to ithreads.
=head2 Test2
The core of Test2 supports threading so long as L<Test2::IPC> is loaded. Basic
threading support (making sure events make it to the parent thread) is fully
supported, and must not be broken.
Some times perl installs have broken threads (Some 5.10 versions compiled on
newer gcc's will segv by simply starting a thread). This is beyond Test2's
control, and not solvable in Test2. That said we strive for basic threading
support on perl 5.8.1+.
If Test2 fails for threads on any perl 5.8 or above, and it is reasonably
possible for Test2 to work around the issue, it should. (Patches and bug
reports welcome).
=head2 Test::Builder
L<Test::Builder> has had thread support for a long time. With Test2 the
mechanism for thread support was switched to L<Test2::IPC>. L<Test::Builder>
should still support threads as much as it did before the switch to Test2.
Support includes auto-enabling thread support if L<threads> is loaded before
Test::Builder.
If there is a deviation between the new and old threading behavior then it is a
bug (unless the old behavior itself can be classified as a bug.) Please report
(or patch!) any such threading issues.
=head2 Test2::Suite
Tools in L<Test2::Suite> have minimal threading support. Most of these tools do
not care/notice threading and simply work because L<Test2::IPC> handles it.
Feel free to report any thread related bugs in Test2::Suite. Be aware though
that these tools are not legacy, and have no pre-existing thread support, we
reserve the right to refuse adding thread support to them.
=head3 Test2::Workflow
L<Test2::Workflow> has been merged into L<Test2::Suite>, so it gets addressed
by this policy.
L<Test2::Workflow> has thread support, but you must ask for it. Thread tests
for Test2::Workflow do not event run without setting either the AUTHOR_TESTING
env var, or the T2_DO_THREAD_TESTS env var.
To use threads with Test2::Workflow you must set the T2_WORKFLOW_USE_THREADS
env var.
If you do rely on threads with Test2::Workflow and find a bug please report it,
but it will be given an ultra-low priority. Merging patches that fix threading
issues will be given normal priority.
=head1 SEE ALSO
L<Test2> - Test2 itself.
L<Test2::Suite> - Initial tools built using L<Test2>.
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,115 @@
package Test2::Manual::Contributing;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Contributing - How to contribute to the Test2 project.
=head1 DESCRIPTION
This is a short manual page dedicated to helping people who wish to contribute
to the Test2 project.
=head1 WAYS TO HELP
=head2 REPORT BUGS
The easiest way to help is to report bugs when you find them. Bugs are a fact
of life when writing or using software. If you use Test2 long enough you are
likely to find a bug. When you find such a bug it would help us out if you
would submit a ticket.
=head3 BUG TRACKERS
Always try to find the preferred bug tracker for the module that has the bug.
Here are the big 3 for the main Test2 project:
=over 4
=item Test2/Test-Builder/Test-More
L<https://github.com/Test-More/test-more/issues>
=item Test2-Suite
L<https://github.com/Test-More/Test2-Suite/issues>
=item Test2-Harness
L<https://github.com/Test-More/Test2-Harness/issues>
=back
=head2 SUBMIT PATCHES
You are welcome to fix bugs you find, or from the tracker. We also often accept
patches that add new features or update documentation. The preferred method of
submitting patches is a github pull request, that said we also accept patches
via email.
=head2 ADD/UPDATE DOCUMENTATION
Documentation can be flawed just like code can be. Documentation can also
become outdated. If you see some incorrect documentation, or documentation that
is missing, we would love to get a patch to fix it!
=head2 ANSWER QUESTIONS ON IRC/SLACK
We are always hanging out on L<irc://irc.perl.org>, the #perl-qa and #toolchain
channels are a good place to find us.
There is also a Test2 slack channel: L<https://perl-test2.slack.com>.
=head2 WRITE NEW TOOLS USING TEST2
Writing a new tool using Test2 is always a good way to contribute. When you
write a tool that you think is useful, it is nice to share it by putting it on
CPAN.
=head2 PORT OLD TOOLS TO TEST2
The C<Test::*> namespace has been around for a long time, and has a LOT of
tools. The C<Test2::Tools::*> namespace is fairly young, and has less tools.
Finding a useful old tool with no modern equivalent, and writing a port is a
very good use of your time.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,245 @@
package Test2::Manual::Testing;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Testing - Hub for documentation about writing tests with Test2.
=head1 DESCRIPTION
This document outlines all the tutorials and POD that cover writing tests. This
section does not cover any Test2 internals, nor does it cover how to write new
tools, for that see L<Test2::Manual::Tooling>.
=head1 NAMESPACE MAP
When writing tests there are a couple namespaces to focus on:
=over 4
=item Test2::Tools::*
This is where toolsets can be found. A toolset exports functions that help you
make assertions about your code. Toolsets will only export functions, they
should not ever have extra/global effects.
=item Test2::Plugins::*
This is where plugins live. Plugins should not export anything, but instead
will introduce or alter behaviors for Test2 in general. These behaviors may be
lexically scoped, or they may be global.
=item Test2::Bundle::*
Bundles combine toolsets and plugins together to reduce your boilerplate. First
time test writers are encouraged to start with the L<Test2::V0> bundle (which
is an exception to the namespace rule as it does not live under
C<Test2::Bundle::>). If you find yourself loading several plugins and toolsets
over and over again you could benefit from writing your own bundle.
=item Test2::Require::*
This namespace contains modules that will cause a test to skip if specific
conditions are not met. Use this if you have tests that only run on specific
perl versions, or require external libraries that may not always be available.
=back
=head1 LISTING DEPENDENCIES
When you use L<Test2>, specifically things included in L<Test2::Suite> you need
to list them in your modules test dependencies. It is important to note that
you should list the tools/plugins/bundles you need, you should not simply list
L<Test2::Suite> as your dependency. L<Test2::Suite> is a living distribution
intended to represent the "current" best practices. As tools, plugins, and
bundles evolve, old ones will become discouraged and potentially be moved from
L<Test2::Suite> into their own distributions.
One goal of L<Test2::Suite> is to avoid breaking backwards compatibility.
Another goal is to always improve by replacing bad designs with better ones.
When necessary L<Test2::Suite> will break old modules out into separate dists
and define new ones, typically with a new bundle. In short, if we feel the need
to break something we will do so by creating a new bundle, and discouraging the
old one, but we will not break the old one.
So for example, if you use L<Test2::V0>, and L<Dist::Zilla> you
should have this in your config:
[Prereqs / TestRequires]
Test2::V0 = 0.000060
You B<SHOULD NOT> do this:
[Prereqs / TestRequires]
Test2::Suite = 0.000060
Because L<Test2::V0> might not always be part of L<Test2::Suite>.
When writing new tests you should often check L<Test2::Suite> to see what the
current recommended bundle is.
=head3 Dist::Zilla
[Prereqs / TestRequires]
Test2::V0 = 0.000060
=head3 ExtUtils::MakeMaker
my %WriteMakefileArgs = (
...,
"TEST_REQUIRES" => {
"Test2::V0" => "0.000060"
},
...
);
=head3 Module::Install
test_requires 'Test2::V0' => '0.000060';
=head3 Module::Build
my $build = Module::Build->new(
...,
test_requires => {
"Test2::V0" => "0.000060",
},
...
);
=head1 TUTORIALS
=head2 SIMPLE/INTRODUCTION TUTORIAL
L<Test2::Manual::Testing::Introduction> is an introduction to writing tests
using the L<Test2> tools.
=head2 MIGRATING FROM TEST::BUILDER and TEST::MORE
L<Test2::Manual::Testing::Migrating> Is a tutorial for converting old tests
that use L<Test::Builder> or L<Test::More> to the newer L<Test2> way of doing
things.
=head2 ADVANCED PLANNING
L<Test2::Manual::Testing::Planning> is a tutorial on the many ways to set a
plan.
=head2 TODO TESTS
L<Test2::Manual::Testing::Todo> is a tutorial for markings tests as TODO.
=head2 SUBTESTS
COMING SOON.
=head2 COMPARISONS
COMING SOON.
=head3 SIMPLE COMPARISONS
COMING SOON.
=head3 ADVANCED COMPARISONS
COMING SOON.
=head2 TESTING EXPORTERS
COMING SOON.
=head2 TESTING CLASSES
COMING SOON.
=head2 TRAPPING
COMING SOON.
=head3 TRAPPING EXCEPTIONS
COMING SOON.
=head3 TRAPPING WARNINGS
COMING SOON.
=head2 DEFERRED TESTING
COMING SOON.
=head2 MANAGING ENCODINGS
COMING SOON.
=head2 AUTO-ABORT ON FAILURE
COMING SOON.
=head2 CONTROLLING RANDOM BEHAVIOR
COMING SOON.
=head2 WRITING YOUR OWN BUNDLE
COMING SOON.
=head1 TOOLSET DOCUMENTATION
COMING SOON.
=head1 PLUGIN DOCUMENTATION
COMING SOON.
=head1 BUNDLE DOCUMENTATION
COMING SOON.
=head1 REQUIRE DOCUMENTATION
COMING SOON.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,293 @@
package Test2::Manual::Testing::Introduction;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Testing::Introduction - Introduction to testing with Test2.
=head1 DESCRIPTION
This tutorial is a beginners introduction to testing. This will take you
through writing a test file, making assertions, and running your test.
=head1 BOILERPLATE
=head2 THE TEST FILE
Test files typically are placed inside the C<t/> directory, and end with the
C<.t> file extension.
C<t/example.t>:
use Test2::V0;
# Assertions will go here
done_testing;
This is all the boilerplate you need.
=over 4
=item use Test2::V0;
This loads a collection of testing tools that will be described later in the
tutorial. This will also turn on C<strict> and C<warnings> for you.
=item done_testing;
This should always be at the end of your test files. This tells L<Test2> that
you are done making assertions. This is important as C<test2> will assume the
test did not complete successfully without this, or some other form of test
"plan".
=back
=head2 DIST CONFIG
You should always list bundles and tools directly. You should not simply list
L<Test2::Suite> and call it done, bundles and tools may be moved out of
L<Test2::Suite> to their own dists at any time.
=head3 Dist::Zilla
[Prereqs / TestRequires]
Test2::V0 = 0.000060
=head3 ExtUtils::MakeMaker
my %WriteMakefileArgs = (
...,
"TEST_REQUIRES" => {
"Test2::V0" => "0.000060"
},
...
);
=head3 Module::Install
test_requires 'Test2::V0' => '0.000060';
=head3 Module::Build
my $build = Module::Build->new(
...,
test_requires => {
"Test2::V0" => "0.000060",
},
...
);
=head1 MAKING ASSERTIONS
The most simple tool for making assertions is C<ok()>. C<ok()> lets you assert
that a condition is true.
ok($CONDITION, "Description of the condition");
Here is a complete C<t/example.t>:
use Test2::V0;
ok(1, "1 is true, so this will pass");
done_testing;
=head1 RUNNING THE TEST
Test files are simply scripts. Just like any other script you can run the test
directly with perl. Another option is to use a test "harness" which runs the
test for you, and provides extra information and checks the scripts exit value
for you.
=head2 RUN DIRECTLY
$ perl -Ilib t/example.t
Which should produce output like this:
# Seeded srand with seed '20161028' from local date.
ok 1 - 1 is true, so this will pass
1..1
If the test had failed (C<ok(0, ...)>) it would look like this:
# Seeded srand with seed '20161028' from local date.
not ok 1 - 0 is false, so this will fail
1..1
Test2 will also set the exit value of the script, a successful run will have an
exit value of 0, a failed run will have a non-zero exit value.
=head2 USING YATH
The C<yath> command line tool is provided by L<Test2::Harness> which you may
need to install yourself from cpan. C<yath> is the harness written specifically
for L<Test2>.
$ yath -Ilib t/example.t
This will produce output similar to this:
( PASSED ) job 1 t/example.t
================================================================================
Run ID: 1508027909
All tests were successful!
You can also request verbose output with the C<-v> flag:
$ yath -Ilib -v t/example.t
Which produces:
( LAUNCH ) job 1 example.t
( NOTE ) job 1 Seeded srand with seed '20171014' from local date.
[ PASS ] job 1 + 1 is true, so this will pass
[ PLAN ] job 1 Expected asserions: 1
( PASSED ) job 1 example.t
================================================================================
Run ID: 1508028002
All tests were successful!
=head2 USING PROVE
The C<prove> command line tool is provided by the L<Test::Harness> module which
comes with most versions of perl. L<Test::Harness> is dual-life, which means
you can also install the latest version from cpan.
$ prove -Ilib t/example.t
This will produce output like this:
example.t .. ok
All tests successful.
Files=1, Tests=1, 0 wallclock secs ( 0.01 usr 0.00 sys + 0.05 cusr 0.00 csys = 0.06 CPU)
Result: PASS
You can also request verbose output with the C<-v> flag:
$ prove -Ilib -v t/example.t
The verbose output looks like this:
example.t ..
# Seeded srand with seed '20161028' from local date.
ok 1 - 1 is true, so this will pass
1..1
ok
All tests successful.
Files=1, Tests=1, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.06 cusr 0.00 csys = 0.08 CPU)
Result: PASS
=head1 THE "PLAN"
All tests need a "plan". The job of a plan is to make sure you ran all the
tests you expected. The plan prevents a passing result from a test that exits
before all the tests are run.
There are 2 primary ways to set the plan:
=over 4
=item done_testing()
The most common, and recommended way to set a plan is to add C<done_testing> at
the end of your test file. This will automatically calculate the plan for you
at the end of the test. If the test were to exit early then C<done_testing>
would not run and no plan would be found, forcing a failure.
=item plan($COUNT)
The C<plan()> function allows you to specify an exact number of assertions you
want to run. If you run too many or too few assertions then the plan will not
match and it will be counted as a failure. The primary problem with this way of
planning is that you need to add up the number of assertions, and adjust the
count whenever you update the test file.
C<plan()> must be used before all assertions, or after all assertions, it
cannot be done in the middle of making assertions.
=back
=head1 ADDITIONAL ASSERTION TOOLS
The L<Test2::V0> bundle provides a lot more than C<ok()>,
C<plan()>, and C<done_testing()>. The biggest tools to note are:
=over 4
=item is($a, $b, $description)
C<is()> allows you to compare 2 structures and insure they are identical. You
can use it for simple string comparisons, or even deep data structure
comparisons.
is("foo", "foo", "Both strings are identical");
is(["foo", 1], ["foo", 1], "Both arrays contain the same elements");
=item like($a, $b, $description)
C<like()> is similar to C<is()> except that it only checks items listed on the
right, it ignores any extra values found on the left.
like([1, 2, 3, 4], [1, 2, 3], "Passes, the extra element on the left is ignored");
You can also used regular expressions on the right hand side:
like("foo bar baz", qr/bar/, "The string matches the regex, this passes");
You can also nest the regexes:
like([1, 2, 'foo bar baz', 3], [1, 2, qr/bar/], "This passes");
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,420 @@
package Test2::Manual::Testing::Migrating;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
=head1 NAME
Test2::Manual::Testing::Migrating - How to migrate existing tests from
Test::More to Test2.
=head1 DESCRIPTION
This tutorial covers the conversion of an existing test. This tutorial assumes
you have a test written using L<Test::More>.
=head1 LEGACY TEST
This tutorial will be converting this example test one section at a time:
C<t/example.t>:
#####################
# Boilerplate
use strict;
use warnings;
use Test::More tests => 14;
use_ok 'Scalar::Util';
require_ok 'Exporter';
#####################
# Simple assertions (no changes)
ok(1, "pass");
is("apple", "apple", "Simple string compare");
like("foo bar baz", qr/bar/, "Regex match");
#####################
# Todo
{
local $TODO = "These are todo";
ok(0, "oops");
}
#####################
# Deep comparisons
is_deeply([1, 2, 3], [1, 2, 3], "Deep comparison");
#####################
# Comparing references
my $ref = [1];
is($ref, $ref, "Check that we have the same ref both times");
#####################
# Things that are gone
ok(eq_array([1], [1]), "array comparison");
ok(eq_hash({a => 1}, {a => 1}), "hash comparison");
ok(eq_set([1, 3, 2], [1, 2, 3]), "set comparison");
note explain([1, 2, 3]);
{
package THING;
sub new { bless({}, shift) }
}
my $thing = new_ok('THING');
#####################
# Tools that changed
isa_ok($thing, 'THING', '$thing');
can_ok(__PACKAGE__, qw/ok is/);
=head1 BOILERPLATE
BEFORE:
use strict;
use warnings;
use Test::More tests => 14;
use_ok 'Scalar::Util';
require_ok 'Exporter';
AFTER:
use Test2::V0;
plan(11);
use Scalar::Util;
require Exporter;
=over 4
=item Replace Test::More with Test2::V0
L<Test2::V0> is the recommended bundle. In a full migration you
will want to replace L<Test::More> with the L<Test2::V0> bundle.
B<Note:> You should always double check the latest L<Test2> to see if there is
a new recommended bundle. When writing a new test you should always use the
newest Test::V# module. Higher numbers are newer version.
=item Stop using use_ok()
C<use_ok()> has been removed. a C<use MODULE> statement will throw an exception
on failure anyway preventing the test from passing.
If you I<REALLY> want/need to assert that the file loaded you can use the L<ok>
module:
use ok 'Scalar::Util';
The main difference here is that there is a space instead of an underscore.
=item Stop using require_ok()
C<require_ok> has been removed just like C<use_ok>. There is no L<ok> module
equivalent here. Just use C<require>.
=item Remove strict/warnings (optional)
The L<Test2::V0> bundle turns strict and warnings on for you.
=item Change where the plan is set
Test2 does not allow you to set the plan at import. In the old code you would
pass C<< tests => 11 >> as an import argument. In L<Test2> you either need to
use the C<plan()> function to set the plan, or use C<done_testing()> at the end
of the test.
If your test already uses C<done_testing()> you can keep that and no plan
changes are necessary.
B<Note:> We are also changing the plan from 14 to 11, that is because we
dropped C<use_ok>, C<require_ok>, and we will be dropping one more later on.
This is why C<done_testing()> is recommended over a set plan.
=back
=head1 SIMPLE ASSERTIONS
The vast majority of assertions will not need any changes:
#####################
# Simple assertions (no changes)
ok(1, "pass");
is("apple", "apple", "Simple string compare");
like("foo bar baz", qr/bar/, "Regex match");
=head1 TODO
{
local $TODO = "These are todo";
ok(0, "oops");
}
The C<$TODO> package variable is gone. You now have a C<todo()> function.
There are 2 ways this can be used:
=over 4
=item todo $reason => sub { ... }
todo "These are todo" => sub {
ok(0, "oops");
};
This is the cleanest way to do a todo. This will make all assertions inside the
codeblock into TODO assertions.
=item { my $TODO = todo $reason; ... }
{
my $TODO = todo "These are todo";
ok(0, "oops");
}
This is a system that emulates the old way. Instead of modifying a global
C<$TODO> variable you create a todo object with the C<todo()> function and
assign it to a lexical variable. Once the todo object falls out of scope the
TODO ends.
=back
=head1 DEEP COMPARISONS
is_deeply([1, 2, 3], [1, 2, 3], "Deep comparison");
Deep comparisons are easy, simply replace C<is_deeply()> with C<is()>.
is([1, 2, 3], [1, 2, 3], "Deep comparison");
=head1 COMPARING REFERENCES
my $ref = [1];
is($ref, $ref, "Check that we have the same ref both times");
The C<is()> function provided by L<Test::More> forces both arguments into
strings, which makes this a comparison of the reference addresses. L<Test2>'s
C<is()> function is a deep comparison, so this will still pass, but fails to
actually test what we want (that both references are the same exact ref, not
just identical structures.)
We now have the C<ref_is()> function that does what we really want, it ensures
both references are the same reference. This function does the job better than
the original, which could be thrown off by string overloading.
my $ref = [1];
ref_is($ref, $ref, "Check that we have the same ref both times");
=head1 TOOLS THAT ARE GONE
ok(eq_array([1], [1]), "array comparison");
ok(eq_hash({a => 1}, {a => 1}), "hash comparison");
ok(eq_set([1, 3, 2], [1, 2, 3]), "set comparison");
note explain([1, 2, 3]);
{
package THING;
sub new { bless({}, shift) }
}
my $thing = new_ok('THING');
C<eq_array>, C<eq_hash> and C<eq_set> have been considered deprecated for a
very long time, L<Test2> does not provide them at all. Instead you can just use
C<is()>:
is([1], [1], "array comparison");
is({a => 1}, {a => 1}, "hash comparison");
C<eq_set> is a tad more complicated, see L<Test2::Tools::Compare> for an
explanation:
is([1, 3, 2], bag { item 1; item 2; item 3; end }, "set comparison");
C<explain()> has a rocky history. There have been arguments about how it should
work. L<Test2> decided to simply not include C<explain()> to avoid the
arguments. You can instead directly use Data::Dumper:
use Data::Dumper;
note Dumper([1, 2, 3]);
C<new_ok()> is gone. The implementation was complicated, and did not add much
value:
{
package THING;
sub new { bless({}, shift) }
}
my $thing = THING->new;
ok($thing, "made a new thing");
The complete section after the conversion is:
is([1], [1], "array comparison");
is({a => 1}, {a => 1}, "hash comparison");
is([1, 3, 2], bag { item 1; item 2; item 3; end }, "set comparison");
use Data::Dumper;
note Dumper([1, 2, 3]);
{
package THING;
sub new { bless({}, shift) }
}
my $thing = THING->new;
ok($thing, "made a new thing");
=head1 TOOLS THAT HAVE CHANGED
isa_ok($thing, 'THING', '$thing');
can_ok(__PACKAGE__, qw/ok is/);
In L<Test::More> these functions are very confusing, and most people use them
wrong!
C<isa_ok()> from L<Test::More> takes a thing, a class/reftype to check, and
then uses the third argument as an alternative display name for the first
argument (NOT a test name!).
C<can_ok()> from L<Test::More> is not consistent with C<isa_ok> as all
arguments after the first are subroutine names.
L<Test2> fixes this by making both functions consistent and obvious:
isa_ok($thing, ['THING'], 'got a THING');
can_ok(__PACKAGE__, [qw/ok is/], "have expected subs");
You will note that both functions take a thing, an arrayref as the second
argument, then a test name as the third argument.
=head1 FINAL VERSION
#####################
# Boilerplate
use Test2::V0;
plan(11);
use Scalar::Util;
require Exporter;
#####################
# Simple assertions (no changes)
ok(1, "pass");
is("apple", "apple", "Simple string compare");
like("foo bar baz", qr/bar/, "Regex match");
#####################
# Todo
todo "These are todo" => sub {
ok(0, "oops");
};
#####################
# Deep comparisons
is([1, 2, 3], [1, 2, 3], "Deep comparison");
#####################
# Comparing references
my $ref = [1];
ref_is($ref, $ref, "Check that we have the same ref both times");
#####################
# Things that are gone
is([1], [1], "array comparison");
is({a => 1}, {a => 1}, "hash comparison");
is([1, 3, 2], bag { item 1; item 2; item 3; end }, "set comparison");
use Data::Dumper;
note Dumper([1, 2, 3]);
{
package THING;
sub new { bless({}, shift) }
}
my $thing = THING->new;
#####################
# Tools that changed
isa_ok($thing, ['THING'], 'got a THING');
can_ok(__PACKAGE__, [qw/ok is/], "have expected subs");
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,104 @@
package Test2::Manual::Testing::Planning;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Testing::Planning - The many ways to set a plan.
=head1 DESCRIPTION
This tutorial covers the many ways of setting a plan.
=head1 TEST COUNT
The C<plan()> function is provided by L<Test2::Tools::Basic>. This function lets
you specify an exact number of tests to run. This can be done at the start of
testing, or at the end. This cannot be done partway through testing.
use Test2::Tools::Basic;
plan(10); # 10 tests expected
...
=head1 DONE TESTING
The C<done_testing()> function is provided by L<Test2::Tools::Basic>. This
function will automatically set the plan to the number of tests that were run.
This must be used at the very end of testing.
use Test2::Tools::Basic;
...
done_testing();
=head1 SKIP ALL
The C<skip_all()> function is provided by L<Test2::Tools::Basic>. This function
will set the plan to C<0>, and exit the test immediately. You may provide a skip
reason that explains why the test should be skipped.
use Test2::Tools::Basic;
skip_all("This test will not run here") if ...;
...
=head1 CUSTOM PLAN EVENT
A plan is simply an L<Test2::Event::Plan> event that gets sent to the current
hub. You could always write your own tool to set the plan.
use Test2::API qw/context/;
sub set_plan {
my $count = @_;
my $ctx = context();
$ctx->send_event('Plan', max => $count);
$ctx->release;
return $count;
}
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,112 @@
package Test2::Manual::Testing::Todo;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Testing::Todo - Tutorial for marking tests as TODO.
=head1 DESCRIPTION
This tutorial covers the process of marking tests as TODO. It also describes
how TODO works under the hood.
=head1 THE TOOL
use Test2::Tools::Basic qw/todo/;
=head2 TODO BLOCK
This form is low-magic. All tests inside the block are marked as todo, tests
outside the block are not todo. You do not need to do any variable management.
The flaw with this form is that it adds a couple levels to the stack, which can
break some high-magic tests.
Overall this is the preferred form unless you have a special case that requires
the variable form.
todo "Reason for the todo" => sub {
ok(0, "fail but todo");
...
};
=head2 TODO VARIABLE
This form maintains the todo scope for the life of the variable. This is useful
for tests that are sensitive to scope changes. This closely emulates the
L<Test::More> style which localized the C<$TODO> package variable. Once the
variable is destroyed (set it to undef, scope end, etc) the TODO state ends.
my $todo = todo "Reason for the todo";
ok(0, "fail but todo");
...
$todo = undef;
=head1 MANUAL TODO EVENTS
use Test2::API qw/context/;
sub todo_ok {
my ($bool, $name, $todo) = @_;
my $ctx = context();
$ctx->send_event('Ok', pass => $bool, effective_pass => 1, todo => $todo);
$ctx->release;
return $bool;
}
The L<Test2::Event::Ok> event has a C<todo> field which should have the todo
reason. The event also has the C<pass> and C<effective_pass> fields. The
C<pass> field is the actual pass/fail value. The C<effective_pass> is used to
determine if the event is an actual failure (should always be set tot true with
todo).
=head1 HOW THE TODO TOOLS WORK UNDER THE HOOD
The L<Test2::Todo> library gets the current L<Test2::Hub> instance and adds a
filter. The filter that is added will set the todo and effective pass fields on
any L<Test2::Event::Ok> events that pass through the hub. The filter also
converts L<Test2::Event::Diag> events into L<Test2::Event::Note> events.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,120 @@
package Test2::Manual::Tooling;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling - Manual page for tool authors.
=head1 DESCRIPTION
This section covers writing new tools, plugins, and other Test2 components.
=head1 TOOL TUTORIALS
=head2 FIRST TOOL
L<Test2::Manual::Tooling::FirstTool> - Introduction to writing tools by cloning
L<ok()>.
=head2 MOVING FROM Test::Builder
L<Test2::Manual::Tooling::TestBuilder> - This section maps Test::Builder
methods to Test2 concepts.
=head2 NESTING TOOLS
L<Test2::Manual::Tooling::Nesting> - How to call other tools from your tool.
=head2 TOOLS WITH SUBTESTS
L<Test2::Manual::Tooling::Subtest> - How write tools that make use of subtests.
=head2 TESTING YOUR TEST TOOLS
L<Test2::Manual::Tooling::Testing> - How to write tests for your test tools.
=head1 PLUGIN TUTORIALS
=head2 TAKING ACTION WHEN A NEW TOOL STARTS
L<Test2::Manual::Tooling::Plugin::ToolStarts> - How to add behaviors that occur
when a tool starts work.
=head2 TAKING ACTION AFTER A TOOL IS DONE
L<Test2::Manual::Tooling::Plugin::ToolCompletes> - How to add behaviors that
occur when a tool completes work.
=head2 TAKING ACTION AT THE END OF TESTING
L<Test2::Manual::Tooling::Plugin::TestingDone> - How to add behaviors that
occur when testing is complete (IE done_testing, or end of test).
=head2 TAKING ACTION JUST BEFORE EXIT
L<Test2::Manual::Tooling::Plugin::TestExit> - How to safely add pre-exit
behaviors.
=head1 WRITING A SIMPLE JSONL FORMATTER
L<Test2::Manual::Tooling::Formatter> - How to write a custom formatter, in our
case a JSONL formatter.
=head1 WHERE TO FIND HOOKS AND APIS
=over 4
=item global API
L<Test2::API> is the global API. This is primarily used by plugins that provide
global behavior.
=item In hubs
L<Test2::Hub> is the base class for all hubs. This is where hooks for
manipulating events, or running things at the end of testing live.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,145 @@
package Test2::Manual::Tooling::FirstTool;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::FirstTool - Write your first tool with Test2.
=head1 DESCRIPTION
This tutorial will help you write your very first tool by cloning the C<ok()>
tool.
=head1 COMPLETE CODE UP FRONT
package Test2::Tools::MyOk;
use strict;
use warnings;
use Test2::API qw/context/;
use base 'Exporter';
our @EXPORT = qw/ok/;
sub ok($;$@) {
my ($bool, $name, @diag) = @_;
my $ctx = context();
return $ctx->pass_and_release($name) if $bool;
return $ctx->fail_and_release($name, @diag);
}
1;
=head1 LINE BY LINE
=over 4
=item sub ok($;$@) {
In this case we are emulating the C<ok()> function exported by
L<Test2::Tools::Basic>.
C<ok()> and similar test tools use prototypes to enforce argument parsing. Your
test tools do not necessarily need prototypes, like any perl function you need
to make the decision based on how it is used.
The prototype requires at least 1 argument, which will
be forced into a scalar context. The second argument is optional, and is also
forced to be scalar, it is the name of the test. Any remaining arguments are
treated as diagnostics messages that will only be used if the test failed.
=item my ($bool, $name, @diag) = @_;
This line does not need much explanation, we are simply grabbing the args.
=item my $ctx = context();
This is a vital line in B<ALL> tools. The context object is the primary API for
test tools. You B<MUST> get a context if you want to issue any events, such as
making assertions. Further, the context is responsible for making sure failures
are attributed to the correct file and line number.
B<Note:> A test function B<MUST> always release the context when it is done,
you cannot simply let it fall out of scope and be garbage collected. Test2 does
a pretty good job of yelling at you if you make this mistake.
B<Note:> You B<MUST NOT> ever store or pass around a I<real> context object. If
you wish to hold on to a context for any reason you must use clone to make a
copy C<< my $copy = $ctx->clone >>. The copy may be passed around or stored,
but the original B<MUST> be released when you are done with it.
=item return $ctx->pass_and_release($name) if $bool;
When C<$bool> is true, this line uses the context object to issue a
L<Test2::Event::Pass> event. Along with issuing the event this will also
release the context object and return true.
This is short form for:
if($bool) {
$ctx->pass($name);
$ctx->release;
return 1;
}
=item return $ctx->fail_and_release($name, @diag);
This line issues a L<Test2::Event::Fail> event, releases the context object,
and returns false. The fail event will include any diagnostics messages from
the C<@diag> array.
This is short form for:
$ctx->fail($name, @diag);
$ctx->release;
return 0;
=back
=head1 CONTEXT OBJECT DOCUMENTATION
L<Test2::API::Context> is the place to read up on what methods the context
provides.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,138 @@
package Test2::Manual::Tooling::Formatter;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Formatter - How to write a custom formatter, in our
case a JSONL formatter.
=head1 DESCRIPTION
This tutorial explains a minimal formatter that outputs each event as a json
string on its own line. A true formatter will probably be significantly more
complicated, but this will give you the basics needed to get started.
=head1 COMPLETE CODE UP FRONT
package Test2::Formatter::MyFormatter;
use strict;
use warnings;
use JSON::MaybeXS qw/encode_json/;
use base qw/Test2::Formatter/;
sub new { bless {}, shift }
sub encoding {};
sub write {
my ($self, $e, $num, $f) = @_;
$f ||= $e->facet_data;
print encode_json($f), "\n";
}
1;
=head1 LINE BY LINE
=over 4
=item use base qw/Test2::Formatter/;
All formatters should inherit from L<Test2::Formatter>.
=item sub new { bless {}, shift }
Formatters need to be instantiable objects, this is a minimal C<new()> method.
=item sub encoding {};
For this example we leave this sub empty. In general you should implement this
sub to make sure you honor situations where the encoding is set. L<Test2::V0>
itself will try to set the encoding to UTF8.
=item sub write { ... }
The C<write()> method is the most important, each event is sent here.
=item my ($self, $e, $num, $f) = @_;
The C<write()> method receives 3 or 4 arguments, the fourth is optional.
=over 4
=item $self
The formatter itself.
=item $e
The event being written
=item $num
The most recent assertion number. If the event being processed is an assertion
then this will have been bumped by 1 since the last call to write. For non
assertions this number is set to the most recent assertion.
=item $f
This MAY be a hashref containing all the facet data from the event. More often
then not this will be undefined. This is only set if the facet data was needed
by the hub, and it usually is not.
=back
=item $f ||= $e->facet_data;
We want to dump the event facet data. This will set C<$f> to the facet data
unless we already have the facet data.
=item print encode_json($f), "\n";
This line prints the JSON encoded facet data, and a newline.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,140 @@
package Test2::Manual::Tooling::Nesting;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Nesting - Tutorial for using other tools within your
own.
=head1 DESCRIPTION
Sometimes you find yourself writing the same test pattern over and over, in
such cases you may want to encapsulate the logic in a new test function that
calls several tools together. This sounds easy enough, but can cause headaches
if not done correctly.
=head1 NAIVE WAY
Lets say you find yourself writing the same test pattern over and over for multiple objects:
my $obj1 = $class1->new;
is($obj1->foo, 'foo', "got foo");
is($obj1->bar, 'bar', "got bar");
my $obj2 = $class1->new;
is($obj2->foo, 'foo', "got foo");
is($obj2->bar, 'bar', "got bar");
... 10x more times for classes 2-12
The naive way to do this is to write a C<check_class()> function like this:
sub check_class {
my $class = shift;
my $obj = $class->new;
is($obj->foo, 'foo', "got foo");
is($obj->bar, 'bar', "got bar");
}
check_class($class1);
check_class($class2);
check_class($class3);
...
This will appear to work fine, and you might not notice any problems,
I<so long as the tests are passing.>
=head2 WHATS WRONG WITH IT?
The problems with the naive approach become obvious if things start to fail.
The diagnostics that tell you what file and line the failure occurred on will be
wrong. The failure will be reported to the line I<inside> C<check_class>, not
to the line where C<check_class()> was called. This is problem because it
leaves you with no idea which class is failing.
=head2 HOW TO FIX IT
Luckily this is extremely easy to fix. You need to acquire a context object at
the start of your function, and release it at the end... yes it is that simple.
use Test2::API qw/context/;
sub check_class {
my $class = shift;
my $ctx = context();
my $obj = $class->new;
is($obj->foo, 'foo', "got foo");
is($obj->bar, 'bar', "got bar");
$ctx->release;
}
See, that was easy. With these 2 additional lines we know have proper file+line
reporting. The nested tools will find the context we acquired here, and know to
use it's file and line numbers.
=head3 THE OLD WAY (DO NOT DO THIS ANYMORE)
With L<Test::Builder> there was a global variables called
C<$Test::Builder::Level> which helped solve this problem:
sub check_class {
my $class = shift;
local $Test::Builder::Level = $Test::Builder::Level + 1;
my $obj = $class->new;
is($obj->foo, 'foo', "got foo");
is($obj->bar, 'bar', "got bar");
}
This variable worked well enough (and will still work) but was not very
discoverable. Another problem with this variable is that it becomes cumbersome
if you have a more deeply nested code structure called the nested tools, you
might need to count stack frames, and hope they never change due to a third
party module. The context solution has no such caveats.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,108 @@
package Test2::Manual::Tooling::Plugin::TestExit;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Plugin::TestExit - How to safely add pre-exit
behaviors.
=head1 DESCRIPTION
This describes the correct/safe way to add pre-exit behaviors to tests via a
custom plugin.
The naive way to attempt this would be to add an C<END { ... }> block. That can
work, and may not cause problems.... On the other hand there are a lot of ways
that can bite you. Describing all the potential problems of an END block, and
how it might conflict with Test2 (Which has its own END block) is beyond the
scope of this document.
=head1 COMPLETE CODE UP FRONT
package Test2::Plugin::MyPlugin;
use Test2::API qw{test2_add_callback_exit};
sub import {
my $class = shift;
test2_add_callback_exit(sub {
my ($ctx, $orig_code, $new_exit_code_ref) = @_;
return if $orig_code == 42;
$$new_exit_code_ref = 42;
});
}
1;
=head1 LINE BY LINE
=over 4
=item use Test2::API qw{test2_add_callback_exit};
This imports the C<(test2_add_callback_exit)> callback.
=item test2_add_callback_exit(sub { ... });
This adds our callback to be called before exiting.
=item my ($ctx, $orig_code, $new_exit_code_ref) = @_
The callback gets 3 arguments. First is a context object you may use. The
second is the original exit code of the C<END> block Test2 is using. The third
argument is a scalar reference which you may use to get the current exit code,
or set a new one.
=item return if $orig_code == 42
This is a short-cut to do nothing if the original exit code was already 42.
=item $$new_exit_code_ref = 42
This changes the exit code to 42.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,121 @@
package Test2::Manual::Tooling::Plugin::TestingDone;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Plugin::TestingDone - Run code when the test file is
finished, or when done_testing is called.
=head1 DESCRIPTION
This is a way to add behavior to the end of a test file. This code is run
either when done_testing() is called, or when the test file has no more
run-time code to run.
When triggered by done_testing() this will be run BEFORE the plan is calculated
and sent. This means it IS safe to make test assertions in this callback.
=head1 COMPLETE CODE UP FRONT
package Test2::Plugin::MyPlugin;
use Test2::API qw{test2_add_callback_testing_done};
sub import {
my $class = shift;
test2_add_callback_testing_done(sub {
ok(!$some_global, '$some_global was not set');
print "The test file is done, or done_testing was just called\n"
});
}
1;
=head1 LINE BY LINE
=over 4
=item use Test2::API qw{test2_add_callback_testing_done};
This imports the C<test2_add_callback_testing_done()> callback.
=item test2_add_callback_testing_done(sub { ... });
This adds our callback to be called when testing is done.
=item ok(!$some_global, '$some_global was not set')
It is safe to make assertions in this type of callback. This code simply
asserts that some global was never set over the course of the test.
=item print "The test file is done, or done_testing was just called\n"
This prints a message when the callback is run.
=back
=head1 UNDER THE HOOD
Before test2_add_callback_testing_done() this kind of thing was still possible,
but it was hard to get right, here is the code to do it:
test2_add_callback_post_load(sub {
my $stack = test2_stack();
# Insure we have at least one hub, but we do not necessarily want the
# one this returns.
$stack->top;
# We want the root hub, not the top one.
my ($root) = Test2::API::test2_stack->all;
# Make sure the hub does not believe nothing has happened.
$root->set_active(1);
# Now we can add our follow-up code
$root->follow_up(sub {
# Your callback code here
});
});
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,94 @@
package Test2::Manual::Tooling::Plugin::ToolCompletes;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Plugin::ToolCompletes - How to add behaviors that occur
when a tool completes work.
=head1 DESCRIPTION
This tutorial helps you understand how to add behaviors that occur when a tool
is done with its work. All tools need to acquire and then release a context,
for this tutorial we make use of the release hooks that are called every time a
tool releases the context object.
=head1 COMPLETE CODE UP FRONT
package Test2::Plugin::MyPlugin;
use Test2::API qw{test2_add_callback_context_release};
sub import {
my $class = shift;
test2_add_callback_context_release(sub {
my $ctx_ref = shift;
print "Context was released\n";
});
}
1;
=head1 LINE BY LINE
=over 4
=item use Test2::API qw{test2_add_callback_context_release};
This imports the C<test2_add_callback_context_release()> callback.
=item test2_add_callback_context_release(sub { ... })
=item my $ctx_ref = shift
The coderefs for test2_add_callback_context_release() will receive exactly 1
argument, the context being released.
=item print "Context was released\n"
Print a notification whenever the context is released.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,126 @@
package Test2::Manual::Tooling::Plugin::ToolStarts;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Plugin::ToolStarts - How to add behaviors that occur
when a tool starts work.
=head1 DESCRIPTION
This tutorial will help you write plugins that have behavior when a tool
starts. All tools should start by acquiring a context object. This tutorial
shows you the hooks you can use to take advantage of the context acquisition.
=head1 COMPLETE CODE UP FRONT
package Test2::Plugin::MyPlugin;
use Test2::API qw{
test2_add_callback_context_init
test2_add_callback_context_acquire
};
sub import {
my $class = shift;
# Let us know every time a tool requests a context, and give us a
# chance to modify the parameters before we find it.
test2_add_callback_context_acquire(sub {
my $params_ref = shift;
print "A tool has requested the context\n";
});
# Callback every time a new context is created, not called if an
# existing context is found.
test2_add_callback_context_init(sub {
my $ctx_ref = shift;
print "A new context was created\n";
});
}
1;
=head1 LINE BY LINE
=over 4
=item use Test2::API qw{test2_add_callback_context_init test2_add_callback_context_acquire};
This imports the C<test2_add_callback_context_init()> and
C<test2_add_callback_context_acquire()> callbacks.
=item test2_add_callback_context_acquire(sub { ... })
This is where we add our callback for context acquisition. Every time
C<Test2::API::context()> is called the callback will be run.
=item my $params_ref = shift
In the test2_add_callback_context_acquire() callbacks we get exactly 1
argument, a reference to the parameters that C<context()> will use to find the
context.
=item print "A tool has requested the context\n"
Print a notification whenever a tool asks for a context.
=item test2_add_callback_context_init(sub { ... })
Add our context init callback. These callbacks are triggered whenever a
completely new context is created. This is not called if an existing context is
found. In short this only fires off for the top level tool, not nested tools.
=item my $ctx_ref = shift
The coderefs for test2_add_callback_context_init() will receive exactly 1
argument, the newly created context.
=item print "A new context was created\n"
Print a notification whenever a new context is created.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,164 @@
package Test2::Manual::Tooling::Subtest;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Subtest - How to implement a tool that makes use of
subtests.
=head1 DESCRIPTION
Subtests are a nice way of making related events visually, and architecturally
distinct.
=head1 WHICH TYPE OF SUBTEST DO I NEED?
There are 2 types of subtest. The first type is subtests with user-supplied
coderefs, such as the C<subtest()> function itself. The second type is subtest
that do not have any user supplied coderefs.
So which type do you need? The answer to that is simple, if you are going to
let the user define the subtest with their own codeblock, you have the first
type, otherwise you have the second.
In either case, you will still need use the same API function:
C<Test2::API::run_subtest>.
=head2 SUBTEST WITH USER SUPPLIED CODEREF
This example will emulate the C<subtest> function.
use Test2::API qw/context run_subtest/;
sub my_subtest {
my ($name, $code) = @_;
# Like any other tool, you need to acquire a context, if you do not then
# things will not report the correct file and line number.
my $ctx = context();
my $bool = run_subtest($name, $code);
$ctx->release;
return $bool;
}
This looks incredibly simple... and it is. C<run_subtest()> does all the hard
work for you. This will issue an L<Test2::Event::Subtest> event with the
results of the subtest. The subtest event itself will report to the proper file
and line number due to the context you acquired (even though it does not I<look>
like you used the context.
C<run_subtest()> can take additional arguments:
run_subtest($name, $code, \%params, @args);
=over 4
=item @args
This allows you to pass arguments into the codeblock that gets run.
=item \%params
This is a hashref of parameters. Currently there are 3 possible parameters:
=over 4
=item buffered => $bool
This will turn the subtest into the new style buffered subtest. This type of
subtest is recommended, but not default.
=item inherit_trace => $bool
This is used for tool-side coderefs.
=item no_fork => $bool
react to forking/threading inside the subtest itself. In general you are
unlikely to need/want this parameter.
=back
=back
=head2 SUBTEST WITH TOOL-SIDE CODEREF
This is particularly useful if you want to turn a tool that wraps other tools
into a subtest. For this we will be using the tool we created in
L<Test2::Manual::Tooling::Nesting>.
use Test2::API qw/context run_subtest/;
sub check_class {
my $class = shift;
my $ctx = context();
my $code = sub {
my $obj = $class->new;
is($obj->foo, 'foo', "got foo");
is($obj->bar, 'bar', "got bar");
};
my $bool = run_subtest($class, $code, {buffered => 1, inherit_trace => 1});
$ctx->release;
return $bool;
}
The C<run_subtest()> function does all the heavy lifting for us. All we need
to do is give the function a name, a coderef to run, and the
C<< inherit_trace => 1 >> parameter. The C<< buffered => 1 >> parameter is
optional, but recommended.
The C<inherit_trace> parameter tells the subtest tool that the contexts acquired
inside the nested tools should use the same trace as the subtest itself. For
user-supplied codeblocks you do not use inherit_trace because you want errors
to report to the user-supplied file+line.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,171 @@
package Test2::Manual::Tooling::TestBuilder;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::TestBuilder - This section maps Test::Builder methods
to Test2 concepts.
=head1 DESCRIPTION
With Test::Builder tools were encouraged to use methods on the Test::Builder
singleton object. Test2 has a different approach, every tool should get a new
L<Test2::API::Context> object, and call methods on that. This document maps
several concepts from Test::Builder to Test2.
=head1 CONTEXT
First thing to do, stop using the Test::Builder singleton, in fact stop using
or even loading Test::Builder. Instead of Test::Builder each tool you write
should follow this template:
use Test2::API qw/context/;
sub my_tool {
my $ctx = context();
... do work ...
$ctx->ok(1, "a passing assertion");
$ctx->release;
return $whatever;
}
The original Test::Builder style was this:
use Test::Builder;
my $tb = Test::Builder->new; # gets the singleton
sub my_tool {
... do work ...
$tb->ok(1, "a passing assertion");
return $whatever;
}
=head1 TEST BUILDER METHODS
=over 4
=item $tb->BAIL_OUT($reason)
The context object has a 'bail' method:
$ctx->bail($reason)
=item $tb->diag($string)
=item $tb->note($string)
The context object has diag and note methods:
$ctx->diag($string);
$ctx->note($string);
=item $tb->done_testing
The context object has a done_testing method:
$ctx->done_testing;
Unlike the Test::Builder version, no arguments are allowed.
=item $tb->like
=item $tb->unlike
These are not part of context, instead look at L<Test2::Compare> and
L<Test2::Tools::Compare>.
=item $tb->ok($bool, $name)
# Preferred
$ctx->pass($name);
$ctx->fail($name, @diag);
# Discouraged, but supported:
$ctx->ok($bool, $name, \@failure_diags)
=item $tb->subtest
use the C<Test2::API::run_subtest()> function instead. See L<Test2::API> for documentation.
=item $tb->todo_start
=item $tb->todo_end
See L<Test2::Tools::Todo> instead.
=item $tb->output, $tb->failure_output, and $tb->todo_output
These are handled via formatters now. See L<Test2::Formatter> and
L<Test2::Formatter::TAP>.
=back
=head1 LEVEL
L<Test::Builder> had the C<$Test::Builder::Level> variable that you could
modify in order to set the stack depth. This was useful if you needed to nest
tools and wanted to make sure your file and line number were correct. It was
also frustrating and prone to errors. Some people never even discovered the
level variable and always had incorrect line numbers when their tools would
fail.
L<Test2> uses the context system, which solves the problem a better way. The
top-most tool get a context, and holds on to it until it is done. Any tool
nested under the first will find and use the original context instead of
generating a new one. This means the level problem is solved for free, no
variables to mess with.
L<Test2> is also smart enough to honor c<$Test::Builder::Level> if it is set.
=head1 TODO
L<Test::Builder> used the C<$TODO> package variable to set the TODO state. This
was confusing, and easy to get wrong. See L<Test2::Tools::Todo> for the modern
way to accomplish a TODO state.
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut

View File

@@ -0,0 +1,151 @@
package Test2::Manual::Tooling::Testing;
use strict;
use warnings;
our $VERSION = '0.000139';
1;
__END__
=head1 NAME
Test2::Manual::Tooling::Testing - Tutorial on how to test your testing tools.
=head1 DESCRIPTION
Testing your test tools used to be a complex and difficult prospect. The old
tools such as L<Test::Tester> and L<Test::Builder::Tester> were limited, and
fragile. Test2 on the other hand was designed from the very start to be easily
tested! This tutorial shows you how.
=head1 THE HOLY GRAIL OF TESTING YOUR TOOLS
The key to making Test2 easily testable (specially when compared to
Test::Builder) is the C<intercept> function.
use Test2::API qw/intercept/;
my $events = intercept {
ok(1, "pass");
ok(0, "fail");
diag("A diag");
};
The intercept function lets you use any test tools you want inside a codeblock.
No events or contexts generated within the intercept codeblock will have any
effect on the outside testing state. The C<intercept> function completely
isolates the tools called within.
B<Note:> Plugins and things that effect global API state may not be fully
isolated. C<intercept> is intended specifically for event isolation.
The C<intercept> function will return an arrayref containing all the events
that were generated within the codeblock. You can now make any assertions you
want about the events you expected your tools to generate.
[
bless({...}, 'Test2::Event::Ok'), # pass
bless({...}, 'Test2::Event::Ok'), # fail
bless({...}, 'Test2::Event::Diag'), # Failure diagnostics (not always a second event)
bless({...}, 'Test2::Event::Diag'), # custom 'A diag' message
]
Most test tools eventually produce one or more events. To effectively verify
the events you get from intercept you really should read up on how events work
L<Test2::Manual::Anatomy::Event>. Once you know about events you can move on to
the next section which points you at some helpers.
=head1 ADDITIONAL HELPERS
=head2 Test2::Tools::Tester
This is the most recent set of tools to help you test your events. To really
understand these you should familiarize yourself with
L<Test2::Manual::Anatomy::Event>. If you are going to be writing anything more
than the most simple of tools you should know how events work.
The L<Test2::Tools::Tester> documentation is a good place for further reading.
=head2 Test2::Tools::HarnessTester
The L<Test2::Tools::HarnessTester> can export the C<summarize_events()> tool.
This tool lets you run your event arrayref through L<Test2::Harness> so that you
can get a pass/fail summary.
my $summary = summarize_events($events);
The summary looks like this:
{
plan => $plan_facet, # the plan event facet
pass => $bool, # true if the events result in a pass
fail => $bool, # true if the events result in a fail
errors => $error_count, # Number of error facets seen
failures => $failure_count, # Number of failing assertions seen
assertions => $assertion_count, # Total number of assertions seen
}
=head2 Test2::Tools::Compare
B<DEPRECATED> These tools were written before the switch to faceted events.
These will still work, but are no longer the recommended way to test your
tools.
The L<Test2::Tools::Compare> library exports a handful of extras to help test
events.
=over 4
=item event $TYPE => ...
Use in an array check against $events to check for a specific type of event
with the properties you specify.
=item fail_events $TYPE => ...
Use when you expect a failing assertion of $TYPE. This will automatically check
that the next event following it is a diagnostics message with the default
failure text.
B<Note:> This is outdated as a single event may now possess both the failing
assertion AND the failing text, such events will fail this test.
=back
=head1 SEE ALSO
L<Test2::Manual> - Primary index of the manual.
=head1 SOURCE
The source code repository for Test2-Manual can be found at
F<https://github.com/Test-More/Test2-Suite/>.
=head1 MAINTAINERS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 AUTHORS
=over 4
=item Chad Granum E<lt>exodist@cpan.orgE<gt>
=back
=head1 COPYRIGHT
Copyright 2018 Chad Granum E<lt>exodist@cpan.orgE<gt>.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See F<http://dev.perl.org/licenses/>
=cut