This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Upgrade Test::Simple from version 1.302026 to 1.302035
[perl5.git] / cpan / Test-Simple / lib / Test2 / API / Context.pm
CommitLineData
b4514920
CG
1package Test2::API::Context;
2use strict;
3use warnings;
4
35014935 5our $VERSION = '1.302035';
b4514920
CG
6
7
8use Carp qw/confess croak longmess/;
9use Scalar::Util qw/weaken/;
10use Test2::Util qw/get_tid try pkg_to_file get_tid/;
11
12use Test2::Util::Trace();
13use Test2::API();
14
15# Preload some key event types
16my %LOADED = (
17 map {
18 my $pkg = "Test2::Event::$_";
19 my $file = "Test2/Event/$_.pm";
20 require $file unless $INC{$file};
21 ( $pkg => $pkg, $_ => $pkg )
22 } qw/Ok Diag Note Plan Bail Exception Waiting Skip Subtest/
23);
24
25use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/;
26use Test2::Util::HashBase qw{
27 stack hub trace _on_release _depth _is_canon _is_spawn _aborted
28 errno eval_error child_error
29};
30
31# Private, not package vars
32# It is safe to cache these.
33my $ON_RELEASE = Test2::API::_context_release_callbacks_ref();
34my $CONTEXTS = Test2::API::_contexts_ref();
35
36sub init {
37 my $self = shift;
38
39 confess "The 'trace' attribute is required"
40 unless $self->{+TRACE};
41
42 confess "The 'hub' attribute is required"
43 unless $self->{+HUB};
44
45 $self->{+_DEPTH} = 0 unless defined $self->{+_DEPTH};
46
47 $self->{+ERRNO} = $! unless exists $self->{+ERRNO};
48 $self->{+EVAL_ERROR} = $@ unless exists $self->{+EVAL_ERROR};
49 $self->{+CHILD_ERROR} = $? unless exists $self->{+CHILD_ERROR};
50}
51
52sub snapshot { bless {%{$_[0]}, _is_canon => undef, _is_spawn => undef, _aborted => undef}, __PACKAGE__ }
53
54sub restore_error_vars {
55 my $self = shift;
56 ($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR};
57}
58
59sub DESTROY {
60 return unless $_[0]->{+_IS_CANON} || $_[0]->{+_IS_SPAWN};
61 return if $_[0]->{+_ABORTED} && ${$_[0]->{+_ABORTED}};
62 my ($self) = @_;
63
64 my $hub = $self->{+HUB};
65 my $hid = $hub->{hid};
66
67 # Do not show the warning if it looks like an exception has been thrown, or
68 # if the context is not local to this process or thread.
69 if($self->{+EVAL_ERROR} eq $@ && $hub->is_local) {
70 my $frame = $self->{+_IS_SPAWN} || $self->{+TRACE}->frame;
71 warn <<" EOT";
72A context appears to have been destroyed without first calling release().
73Based on \$@ it does not look like an exception was thrown (this is not always
74a reliable test)
75
76This is a problem because the global error variables (\$!, \$@, and \$?) will
77not be restored. In addition some release callbacks will not work properly from
78inside a DESTROY method.
79
80Here are the context creation details, just in case a tool forgot to call
81release():
82 File: $frame->[1]
83 Line: $frame->[2]
84 Tool: $frame->[3]
85
86Cleaning up the CONTEXT stack...
87 EOT
88 }
89
90 return if $self->{+_IS_SPAWN};
91
92 # Remove the key itself to avoid a slow memory leak
93 delete $CONTEXTS->{$hid};
94 $self->{+_IS_CANON} = undef;
95
96 if (my $cbk = $self->{+_ON_RELEASE}) {
97 $_->($self) for reverse @$cbk;
98 }
99 if (my $hcbk = $hub->{_context_release}) {
100 $_->($self) for reverse @$hcbk;
101 }
102 $_->($self) for reverse @$ON_RELEASE;
103}
104
105# release exists to implement behaviors like die-on-fail. In die-on-fail you
106# want to die after a failure, but only after diagnostics have been reported.
107# The ideal time for the die to happen is when the context is released.
108# Unfortunately die does not work in a DESTROY block.
109sub release {
110 my ($self) = @_;
111
112 ($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR} and return $self->{+_IS_SPAWN} = undef
113 if $self->{+_IS_SPAWN};
114
115 croak "release() should not be called on context that is neither canon nor a child"
116 unless $self->{+_IS_CANON};
117
118 my $hub = $self->{+HUB};
119 my $hid = $hub->{hid};
120
121 croak "context thinks it is canon, but it is not"
122 unless $CONTEXTS->{$hid} && $CONTEXTS->{$hid} == $self;
123
124 # Remove the key itself to avoid a slow memory leak
125 $self->{+_IS_CANON} = undef;
126 delete $CONTEXTS->{$hid};
127
128 if (my $cbk = $self->{+_ON_RELEASE}) {
129 $_->($self) for reverse @$cbk;
130 }
131 if (my $hcbk = $hub->{_context_release}) {
132 $_->($self) for reverse @$hcbk;
133 }
134 $_->($self) for reverse @$ON_RELEASE;
135
136 # Do this last so that nothing else changes them.
137 # If one of the hooks dies then these do not get restored, this is
138 # intentional
139 ($!, $@, $?) = @$self{+ERRNO, +EVAL_ERROR, +CHILD_ERROR};
140
141 return;
142}
143
144sub do_in_context {
145 my $self = shift;
146 my ($sub, @args) = @_;
147
148 # We need to update the pid/tid and error vars.
149 my $clone = $self->snapshot;
150 @$clone{+ERRNO, +EVAL_ERROR, +CHILD_ERROR} = ($!, $@, $?);
151 $clone->{+TRACE} = $clone->{+TRACE}->snapshot;
152 $clone->{+TRACE}->set_pid($$);
153 $clone->{+TRACE}->set_tid(get_tid());
154
155 my $hub = $clone->{+HUB};
156 my $hid = $hub->hid;
157
158 my $old = $CONTEXTS->{$hid};
159
160 $clone->{+_IS_CANON} = 1;
161 $CONTEXTS->{$hid} = $clone;
162 weaken($CONTEXTS->{$hid});
163 my ($ok, $err) = &try($sub, @args);
164 my ($rok, $rerr) = try { $clone->release };
165 delete $clone->{+_IS_CANON};
166
167 if ($old) {
168 $CONTEXTS->{$hid} = $old;
169 weaken($CONTEXTS->{$hid});
170 }
171 else {
172 delete $CONTEXTS->{$hid};
173 }
174
175 die $err unless $ok;
176 die $rerr unless $rok;
177}
178
179sub done_testing {
180 my $self = shift;
181 $self->hub->finalize($self->trace, 1);
182 return;
183}
184
185sub throw {
186 my ($self, $msg) = @_;
187 ${$self->{+_ABORTED}}++ if $self->{+_ABORTED};
188 $self->release if $self->{+_IS_CANON} || $self->{+_IS_SPAWN};
189 $self->trace->throw($msg);
190}
191
192sub alert {
193 my ($self, $msg) = @_;
194 $self->trace->alert($msg);
195}
196
197sub send_event {
198 my $self = shift;
199 my $event = shift;
200 my %args = @_;
201
202 my $pkg = $LOADED{$event} || $self->_parse_event($event);
203
204 $self->{+HUB}->send(
205 $pkg->new(
206 trace => $self->{+TRACE}->snapshot,
207 %args,
208 )
209 );
210}
211
212sub build_event {
213 my $self = shift;
214 my $event = shift;
215 my %args = @_;
216
217 my $pkg = $LOADED{$event} || $self->_parse_event($event);
218
219 $pkg->new(
220 trace => $self->{+TRACE}->snapshot,
221 %args,
222 );
223}
224
225sub ok {
226 my $self = shift;
227 my ($pass, $name, $diag) = @_;
228
229 my $hub = $self->{+HUB};
230
231 my $e = bless {
232 trace => bless( {%{$self->{+TRACE}}}, 'Test2::Util::Trace'),
233 pass => $pass,
234 name => $name,
235 }, 'Test2::Event::Ok';
236 $e->init;
237
238 $hub->send($e);
239 return $e if $pass;
240
241 $self->failure_diag($e);
242
243 if ($diag && @$diag) {
244 $self->diag($_) for @$diag
245 }
246
247 return $e;
248}
249
250sub failure_diag {
251 my $self = shift;
252 my ($e) = @_;
253
254 # This behavior is inherited from Test::Builder which injected a newline at
255 # the start of the first diagnostics when the harness is active, but not
256 # verbose. This is important to keep the diagnostics from showing up
257 # appended to the existing line, which is hard to read. In a verbose
258 # harness there is no need for this.
259 my $prefix = $ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_IS_VERBOSE} ? "\n" : "";
260
261 # Figure out the debug info, this is typically the file name and line
262 # number, but can also be a custom message. If no trace object is provided
263 # then we have nothing useful to display.
264 my $name = $e->name;
265 my $trace = $e->trace;
266 my $debug = $trace ? $trace->debug : "[No trace info available]";
267
268 # Create the initial diagnostics. If the test has a name we put the debug
269 # info on a second line, this behavior is inherited from Test::Builder.
270 my $msg = defined($name)
271 ? qq[${prefix}Failed test '$name'\n$debug.\n]
272 : qq[${prefix}Failed test $debug.\n];
273
274 $self->diag($msg);
275}
276
277sub skip {
278 my $self = shift;
279 my ($name, $reason, @extra) = @_;
280 $self->send_event(
281 'Skip',
282 name => $name,
283 reason => $reason,
284 pass => 1,
285 @extra,
286 );
287}
288
289sub note {
290 my $self = shift;
291 my ($message) = @_;
292 $self->send_event('Note', message => $message);
293}
294
295sub diag {
296 my $self = shift;
297 my ($message) = @_;
298 my $hub = $self->{+HUB};
299 $self->send_event(
300 'Diag',
301 message => $message,
302 );
303}
304
305sub plan {
306 my ($self, $max, $directive, $reason) = @_;
307 ${$self->{+_ABORTED}}++ if $self->{+_ABORTED} && $directive && $directive =~ m/^(SKIP|skip_all)$/;
308 $self->send_event('Plan', max => $max, directive => $directive, reason => $reason);
309}
310
311sub bail {
312 my ($self, $reason) = @_;
313 ${$self->{+_ABORTED}}++ if $self->{+_ABORTED};
314 $self->send_event('Bail', reason => $reason);
315}
316
317sub _parse_event {
318 my $self = shift;
319 my $event = shift;
320
321 my $pkg;
322 if ($event =~ m/^\+(.*)/) {
323 $pkg = $1;
324 }
325 else {
326 $pkg = "Test2::Event::$event";
327 }
328
329 unless ($LOADED{$pkg}) {
330 my $file = pkg_to_file($pkg);
331 my ($ok, $err) = try { require $file };
332 $self->throw("Could not load event module '$pkg': $err")
333 unless $ok;
334
335 $LOADED{$pkg} = $pkg;
336 }
337
338 confess "'$pkg' is not a subclass of 'Test2::Event'"
339 unless $pkg->isa('Test2::Event');
340
341 $LOADED{$event} = $pkg;
342
343 return $pkg;
344}
345
3461;
347
348__END__
349
350=pod
351
352=encoding UTF-8
353
354=head1 NAME
355
356Test2::API::Context - Object to represent a testing context.
357
358=head1 DESCRIPTION
359
360The context object is the primary interface for authors of testing tools
361written with L<Test2>. The context object represents the context in
362which a test takes place (File and Line Number), and provides a quick way to
363generate events from that context. The context object also takes care of
364sending events to the correct L<Test2::Hub> instance.
365
366=head1 SYNOPSIS
367
368In general you will not be creating contexts directly. To obtain a context you
369should always use C<context()> which is exported by the L<Test2::API> module.
370
371 use Test2::API qw/context/;
372
373 sub my_ok {
374 my ($bool, $name) = @_;
375 my $ctx = context();
376 $ctx->ok($bool, $name);
377 $ctx->release; # You MUST do this!
378 return $bool;
379 }
380
381Context objects make it easy to wrap other tools that also use context. Once
382you grab a context, any tool you call before releasing your context will
383inherit it:
384
385 sub wrapper {
386 my ($bool, $name) = @_;
387 my $ctx = context();
388 $ctx->diag("wrapping my_ok");
389
390 my $out = my_ok($bool, $name);
391 $ctx->release; # You MUST do this!
392 return $out;
393 }
394
395=head1 CRITICAL DETAILS
396
397=over 4
398
399=item you MUST always use the context() sub from Test2::API
400
401Creating your own context via C<< Test2::API::Context->new() >> will almost never
402produce a desirable result. Use C<context()> which is exported by L<Test2>.
403
404There are a handful of cases where a tool author may want to create a new
405context by hand, which is why the C<new> method exists. Unless you really know
406what you are doing you should avoid this.
407
408=item You MUST always release the context when done with it
409
410Releasing the context tells the system you are done with it. This gives it a
411chance to run any necessary callbacks or cleanup tasks. If you forget to
412release the context it will try to detect the problem and warn you about it.
413
414=item You MUST NOT pass context objects around
415
416When you obtain a context object it is made specifically for your tool and any
417tools nested within. If you pass a context around you run the risk of polluting
418other tools with incorrect context information.
419
420If you are certain that you want a different tool to use the same context you
421may pass it a snapshot. C<< $ctx->snapshot >> will give you a shallow clone of
422the context that is safe to pass around or store.
423
424=item You MUST NOT store or cache a context for later
425
426As long as a context exists for a given hub, all tools that try to get a
427context will get the existing instance. If you try to store the context you
428will pollute other tools with incorrect context information.
429
430If you are certain that you want to save the context for later, you can use a
431snapshot. C<< $ctx->snapshot >> will give you a shallow clone of the context
432that is safe to pass around or store.
433
434C<context()> has some mechanisms to protect you if you do cause a context to
435persist beyond the scope in which it was obtained. In practice you should not
436rely on these protections, and they are fairly noisy with warnings.
437
438=item You SHOULD obtain your context as soon as possible in a given tool
439
440You never know what tools you call from within your own tool will need a
441context. Obtaining the context early ensures that nested tools can find the
442context you want them to find.
443
444=back
445
446=head1 METHODS
447
448=over 4
449
450=item $ctx->done_testing;
451
452Note that testing is finished. If no plan has been set this will generate a
453Plan event.
454
455=item $clone = $ctx->snapshot()
456
457This will return a shallow clone of the context. The shallow clone is safe to
458store for later.
459
460=item $ctx->release()
461
462This will release the context. This runs cleanup tasks, and several important
463hooks. It will also restore C<$!>, C<$?>, and C<$@> to what they were when the
464context was created.
465
466B<Note:> If a context is acquired more than once an internal refcount is kept.
467C<release()> decrements the ref count, none of the other actions of
468C<release()> will occur unless the refcount hits 0. This means only the last
469call to C<release()> will reset C<$?>, C<$!>, C<$@>,and run the cleanup tasks.
470
471=item $ctx->throw($message)
472
473This will throw an exception reporting to the file and line number of the
474context. This will also release the context for you.
475
476=item $ctx->alert($message)
477
478This will issue a warning from the file and line number of the context.
479
480=item $stack = $ctx->stack()
481
482This will return the L<Test2::API::Stack> instance the context used to find
483the current hub.
484
485=item $hub = $ctx->hub()
486
58818a66
CG
487This will return the L<Test2::Hub> instance the context recognizes as the
488current one to which all events should be sent.
b4514920
CG
489
490=item $dbg = $ctx->trace()
491
492This will return the L<Test2::Util::Trace> instance used by the context.
493
494=item $ctx->do_in_context(\&code, @args);
495
496Sometimes you have a context that is not current, and you want things to use it
497as the current one. In these cases you can call
498C<< $ctx->do_in_context(sub { ... }) >>. The codeblock will be run, and
499anything inside of it that looks for a context will find the one on which the
500method was called.
501
502This B<DOES NOT> affect context on other hubs, only the hub used by the context
503will be affected.
504
505 my $ctx = ...;
506 $ctx->do_in_context(sub {
507 my $ctx = context(); # returns the $ctx the sub is called on
508 });
509
510B<Note:> The context will actually be cloned, the clone will be used instead of
58818a66 511the original. This allows the thread id, process id, and error variables to be correct without
b4514920
CG
512modifying the original context.
513
514=item $ctx->restore_error_vars()
515
516This will set C<$!>, C<$?>, and C<$@> to what they were when the context was
517created. There is no localization or anything done here, calling this method
518will actually set these vars.
519
520=item $! = $ctx->errno()
521
522The (numeric) value of C<$!> when the context was created.
523
524=item $? = $ctx->child_error()
525
526The value of C<$?> when the context was created.
527
528=item $@ = $ctx->eval_error()
529
530The value of C<$@> when the context was created.
531
532=back
533
534=head2 EVENT PRODUCTION METHODS
535
536=over 4
537
538=item $event = $ctx->ok($bool, $name)
539
540=item $event = $ctx->ok($bool, $name, \@diag)
541
542This will create an L<Test2::Event::Ok> object for you. If C<$bool> is false
543then an L<Test2::Event::Diag> event will be sent as well with details about the
544failure. If you do not want automatic diagnostics you should use the
545C<send_event()> method directly.
546
547The C<\@diag> can contain diagnostics messages you wish to have displayed in the
548event of a failure. For a passing test the diagnostics array will be ignored.
549
550=item $event = $ctx->note($message)
551
552Send an L<Test2::Event::Note>. This event prints a message to STDOUT.
553
554=item $event = $ctx->diag($message)
555
556Send an L<Test2::Event::Diag>. This event prints a message to STDERR.
557
558=item $event = $ctx->plan($max)
559
560=item $event = $ctx->plan(0, 'SKIP', $reason)
561
562This can be used to send an L<Test2::Event::Plan> event. This event
563usually takes either a number of tests you expect to run. Optionally you can
564set the expected count to 0 and give the 'SKIP' directive with a reason to
565cause all tests to be skipped.
566
567=item $event = $ctx->skip($name, $reason);
568
569Send an L<Test2::Event::Skip> event.
570
571=item $event = $ctx->bail($reason)
572
573This sends an L<Test2::Event::Bail> event. This event will completely
574terminate all testing.
575
576=item $event = $ctx->send_event($Type, %parameters)
577
578This lets you build and send an event of any type. The C<$Type> argument should
579be the event package name with C<Test2::Event::> left off, or a fully
580qualified package name prefixed with a '+'. The event is returned after it is
581sent.
582
583 my $event = $ctx->send_event('Ok', ...);
584
585or
586
587 my $event = $ctx->send_event('+Test2::Event::Ok', ...);
588
589=item $event = $ctx->build_event($Type, %parameters)
590
591This is the same as C<send_event()>, except it builds and returns the event
592without sending it.
593
594=back
595
596=head1 HOOKS
597
598There are 2 types of hooks, init hooks, and release hooks. As the names
599suggest, these hooks are triggered when contexts are created or released.
600
601=head2 INIT HOOKS
602
603These are called whenever a context is initialized. That means when a new
604instance is created. These hooks are B<NOT> called every time something
605requests a context, just when a new one is created.
606
607=head3 GLOBAL
608
609This is how you add a global init callback. Global callbacks happen for every
610context for any hub or stack.
611
612 Test2::API::test2_add_callback_context_init(sub {
613 my $ctx = shift;
614 ...
615 });
616
617=head3 PER HUB
618
619This is how you add an init callback for all contexts created for a given hub.
620These callbacks will not run for other hubs.
621
622 $hub->add_context_init(sub {
623 my $ctx = shift;
624 ...
625 });
626
627=head3 PER CONTEXT
628
629This is how you specify an init hook that will only run if your call to
630C<context()> generates a new context. The callback will be ignored if
631C<context()> is returning an existing context.
632
633 my $ctx = context(on_init => sub {
634 my $ctx = shift;
635 ...
636 });
637
638=head2 RELEASE HOOKS
639
640These are called whenever a context is released. That means when the last
641reference to the instance is about to be destroyed. These hooks are B<NOT>
642called every time C<< $ctx->release >> is called.
643
644=head3 GLOBAL
645
646This is how you add a global release callback. Global callbacks happen for every
647context for any hub or stack.
648
649 Test2::API::test2_add_callback_context_release(sub {
650 my $ctx = shift;
651 ...
652 });
653
654=head3 PER HUB
655
656This is how you add a release callback for all contexts created for a given
657hub. These callbacks will not run for other hubs.
658
659 $hub->add_context_release(sub {
660 my $ctx = shift;
661 ...
662 });
663
664=head3 PER CONTEXT
665
666This is how you add release callbacks directly to a context. The callback will
667B<ALWAYS> be added to the context that gets returned, it does not matter if a
668new one is generated, or if an existing one is returned.
669
670 my $ctx = context(on_release => sub {
671 my $ctx = shift;
672 ...
673 });
674
675=head1 THIRD PARTY META-DATA
676
677This object consumes L<Test2::Util::ExternalMeta> which provides a consistent
678way for you to attach meta-data to instances of this class. This is useful for
58818a66 679tools, plugins, and other extensions.
b4514920
CG
680
681=head1 SOURCE
682
683The source code repository for Test2 can be found at
684F<http://github.com/Test-More/test-more/>.
685
686=head1 MAINTAINERS
687
688=over 4
689
690=item Chad Granum E<lt>exodist@cpan.orgE<gt>
691
692=back
693
694=head1 AUTHORS
695
696=over 4
697
698=item Chad Granum E<lt>exodist@cpan.orgE<gt>
699
700=item Kent Fredric E<lt>kentnl@cpan.orgE<gt>
701
702=back
703
704=head1 COPYRIGHT
705
706Copyright 2016 Chad Granum E<lt>exodist@cpan.orgE<gt>.
707
708This program is free software; you can redistribute it and/or
709modify it under the same terms as Perl itself.
710
711See F<http://dev.perl.org/licenses/>
712
713=cut