5 our $VERSION = '1.302067';
8 use Carp qw/carp croak confess/;
9 use Test2::Util qw/get_tid ipc_separator/;
11 use Scalar::Util qw/weaken/;
13 use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/;
14 use Test2::Util::HashBase qw{
41 $self->{+TID} = get_tid();
42 $self->{+HID} = join ipc_separator, $self->{+PID}, $self->{+TID}, $ID_POSTFIX++;
46 $self->{+_PASSING} = 1;
48 if (my $formatter = delete $self->{formatter}) {
49 $self->format($formatter);
52 if (my $ipc = $self->{+IPC}) {
53 $ipc->add_hub($self->{+HID});
64 $self->{+_PASSING} = 1;
66 delete $self->{+_PLAN};
67 delete $self->{+ENDED};
68 delete $self->{+BAILED_OUT};
69 delete $self->{+SKIP_REASON};
74 my ($from, %params) = @_;
76 $self->{+_FORMATTER} = $from->{+_FORMATTER}
77 unless $self->{+_FORMATTER} || exists($params{formatter});
79 if ($from->{+IPC} && !$self->{+IPC} && !exists($params{ipc})) {
80 my $ipc = $from->{+IPC};
82 $ipc->add_hub($self->{+HID});
85 if (my $ls = $from->{+_LISTENERS}) {
86 push @{$self->{+_LISTENERS}} => grep { $_->{inherit} } @$ls;
89 if (my $pfs = $from->{+_PRE_FILTERS}) {
90 push @{$self->{+_PRE_FILTERS}} => grep { $_->{inherit} } @$pfs;
93 if (my $fs = $from->{+_FILTERS}) {
94 push @{$self->{+_FILTERS}} => grep { $_->{inherit} } @$fs;
101 my $old = $self->{+_FORMATTER};
102 ($self->{+_FORMATTER}) = @_ if @_;
109 return $$ == $self->{+PID}
110 && get_tid() == $self->{+TID};
115 my ($sub, %params) = @_;
117 carp "Useless addition of a listener in a child process or thread!"
118 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
120 croak "listen only takes coderefs for arguments, got '$sub'"
121 unless ref $sub && ref $sub eq 'CODE';
123 push @{$self->{+_LISTENERS}} => { %params, code => $sub };
125 $sub; # Intentional return.
131 carp "Useless removal of a listener in a child process or thread!"
132 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
134 my %subs = map {$_ => $_} @_;
136 @{$self->{+_LISTENERS}} = grep { !$subs{$_->{code}} } @{$self->{+_LISTENERS}};
141 my ($sub, %params) = @_;
143 carp "Useless addition of a filter in a child process or thread!"
144 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
146 croak "filter only takes coderefs for arguments, got '$sub'"
147 unless ref $sub && ref $sub eq 'CODE';
149 push @{$self->{+_FILTERS}} => { %params, code => $sub };
151 $sub; # Intentional Return
156 carp "Useless removal of a filter in a child process or thread!"
157 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
158 my %subs = map {$_ => $_} @_;
159 @{$self->{+_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_FILTERS}};
164 my ($sub, %params) = @_;
166 croak "pre_filter only takes coderefs for arguments, got '$sub'"
167 unless ref $sub && ref $sub eq 'CODE';
169 push @{$self->{+_PRE_FILTERS}} => { %params, code => $sub };
171 $sub; # Intentional Return
176 my %subs = map {$_ => $_} @_;
177 @{$self->{+_PRE_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_PRE_FILTERS}};
184 carp "Useless addition of a follow-up in a child process or thread!"
185 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
187 croak "follow_up only takes coderefs for arguments, got '$sub'"
188 unless ref $sub && ref $sub eq 'CODE';
190 push @{$self->{+_FOLLOW_UPS}} => $sub;
193 *add_context_aquire = \&add_context_acquire;
194 sub add_context_acquire {
198 croak "add_context_acquire only takes coderefs for arguments, got '$sub'"
199 unless ref $sub && ref $sub eq 'CODE';
201 push @{$self->{+_CONTEXT_ACQUIRE}} => $sub;
203 $sub; # Intentional return.
206 *remove_context_aquire = \&remove_context_acquire;
207 sub remove_context_acquire {
209 my %subs = map {$_ => $_} @_;
210 @{$self->{+_CONTEXT_ACQUIRE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_ACQUIRE}};
213 sub add_context_init {
217 croak "add_context_init only takes coderefs for arguments, got '$sub'"
218 unless ref $sub && ref $sub eq 'CODE';
220 push @{$self->{+_CONTEXT_INIT}} => $sub;
222 $sub; # Intentional return.
225 sub remove_context_init {
227 my %subs = map {$_ => $_} @_;
228 @{$self->{+_CONTEXT_INIT}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_INIT}};
231 sub add_context_release {
235 croak "add_context_release only takes coderefs for arguments, got '$sub'"
236 unless ref $sub && ref $sub eq 'CODE';
238 push @{$self->{+_CONTEXT_RELEASE}} => $sub;
240 $sub; # Intentional return.
243 sub remove_context_release {
245 my %subs = map {$_ => $_} @_;
246 @{$self->{+_CONTEXT_RELEASE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_RELEASE}};
253 if ($self->{+_PRE_FILTERS}) {
254 for (@{$self->{+_PRE_FILTERS}}) {
255 $e = $_->{code}->($self, $e);
260 my $ipc = $self->{+IPC} || return $self->process($e);
263 $ipc->send($self->{+HID}, $e, 'GLOBAL');
264 return $self->process($e);
267 return $ipc->send($self->{+HID}, $e)
268 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
277 if ($self->{+_FILTERS}) {
278 for (@{$self->{+_FILTERS}}) {
279 $e = $_->{code}->($self, $e);
285 my $is_ok = $type eq 'Test2::Event::Ok';
286 my $no_fail = $type eq 'Test2::Event::Diag' || $type eq 'Test2::Event::Note';
287 my $causes_fail = $is_ok ? !$e->{effective_pass} : $no_fail ? 0 : $e->causes_fail;
288 my $counted = $is_ok || (!$no_fail && $e->increments_count);
290 $self->{+COUNT}++ if $counted;
291 $self->{+FAILED}++ if $causes_fail && $counted;
292 $self->{+_PASSING} = 0 if $causes_fail;
294 my $callback = $e->callback($self) unless $is_ok || $no_fail;
296 my $count = $self->{+COUNT};
298 $self->{+_FORMATTER}->write($e, $count) if $self->{+_FORMATTER};
300 if ($self->{+_LISTENERS}) {
301 $_->{code}->($self, $e, $count) for @{$self->{+_LISTENERS}};
304 return $e if $is_ok || $no_fail;
306 my $code = $e->terminate;
308 $self->{+_FORMATTER}->terminate($e) if $self->{+_FORMATTER};
309 $self->terminate($code, $e);
324 my $ipc = $self->{+IPC} || return;
325 return if $self->{+PID} != $$ || $self->{+TID} != get_tid();
327 # No need to do IPC checks on culled events
328 $self->process($_) for $ipc->cull($self->{+HID});
333 my ($trace, $do_plan) = @_;
337 my $plan = $self->{+_PLAN};
338 my $count = $self->{+COUNT};
339 my $failed = $self->{+FAILED};
340 my $active = $self->{+ACTIVE};
342 # return if NOTHING was done.
343 unless ($active || $do_plan || defined($plan) || $count || $failed) {
344 $self->{+_FORMATTER}->finalize($plan, $count, $failed, 0, $self->is_subtest) if $self->{+_FORMATTER};
348 unless ($self->{+ENDED}) {
349 if ($self->{+_FOLLOW_UPS}) {
350 $_->($trace, $self) for reverse @{$self->{+_FOLLOW_UPS}};
353 # These need to be refreshed now
354 $plan = $self->{+_PLAN};
355 $count = $self->{+COUNT};
356 $failed = $self->{+FAILED};
358 if (($plan && $plan eq 'NO PLAN') || ($do_plan && !$plan)) {
360 Test2::Event::Plan->new(
366 $plan = $self->{+_PLAN};
369 my $frame = $trace->frame;
370 if($self->{+ENDED}) {
371 my (undef, $ffile, $fline) = @{$self->{+ENDED}};
372 my (undef, $sfile, $sline) = @$frame;
376 First End: $ffile line $fline
377 Second End: $sfile line $sline
381 $self->{+ENDED} = $frame;
382 my $pass = $self->is_passing(); # Generate the final boolean.
384 $self->{+_FORMATTER}->finalize($plan, $count, $failed, $pass, $self->is_subtest) if $self->{+_FORMATTER};
392 ($self->{+_PASSING}) = @_ if @_;
394 # If we already failed just return 0.
395 my $pass = $self->{+_PASSING} or return 0;
396 return $self->{+_PASSING} = 0 if $self->{+FAILED};
398 my $count = $self->{+COUNT};
399 my $ended = $self->{+ENDED};
400 my $plan = $self->{+_PLAN};
402 return $pass if !$count && $plan && $plan =~ m/^SKIP$/;
404 return $self->{+_PASSING} = 0
405 if $ended && (!$count || !$plan);
407 return $pass unless $plan && $plan =~ m/^\d+$/;
410 return $self->{+_PASSING} = 0 if $count != $plan;
413 return $self->{+_PASSING} = 0 if $count > $plan;
422 return $self->{+_PLAN} unless @_;
426 confess "You cannot unset the plan"
427 unless defined $plan;
429 confess "You cannot change the plan"
430 if $self->{+_PLAN} && $self->{+_PLAN} !~ m/^NO PLAN$/;
432 confess "'$plan' is not a valid plan! Plan must be an integer greater than 0, 'NO PLAN', or 'SKIP'"
433 unless $plan =~ m/^(\d+|NO PLAN|SKIP)$/;
435 $self->{+_PLAN} = $plan;
441 return undef unless $self->{+ENDED};
442 my $plan = $self->{+_PLAN} || return undef;
444 return 1 if $plan !~ m/^\d+$/;
446 return 1 if $plan == $self->{+COUNT};
452 my $ipc = $self->{+IPC} || return;
453 return unless $$ == $self->{+PID};
454 return unless get_tid() == $self->{+TID};
456 $ipc->drop_hub($self->{+HID});
469 Test2::Hub - The conduit through which all events flow.
475 my $hub = Test2::Hub->new();
480 The hub is the place where all events get processed and handed off to the
481 formatter. The hub also tracks test state, and provides several hooks into the
486 =head2 SENDING EVENTS
490 The C<send()> method is used to issue an event to the hub. This method will
491 handle thread/fork sync, filters, listeners, TAP output, etc.
493 =head2 ALTERING OR REMOVING EVENTS
495 You can use either C<filter()> or C<pre_filter()>, depending on your
496 needs. Both have identical syntax, so only C<filter()> is shown here.
499 my ($hub, $event) = @_;
501 my $action = get_action($event);
503 # No action should be taken
504 return $event if $action eq 'none';
506 # You want your filter to remove the event
507 return undef if $action eq 'delete';
509 if ($action eq 'do_it') {
510 my $new_event = copy_event($event);
511 ... Change your copy of the event ...
515 die "Should not happen";
518 By default, filters are not inherited by child hubs. That means if you start a
519 subtest, the subtest will not inherit the filter. You can change this behavior
520 with the C<inherit> parameter:
522 $hub->filter(sub { ... }, inherit => 1);
524 =head2 LISTENING FOR EVENTS
527 my ($hub, $event, $number) = @_;
529 ... do whatever you want with the event ...
534 By default listeners are not inherited by child hubs. That means if you start a
535 subtest, the subtest will not inherit the listener. You can change this behavior
536 with the C<inherit> parameter:
538 $hub->listen(sub { ... }, inherit => 1);
541 =head2 POST-TEST BEHAVIORS
543 $hub->follow_up(sub {
544 my ($trace, $hub) = @_;
546 ... do whatever you need to ...
551 follow_up subs are called only once, either when done_testing is called, or in
554 =head2 SETTING THE FORMATTER
556 By default an instance of L<Test2::Formatter::TAP> is created and used.
558 my $old = $hub->format(My::Formatter->new);
560 Setting the formatter will REPLACE any existing formatter. You may set the
561 formatter to undef to prevent output. The old formatter will be returned if one
562 was already set. Only one formatter is allowed at a time.
568 =item $hub->send($event)
570 This is where all events enter the hub for processing.
572 =item $hub->process($event)
574 This is called by send after it does any IPC handling. You can use this to
575 bypass the IPC process, but in general you should avoid using this.
577 =item $old = $hub->format($formatter)
579 Replace the existing formatter instance with a new one. Formatters must be
580 objects that implement a C<< $formatter->write($event) >> method.
582 =item $sub = $hub->listen(sub { ... }, %optional_params)
584 You can use this to record all events AFTER they have been sent to the
585 formatter. No changes made here will be meaningful, except possibly to other
589 my ($hub, $event, $number) = @_;
591 ... do whatever you want with the event ...
596 Normally listeners are not inherited by child hubs such as subtests. You can
597 add the C<< inherit => 1 >> parameter to allow a listener to be inherited.
599 =item $hub->unlisten($sub)
601 You can use this to remove a listen callback. You must pass in the coderef
602 returned by the C<listen()> method.
604 =item $sub = $hub->filter(sub { ... }, %optional_params)
606 =item $sub = $hub->pre_filter(sub { ... }, %optional_params)
608 These can be used to add filters. Filters can modify, replace, or remove events
609 before anything else can see them.
613 my ($hub, $event) = @_;
615 return $event; # No Changes
616 return; # Remove the event
618 # Or you can modify an event before returning it.
624 If you are not using threads, forking, or IPC then the only difference between
625 a C<filter> and a C<pre_filter> is that C<pre_filter> subs run first. When you
626 are using threads, forking, or IPC, pre_filters happen to events before they
627 are sent to their destination proc/thread, ordinary filters happen only in the
628 destination hub/thread.
630 You cannot add a regular filter to a hub if the hub was created in another
631 process or thread. You can always add a pre_filter.
633 =item $hub->unfilter($sub)
635 =item $hub->pre_unfilter($sub)
637 These can be used to remove filters and pre_filters. The C<$sub> argument is
638 the reference returned by C<filter()> or C<pre_filter()>.
640 =item $hub->follow_op(sub { ... })
642 Use this to add behaviors that are called just before the hub is finalized. The
643 only argument to your codeblock will be a L<Test2::Util::Trace> instance.
645 $hub->follow_up(sub {
646 my ($trace, $hub) = @_;
648 ... do whatever you need to ...
653 follow_up subs are called only once, ether when done_testing is called, or in
656 =item $sub = $hub->add_context_acquire(sub { ... });
658 Add a callback that will be called every time someone tries to acquire a
659 context. It gets a single argument, a reference of the hash of parameters
660 being used the construct the context. This is your chance to change the
661 parameters by directly altering the hash.
663 test2_add_callback_context_acquire(sub {
668 This is a very scary API function. Please do not use this unless you need to.
669 This is here for L<Test::Builder> and backwards compatibility. This has you
670 directly manipulate the hash instead of returning a new one for performance
673 B<Note> Using this hook could have a huge performance impact.
675 The coderef you provide is returned and can be used to remove the hook later.
677 =item $hub->remove_context_acquire($sub);
679 This can be used to remove a context acquire hook.
681 =item $sub = $hub->add_context_init(sub { ... });
683 This allows you to add callbacks that will trigger every time a new context is
684 created for the hub. The only argument to the sub will be the
685 L<Test2::API::Context> instance that was created.
687 B<Note> Using this hook could have a huge performance impact.
689 The coderef you provide is returned and can be used to remove the hook later.
691 =item $hub->remove_context_init($sub);
693 This can be used to remove a context init hook.
695 =item $sub = $hub->add_context_release(sub { ... });
697 This allows you to add callbacks that will trigger every time a context for
698 this hub is released. The only argument to the sub will be the
699 L<Test2::API::Context> instance that was released. These will run in reverse
702 B<Note> Using this hook could have a huge performance impact.
704 The coderef you provide is returned and can be used to remove the hook later.
706 =item $hub->remove_context_release($sub);
708 This can be used to remove a context release hook.
712 Cull any IPC events (and process them).
714 =item $pid = $hub->pid()
716 Get the process id under which the hub was created.
718 =item $tid = $hub->tid()
720 Get the thread id under which the hub was created.
722 =item $hud = $hub->hid()
724 Get the identifier string of the hub.
726 =item $ipc = $hub->ipc()
728 Get the IPC object used by the hub.
730 =item $hub->set_no_ending($bool)
732 =item $bool = $hub->no_ending
734 This can be used to disable auto-ending behavior for a hub. The auto-ending
735 behavior is triggered by an end block and is used to cull IPC events, and
736 output the final plan if the plan was 'no_plan'.
738 =item $bool = $hub->active
740 =item $hub->set_active($bool)
742 These are used to get/set the 'active' attribute. When true this attribute will
743 force C<< hub->finalize() >> to take action even if there is no plan, and no
744 tests have been run. This flag is useful for plugins that add follow-up
745 behaviors that need to run even if no events are seen.
753 =item $hub->reset_state()
755 Reset all state to the start. This sets the test count to 0, clears the plan,
756 removes the failures, etc.
758 =item $num = $hub->count
760 Get the number of tests that have been run.
762 =item $num = $hub->failed
764 Get the number of failures (Not all failures come from a test fail, so this
765 number can be larger than the count).
767 =item $bool = $hub->ended
769 True if the testing has ended. This MAY return the stack frame of the tool that
770 ended the test, but that is not guaranteed.
772 =item $bool = $hub->is_passing
774 =item $hub->is_passing($bool)
776 Check if the overall test run is a failure. Can also be used to set the
779 =item $hub->plan($plan)
781 =item $plan = $hub->plan
783 Get or set the plan. The plan must be an integer larger than 0, the string
784 'no_plan', or the string 'skip_all'.
786 =item $bool = $hub->check_plan
788 Check if the plan and counts match, but only if the tests have ended. If tests
789 have not ended this will return undef, otherwise it will be a true/false.
793 =head1 THIRD PARTY META-DATA
795 This object consumes L<Test2::Util::ExternalMeta> which provides a consistent
796 way for you to attach meta-data to instances of this class. This is useful for
797 tools, plugins, and other extensions.
801 The source code repository for Test2 can be found at
802 F<http://github.com/Test-More/test-more/>.
808 =item Chad Granum E<lt>exodist@cpan.orgE<gt>
816 =item Chad Granum E<lt>exodist@cpan.orgE<gt>
822 Copyright 2016 Chad Granum E<lt>exodist@cpan.orgE<gt>.
824 This program is free software; you can redistribute it and/or
825 modify it under the same terms as Perl itself.
827 See F<http://dev.perl.org/licenses/>