summaryrefslogtreecommitdiffstats
path: root/upstream/debian-unstable/man3/Test2::API::Context.3perl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
commitfc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch)
treece1e3bce06471410239a6f41282e328770aa404a /upstream/debian-unstable/man3/Test2::API::Context.3perl
parentInitial commit. (diff)
downloadmanpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.tar.xz
manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.zip
Adding upstream version 4.22.0.upstream/4.22.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'upstream/debian-unstable/man3/Test2::API::Context.3perl')
-rw-r--r--upstream/debian-unstable/man3/Test2::API::Context.3perl611
1 files changed, 611 insertions, 0 deletions
diff --git a/upstream/debian-unstable/man3/Test2::API::Context.3perl b/upstream/debian-unstable/man3/Test2::API::Context.3perl
new file mode 100644
index 00000000..2a1febab
--- /dev/null
+++ b/upstream/debian-unstable/man3/Test2::API::Context.3perl
@@ -0,0 +1,611 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "Test2::API::Context 3perl"
+.TH Test2::API::Context 3perl 2024-01-12 "perl v5.38.2" "Perl Programmers Reference Guide"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+Test2::API::Context \- Object to represent a testing context.
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+The context object is the primary interface for authors of testing tools
+written with Test2. The context object represents the context in
+which a test takes place (File and Line Number), and provides a quick way to
+generate events from that context. The context object also takes care of
+sending events to the correct Test2::Hub instance.
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+In general you will not be creating contexts directly. To obtain a context you
+should always use \f(CWcontext()\fR which is exported by the Test2::API module.
+.PP
+.Vb 1
+\& use Test2::API qw/context/;
+\&
+\& sub my_ok {
+\& my ($bool, $name) = @_;
+\& my $ctx = context();
+\&
+\& if ($bool) {
+\& $ctx\->pass($name);
+\& }
+\& else {
+\& $ctx\->fail($name);
+\& }
+\&
+\& $ctx\->release; # You MUST do this!
+\& return $bool;
+\& }
+.Ve
+.PP
+Context objects make it easy to wrap other tools that also use context. Once
+you grab a context, any tool you call before releasing your context will
+inherit it:
+.PP
+.Vb 4
+\& sub wrapper {
+\& my ($bool, $name) = @_;
+\& my $ctx = context();
+\& $ctx\->diag("wrapping my_ok");
+\&
+\& my $out = my_ok($bool, $name);
+\& $ctx\->release; # You MUST do this!
+\& return $out;
+\& }
+.Ve
+.SH "CRITICAL DETAILS"
+.IX Header "CRITICAL DETAILS"
+.IP "you MUST always use the \fBcontext()\fR sub from Test2::API" 4
+.IX Item "you MUST always use the context() sub from Test2::API"
+Creating your own context via \f(CW\*(C`Test2::API::Context\->new()\*(C'\fR will almost never
+produce a desirable result. Use \f(CWcontext()\fR which is exported by Test2::API.
+.Sp
+There are a handful of cases where a tool author may want to create a new
+context by hand, which is why the \f(CW\*(C`new\*(C'\fR method exists. Unless you really know
+what you are doing you should avoid this.
+.IP "You MUST always release the context when done with it" 4
+.IX Item "You MUST always release the context when done with it"
+Releasing the context tells the system you are done with it. This gives it a
+chance to run any necessary callbacks or cleanup tasks. If you forget to
+release the context it will try to detect the problem and warn you about it.
+.IP "You MUST NOT pass context objects around" 4
+.IX Item "You MUST NOT pass context objects around"
+When you obtain a context object it is made specifically for your tool and any
+tools nested within. If you pass a context around you run the risk of polluting
+other tools with incorrect context information.
+.Sp
+If you are certain that you want a different tool to use the same context you
+may pass it a snapshot. \f(CW\*(C`$ctx\->snapshot\*(C'\fR will give you a shallow clone of
+the context that is safe to pass around or store.
+.IP "You MUST NOT store or cache a context for later" 4
+.IX Item "You MUST NOT store or cache a context for later"
+As long as a context exists for a given hub, all tools that try to get a
+context will get the existing instance. If you try to store the context you
+will pollute other tools with incorrect context information.
+.Sp
+If you are certain that you want to save the context for later, you can use a
+snapshot. \f(CW\*(C`$ctx\->snapshot\*(C'\fR will give you a shallow clone of the context
+that is safe to pass around or store.
+.Sp
+\&\f(CWcontext()\fR has some mechanisms to protect you if you do cause a context to
+persist beyond the scope in which it was obtained. In practice you should not
+rely on these protections, and they are fairly noisy with warnings.
+.IP "You SHOULD obtain your context as soon as possible in a given tool" 4
+.IX Item "You SHOULD obtain your context as soon as possible in a given tool"
+You never know what tools you call from within your own tool will need a
+context. Obtaining the context early ensures that nested tools can find the
+context you want them to find.
+.SH METHODS
+.IX Header "METHODS"
+.ie n .IP $ctx\->done_testing; 4
+.el .IP \f(CW$ctx\fR\->done_testing; 4
+.IX Item "$ctx->done_testing;"
+Note that testing is finished. If no plan has been set this will generate a
+Plan event.
+.ie n .IP "$clone = $ctx\->\fBsnapshot()\fR" 4
+.el .IP "\f(CW$clone\fR = \f(CW$ctx\fR\->\fBsnapshot()\fR" 4
+.IX Item "$clone = $ctx->snapshot()"
+This will return a shallow clone of the context. The shallow clone is safe to
+store for later.
+.ie n .IP $ctx\->\fBrelease()\fR 4
+.el .IP \f(CW$ctx\fR\->\fBrelease()\fR 4
+.IX Item "$ctx->release()"
+This will release the context. This runs cleanup tasks, and several important
+hooks. It will also restore \f(CW$!\fR, \f(CW$?\fR, and \f(CW$@\fR to what they were when the
+context was created.
+.Sp
+\&\fBNote:\fR If a context is acquired more than once an internal refcount is kept.
+\&\f(CWrelease()\fR decrements the ref count, none of the other actions of
+\&\f(CWrelease()\fR will occur unless the refcount hits 0. This means only the last
+call to \f(CWrelease()\fR will reset \f(CW$?\fR, \f(CW$!\fR, \f(CW$@\fR,and run the cleanup tasks.
+.ie n .IP $ctx\->throw($message) 4
+.el .IP \f(CW$ctx\fR\->throw($message) 4
+.IX Item "$ctx->throw($message)"
+This will throw an exception reporting to the file and line number of the
+context. This will also release the context for you.
+.ie n .IP $ctx\->alert($message) 4
+.el .IP \f(CW$ctx\fR\->alert($message) 4
+.IX Item "$ctx->alert($message)"
+This will issue a warning from the file and line number of the context.
+.ie n .IP "$stack = $ctx\->\fBstack()\fR" 4
+.el .IP "\f(CW$stack\fR = \f(CW$ctx\fR\->\fBstack()\fR" 4
+.IX Item "$stack = $ctx->stack()"
+This will return the Test2::API::Stack instance the context used to find
+the current hub.
+.ie n .IP "$hub = $ctx\->\fBhub()\fR" 4
+.el .IP "\f(CW$hub\fR = \f(CW$ctx\fR\->\fBhub()\fR" 4
+.IX Item "$hub = $ctx->hub()"
+This will return the Test2::Hub instance the context recognizes as the
+current one to which all events should be sent.
+.ie n .IP "$dbg = $ctx\->\fBtrace()\fR" 4
+.el .IP "\f(CW$dbg\fR = \f(CW$ctx\fR\->\fBtrace()\fR" 4
+.IX Item "$dbg = $ctx->trace()"
+This will return the Test2::EventFacet::Trace instance used by the context.
+.ie n .IP "$ctx\->do_in_context(\e&code, @args);" 4
+.el .IP "\f(CW$ctx\fR\->do_in_context(\e&code, \f(CW@args\fR);" 4
+.IX Item "$ctx->do_in_context(&code, @args);"
+Sometimes you have a context that is not current, and you want things to use it
+as the current one. In these cases you can call
+\&\f(CW\*(C`$ctx\->do_in_context(sub { ... })\*(C'\fR. The codeblock will be run, and
+anything inside of it that looks for a context will find the one on which the
+method was called.
+.Sp
+This \fBDOES NOT\fR affect context on other hubs, only the hub used by the context
+will be affected.
+.Sp
+.Vb 4
+\& my $ctx = ...;
+\& $ctx\->do_in_context(sub {
+\& my $ctx = context(); # returns the $ctx the sub is called on
+\& });
+.Ve
+.Sp
+\&\fBNote:\fR The context will actually be cloned, the clone will be used instead of
+the original. This allows the thread id, process id, and error variables to be correct without
+modifying the original context.
+.ie n .IP $ctx\->\fBrestore_error_vars()\fR 4
+.el .IP \f(CW$ctx\fR\->\fBrestore_error_vars()\fR 4
+.IX Item "$ctx->restore_error_vars()"
+This will set \f(CW$!\fR, \f(CW$?\fR, and \f(CW$@\fR to what they were when the context was
+created. There is no localization or anything done here, calling this method
+will actually set these vars.
+.ie n .IP "$! = $ctx\->\fBerrno()\fR" 4
+.el .IP "$! = \f(CW$ctx\fR\->\fBerrno()\fR" 4
+.IX Item "$! = $ctx->errno()"
+The (numeric) value of \f(CW$!\fR when the context was created.
+.ie n .IP "$? = $ctx\->\fBchild_error()\fR" 4
+.el .IP "$? = \f(CW$ctx\fR\->\fBchild_error()\fR" 4
+.IX Item "$? = $ctx->child_error()"
+The value of \f(CW$?\fR when the context was created.
+.ie n .IP "$@ = $ctx\->\fBeval_error()\fR" 4
+.el .IP "$@ = \f(CW$ctx\fR\->\fBeval_error()\fR" 4
+.IX Item "$@ = $ctx->eval_error()"
+The value of \f(CW$@\fR when the context was created.
+.SS "EVENT PRODUCTION METHODS"
+.IX Subsection "EVENT PRODUCTION METHODS"
+\&\fBWhich one do I use?\fR
+.PP
+The \f(CW\*(C`pass*\*(C'\fR and \f(CW\*(C`fail*\*(C'\fR are optimal if they meet your situation, using one of
+them will always be the most optimal. That said they are optimal by eliminating
+many features.
+.PP
+Method such as \f(CW\*(C`ok\*(C'\fR, and \f(CW\*(C`note\*(C'\fR are shortcuts for generating common 1\-task
+events based on the old API, however they are forward compatible, and easy to
+use. If these meet your needs then go ahead and use them, but please check back
+often for alternatives that may be added.
+.PP
+If you want to generate new style events, events that do many things at once,
+then you want the \f(CW\*(C`*ev2*\*(C'\fR methods. These let you directly specify which facets
+you wish to use.
+.ie n .IP "$event = $ctx\->\fBpass()\fR" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->\fBpass()\fR" 4
+.IX Item "$event = $ctx->pass()"
+.PD 0
+.ie n .IP "$event = $ctx\->pass($name)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->pass($name)" 4
+.IX Item "$event = $ctx->pass($name)"
+.PD
+This will send and return an Test2::Event::Pass event. You may optionally
+provide a \f(CW$name\fR for the assertion.
+.Sp
+The Test2::Event::Pass is a specially crafted and optimized event, using
+this will help the performance of passing tests.
+.ie n .IP "$true = $ctx\->\fBpass_and_release()\fR" 4
+.el .IP "\f(CW$true\fR = \f(CW$ctx\fR\->\fBpass_and_release()\fR" 4
+.IX Item "$true = $ctx->pass_and_release()"
+.PD 0
+.ie n .IP "$true = $ctx\->pass_and_release($name)" 4
+.el .IP "\f(CW$true\fR = \f(CW$ctx\fR\->pass_and_release($name)" 4
+.IX Item "$true = $ctx->pass_and_release($name)"
+.PD
+This is a combination of \f(CWpass()\fR and \f(CWrelease()\fR. You can use this if you do
+not plan to do anything with the context after sending the event. This helps
+write more clear and compact code.
+.Sp
+.Vb 4
+\& sub shorthand {
+\& my ($bool, $name) = @_;
+\& my $ctx = context();
+\& return $ctx\->pass_and_release($name) if $bool;
+\&
+\& ... Handle a failure ...
+\& }
+\&
+\& sub longform {
+\& my ($bool, $name) = @_;
+\& my $ctx = context();
+\&
+\& if ($bool) {
+\& $ctx\->pass($name);
+\& $ctx\->release;
+\& return 1;
+\& }
+\&
+\& ... Handle a failure ...
+\& }
+.Ve
+.ie n .IP "my $event = $ctx\->\fBfail()\fR" 4
+.el .IP "my \f(CW$event\fR = \f(CW$ctx\fR\->\fBfail()\fR" 4
+.IX Item "my $event = $ctx->fail()"
+.PD 0
+.ie n .IP "my $event = $ctx\->fail($name)" 4
+.el .IP "my \f(CW$event\fR = \f(CW$ctx\fR\->fail($name)" 4
+.IX Item "my $event = $ctx->fail($name)"
+.ie n .IP "my $event = $ctx\->fail($name, @diagnostics)" 4
+.el .IP "my \f(CW$event\fR = \f(CW$ctx\fR\->fail($name, \f(CW@diagnostics\fR)" 4
+.IX Item "my $event = $ctx->fail($name, @diagnostics)"
+.PD
+This lets you send an Test2::Event::Fail event. You may optionally provide a
+\&\f(CW$name\fR and \f(CW@diagnostics\fR messages.
+.Sp
+Diagnostics messages can be simple strings, data structures, or instances of
+Test2::EventFacet::Info::Table (which are converted inline into the
+Test2::EventFacet::Info structure).
+.ie n .IP "my $false = $ctx\->\fBfail_and_release()\fR" 4
+.el .IP "my \f(CW$false\fR = \f(CW$ctx\fR\->\fBfail_and_release()\fR" 4
+.IX Item "my $false = $ctx->fail_and_release()"
+.PD 0
+.ie n .IP "my $false = $ctx\->fail_and_release($name)" 4
+.el .IP "my \f(CW$false\fR = \f(CW$ctx\fR\->fail_and_release($name)" 4
+.IX Item "my $false = $ctx->fail_and_release($name)"
+.ie n .IP "my $false = $ctx\->fail_and_release($name, @diagnostics)" 4
+.el .IP "my \f(CW$false\fR = \f(CW$ctx\fR\->fail_and_release($name, \f(CW@diagnostics\fR)" 4
+.IX Item "my $false = $ctx->fail_and_release($name, @diagnostics)"
+.PD
+This is a combination of \f(CWfail()\fR and \f(CWrelease()\fR. This can be used to write
+clearer and shorter code.
+.Sp
+.Vb 4
+\& sub shorthand {
+\& my ($bool, $name) = @_;
+\& my $ctx = context();
+\& return $ctx\->fail_and_release($name) unless $bool;
+\&
+\& ... Handle a success ...
+\& }
+\&
+\& sub longform {
+\& my ($bool, $name) = @_;
+\& my $ctx = context();
+\&
+\& unless ($bool) {
+\& $ctx\->pass($name);
+\& $ctx\->release;
+\& return 1;
+\& }
+\&
+\& ... Handle a success ...
+\& }
+.Ve
+.ie n .IP "$event = $ctx\->ok($bool, $name)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->ok($bool, \f(CW$name\fR)" 4
+.IX Item "$event = $ctx->ok($bool, $name)"
+.PD 0
+.ie n .IP "$event = $ctx\->ok($bool, $name, \e@on_fail)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->ok($bool, \f(CW$name\fR, \e@on_fail)" 4
+.IX Item "$event = $ctx->ok($bool, $name, @on_fail)"
+.PD
+\&\fBNOTE:\fR Use of this method is discouraged in favor of \f(CWpass()\fR and \f(CWfail()\fR
+which produce Test2::Event::Pass and Test2::Event::Fail events. These
+newer event types are faster and less crufty.
+.Sp
+This will create an Test2::Event::Ok object for you. If \f(CW$bool\fR is false
+then an Test2::Event::Diag event will be sent as well with details about the
+failure. If you do not want automatic diagnostics you should use the
+\&\f(CWsend_event()\fR method directly.
+.Sp
+The third argument \f(CW\*(C`\e@on_fail\*(C'\fR) is an optional set of diagnostics to be sent in
+the event of a test failure. Unlike with \f(CWfail()\fR these diagnostics must be
+plain strings, data structures are not supported.
+.ie n .IP "$event = $ctx\->note($message)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->note($message)" 4
+.IX Item "$event = $ctx->note($message)"
+Send an Test2::Event::Note. This event prints a message to STDOUT.
+.ie n .IP "$event = $ctx\->diag($message)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->diag($message)" 4
+.IX Item "$event = $ctx->diag($message)"
+Send an Test2::Event::Diag. This event prints a message to STDERR.
+.ie n .IP "$event = $ctx\->plan($max)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->plan($max)" 4
+.IX Item "$event = $ctx->plan($max)"
+.PD 0
+.ie n .IP "$event = $ctx\->plan(0, 'SKIP', $reason)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->plan(0, 'SKIP', \f(CW$reason\fR)" 4
+.IX Item "$event = $ctx->plan(0, 'SKIP', $reason)"
+.PD
+This can be used to send an Test2::Event::Plan event. This event
+usually takes either a number of tests you expect to run. Optionally you can
+set the expected count to 0 and give the 'SKIP' directive with a reason to
+cause all tests to be skipped.
+.ie n .IP "$event = $ctx\->skip($name, $reason);" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->skip($name, \f(CW$reason\fR);" 4
+.IX Item "$event = $ctx->skip($name, $reason);"
+Send an Test2::Event::Skip event.
+.ie n .IP "$event = $ctx\->bail($reason)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->bail($reason)" 4
+.IX Item "$event = $ctx->bail($reason)"
+This sends an Test2::Event::Bail event. This event will completely
+terminate all testing.
+.ie n .IP "$event = $ctx\->send_ev2(%facets)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->send_ev2(%facets)" 4
+.IX Item "$event = $ctx->send_ev2(%facets)"
+This lets you build and send a V2 event directly from facets. The event is
+returned after it is sent.
+.Sp
+This example sends a single assertion, a note (comment for stdout in
+Test::Builder talk) and sets the plan to 1.
+.Sp
+.Vb 5
+\& my $event = $ctx\->send_event(
+\& plan => {count => 1},
+\& assert => {pass => 1, details => "A passing assert"},
+\& info => [{tag => \*(AqNOTE\*(Aq, details => "This is a note"}],
+\& );
+.Ve
+.ie n .IP "$event = $ctx\->build_e2(%facets)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->build_e2(%facets)" 4
+.IX Item "$event = $ctx->build_e2(%facets)"
+This is the same as \f(CWsend_ev2()\fR, except it builds and returns the event
+without sending it.
+.ie n .IP "$event = $ctx\->send_ev2_and_release($Type, %parameters)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->send_ev2_and_release($Type, \f(CW%parameters\fR)" 4
+.IX Item "$event = $ctx->send_ev2_and_release($Type, %parameters)"
+This is a combination of \f(CWsend_ev2()\fR and \f(CWrelease()\fR.
+.Sp
+.Vb 4
+\& sub shorthand {
+\& my $ctx = context();
+\& return $ctx\->send_ev2_and_release(assert => {pass => 1, details => \*(Aqfoo\*(Aq});
+\& }
+\&
+\& sub longform {
+\& my $ctx = context();
+\& my $event = $ctx\->send_ev2(assert => {pass => 1, details => \*(Aqfoo\*(Aq});
+\& $ctx\->release;
+\& return $event;
+\& }
+.Ve
+.ie n .IP "$event = $ctx\->send_event($Type, %parameters)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->send_event($Type, \f(CW%parameters\fR)" 4
+.IX Item "$event = $ctx->send_event($Type, %parameters)"
+\&\fBIt is better to use send_ev2() in new code.\fR
+.Sp
+This lets you build and send an event of any type. The \f(CW$Type\fR argument should
+be the event package name with \f(CW\*(C`Test2::Event::\*(C'\fR left off, or a fully
+qualified package name prefixed with a '+'. The event is returned after it is
+sent.
+.Sp
+.Vb 1
+\& my $event = $ctx\->send_event(\*(AqOk\*(Aq, ...);
+.Ve
+.Sp
+or
+.Sp
+.Vb 1
+\& my $event = $ctx\->send_event(\*(Aq+Test2::Event::Ok\*(Aq, ...);
+.Ve
+.ie n .IP "$event = $ctx\->build_event($Type, %parameters)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->build_event($Type, \f(CW%parameters\fR)" 4
+.IX Item "$event = $ctx->build_event($Type, %parameters)"
+\&\fBIt is better to use build_ev2() in new code.\fR
+.Sp
+This is the same as \f(CWsend_event()\fR, except it builds and returns the event
+without sending it.
+.ie n .IP "$event = $ctx\->send_event_and_release($Type, %parameters)" 4
+.el .IP "\f(CW$event\fR = \f(CW$ctx\fR\->send_event_and_release($Type, \f(CW%parameters\fR)" 4
+.IX Item "$event = $ctx->send_event_and_release($Type, %parameters)"
+\&\fBIt is better to use send_ev2_and_release() in new code.\fR
+.Sp
+This is a combination of \f(CWsend_event()\fR and \f(CWrelease()\fR.
+.Sp
+.Vb 4
+\& sub shorthand {
+\& my $ctx = context();
+\& return $ctx\->send_event_and_release(Pass => { name => \*(Aqfoo\*(Aq });
+\& }
+\&
+\& sub longform {
+\& my $ctx = context();
+\& my $event = $ctx\->send_event(Pass => { name => \*(Aqfoo\*(Aq });
+\& $ctx\->release;
+\& return $event;
+\& }
+.Ve
+.SH HOOKS
+.IX Header "HOOKS"
+There are 2 types of hooks, init hooks, and release hooks. As the names
+suggest, these hooks are triggered when contexts are created or released.
+.SS "INIT HOOKS"
+.IX Subsection "INIT HOOKS"
+These are called whenever a context is initialized. That means when a new
+instance is created. These hooks are \fBNOT\fR called every time something
+requests a context, just when a new one is created.
+.PP
+\fIGLOBAL\fR
+.IX Subsection "GLOBAL"
+.PP
+This is how you add a global init callback. Global callbacks happen for every
+context for any hub or stack.
+.PP
+.Vb 4
+\& Test2::API::test2_add_callback_context_init(sub {
+\& my $ctx = shift;
+\& ...
+\& });
+.Ve
+.PP
+\fIPER HUB\fR
+.IX Subsection "PER HUB"
+.PP
+This is how you add an init callback for all contexts created for a given hub.
+These callbacks will not run for other hubs.
+.PP
+.Vb 4
+\& $hub\->add_context_init(sub {
+\& my $ctx = shift;
+\& ...
+\& });
+.Ve
+.PP
+\fIPER CONTEXT\fR
+.IX Subsection "PER CONTEXT"
+.PP
+This is how you specify an init hook that will only run if your call to
+\&\f(CWcontext()\fR generates a new context. The callback will be ignored if
+\&\f(CWcontext()\fR is returning an existing context.
+.PP
+.Vb 4
+\& my $ctx = context(on_init => sub {
+\& my $ctx = shift;
+\& ...
+\& });
+.Ve
+.SS "RELEASE HOOKS"
+.IX Subsection "RELEASE HOOKS"
+These are called whenever a context is released. That means when the last
+reference to the instance is about to be destroyed. These hooks are \fBNOT\fR
+called every time \f(CW\*(C`$ctx\->release\*(C'\fR is called.
+.PP
+\fIGLOBAL\fR
+.IX Subsection "GLOBAL"
+.PP
+This is how you add a global release callback. Global callbacks happen for every
+context for any hub or stack.
+.PP
+.Vb 4
+\& Test2::API::test2_add_callback_context_release(sub {
+\& my $ctx = shift;
+\& ...
+\& });
+.Ve
+.PP
+\fIPER HUB\fR
+.IX Subsection "PER HUB"
+.PP
+This is how you add a release callback for all contexts created for a given
+hub. These callbacks will not run for other hubs.
+.PP
+.Vb 4
+\& $hub\->add_context_release(sub {
+\& my $ctx = shift;
+\& ...
+\& });
+.Ve
+.PP
+\fIPER CONTEXT\fR
+.IX Subsection "PER CONTEXT"
+.PP
+This is how you add release callbacks directly to a context. The callback will
+\&\fBALWAYS\fR be added to the context that gets returned, it does not matter if a
+new one is generated, or if an existing one is returned.
+.PP
+.Vb 4
+\& my $ctx = context(on_release => sub {
+\& my $ctx = shift;
+\& ...
+\& });
+.Ve
+.SH "THIRD PARTY META-DATA"
+.IX Header "THIRD PARTY META-DATA"
+This object consumes Test2::Util::ExternalMeta which provides a consistent
+way for you to attach meta-data to instances of this class. This is useful for
+tools, plugins, and other extensions.
+.SH SOURCE
+.IX Header "SOURCE"
+The source code repository for Test2 can be found at
+\&\fIhttp://github.com/Test\-More/test\-more/\fR.
+.SH MAINTAINERS
+.IX Header "MAINTAINERS"
+.IP "Chad Granum <exodist@cpan.org>" 4
+.IX Item "Chad Granum <exodist@cpan.org>"
+.SH AUTHORS
+.IX Header "AUTHORS"
+.PD 0
+.IP "Chad Granum <exodist@cpan.org>" 4
+.IX Item "Chad Granum <exodist@cpan.org>"
+.IP "Kent Fredric <kentnl@cpan.org>" 4
+.IX Item "Kent Fredric <kentnl@cpan.org>"
+.PD
+.SH COPYRIGHT
+.IX Header "COPYRIGHT"
+Copyright 2020 Chad Granum <exodist@cpan.org>.
+.PP
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+.PP
+See \fIhttp://dev.perl.org/licenses/\fR