5 our $VERSION = '1.302173';
8 use Carp qw/carp croak confess/;
9 use Test2::Util qw/get_tid gen_uid/;
11 use Scalar::Util qw/weaken/;
12 use List::Util qw/first/;
14 use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/;
15 use Test2::Util::HashBase qw{
45 $self->{+TID} = get_tid();
46 $self->{+HID} = gen_uid();
48 $UUID_VIA ||= Test2::API::_add_uuid_via_ref();
49 $self->{+UUID} = ${$UUID_VIA}->('hub') if $$UUID_VIA;
51 $self->{+NESTED} = 0 unless defined $self->{+NESTED};
52 $self->{+BUFFERED} = 0 unless defined $self->{+BUFFERED};
56 $self->{+_PASSING} = 1;
58 if (my $formatter = delete $self->{formatter}) {
59 $self->format($formatter);
62 if (my $ipc = $self->{+IPC}) {
63 $ipc->add_hub($self->{+HID});
73 return if $self->{+PID} == $$ && $self->{+TID} == get_tid();
76 $self->{+TID} = get_tid();
77 $self->{+HID} = gen_uid();
79 if (my $ipc = $self->{+IPC}) {
80 $ipc->add_hub($self->{+HID});
89 $self->{+_PASSING} = 1;
91 delete $self->{+_PLAN};
92 delete $self->{+ENDED};
93 delete $self->{+BAILED_OUT};
94 delete $self->{+SKIP_REASON};
99 my ($from, %params) = @_;
101 $self->{+NESTED} ||= 0;
103 $self->{+_FORMATTER} = $from->{+_FORMATTER}
104 unless $self->{+_FORMATTER} || exists($params{formatter});
106 if ($from->{+IPC} && !$self->{+IPC} && !exists($params{ipc})) {
107 my $ipc = $from->{+IPC};
108 $self->{+IPC} = $ipc;
109 $ipc->add_hub($self->{+HID});
112 if (my $ls = $from->{+_LISTENERS}) {
113 push @{$self->{+_LISTENERS}} => grep { $_->{inherit} } @$ls;
116 if (my $pfs = $from->{+_PRE_FILTERS}) {
117 push @{$self->{+_PRE_FILTERS}} => grep { $_->{inherit} } @$pfs;
120 if (my $fs = $from->{+_FILTERS}) {
121 push @{$self->{+_FILTERS}} => grep { $_->{inherit} } @$fs;
128 my $old = $self->{+_FORMATTER};
129 ($self->{+_FORMATTER}) = @_ if @_;
136 return $$ == $self->{+PID}
137 && get_tid() == $self->{+TID};
142 my ($sub, %params) = @_;
144 carp "Useless addition of a listener in a child process or thread!"
145 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
147 croak "listen only takes coderefs for arguments, got '$sub'"
148 unless ref $sub && ref $sub eq 'CODE';
150 push @{$self->{+_LISTENERS}} => { %params, code => $sub };
152 $sub; # Intentional return.
158 carp "Useless removal of a listener in a child process or thread!"
159 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
161 my %subs = map {$_ => $_} @_;
163 @{$self->{+_LISTENERS}} = grep { !$subs{$_->{code}} } @{$self->{+_LISTENERS}};
168 my ($sub, %params) = @_;
170 carp "Useless addition of a filter in a child process or thread!"
171 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
173 croak "filter only takes coderefs for arguments, got '$sub'"
174 unless ref $sub && ref $sub eq 'CODE';
176 push @{$self->{+_FILTERS}} => { %params, code => $sub };
178 $sub; # Intentional Return
183 carp "Useless removal of a filter in a child process or thread!"
184 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
185 my %subs = map {$_ => $_} @_;
186 @{$self->{+_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_FILTERS}};
191 my ($sub, %params) = @_;
193 croak "pre_filter only takes coderefs for arguments, got '$sub'"
194 unless ref $sub && ref $sub eq 'CODE';
196 push @{$self->{+_PRE_FILTERS}} => { %params, code => $sub };
198 $sub; # Intentional Return
203 my %subs = map {$_ => $_} @_;
204 @{$self->{+_PRE_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_PRE_FILTERS}};
211 carp "Useless addition of a follow-up in a child process or thread!"
212 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
214 croak "follow_up only takes coderefs for arguments, got '$sub'"
215 unless ref $sub && ref $sub eq 'CODE';
217 push @{$self->{+_FOLLOW_UPS}} => $sub;
220 *add_context_aquire = \&add_context_acquire;
221 sub add_context_acquire {
225 croak "add_context_acquire only takes coderefs for arguments, got '$sub'"
226 unless ref $sub && ref $sub eq 'CODE';
228 push @{$self->{+_CONTEXT_ACQUIRE}} => $sub;
230 $sub; # Intentional return.
233 *remove_context_aquire = \&remove_context_acquire;
234 sub remove_context_acquire {
236 my %subs = map {$_ => $_} @_;
237 @{$self->{+_CONTEXT_ACQUIRE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_ACQUIRE}};
240 sub add_context_init {
244 croak "add_context_init only takes coderefs for arguments, got '$sub'"
245 unless ref $sub && ref $sub eq 'CODE';
247 push @{$self->{+_CONTEXT_INIT}} => $sub;
249 $sub; # Intentional return.
252 sub remove_context_init {
254 my %subs = map {$_ => $_} @_;
255 @{$self->{+_CONTEXT_INIT}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_INIT}};
258 sub add_context_release {
262 croak "add_context_release only takes coderefs for arguments, got '$sub'"
263 unless ref $sub && ref $sub eq 'CODE';
265 push @{$self->{+_CONTEXT_RELEASE}} => $sub;
267 $sub; # Intentional return.
270 sub remove_context_release {
272 my %subs = map {$_ => $_} @_;
273 @{$self->{+_CONTEXT_RELEASE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_RELEASE}};
284 details => ref($self),
286 buffered => $self->{+BUFFERED},
287 hid => $self->{+HID},
288 nested => $self->{+NESTED},
289 pid => $self->{+PID},
290 tid => $self->{+TID},
291 uuid => $self->{+UUID},
293 ipc => $self->{+IPC} ? 1 : 0,
297 $e->set_uuid(${$UUID_VIA}->('event')) if $$UUID_VIA;
299 if ($self->{+_PRE_FILTERS}) {
300 for (@{$self->{+_PRE_FILTERS}}) {
301 $e = $_->{code}->($self, $e);
306 my $ipc = $self->{+IPC} || return $self->process($e);
309 $ipc->send($self->{+HID}, $e, 'GLOBAL');
310 return $self->process($e);
313 return $ipc->send($self->{+HID}, $e)
314 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
323 if ($self->{+_FILTERS}) {
324 for (@{$self->{+_FILTERS}}) {
325 $e = $_->{code}->($self, $e);
330 # Optimize the most common case
332 if ($type eq 'Test2::Event::Pass' || ($type eq 'Test2::Event::Ok' && $e->{pass})) {
333 my $count = ++($self->{+COUNT});
334 $self->{+_FORMATTER}->write($e, $count) if $self->{+_FORMATTER};
336 if ($self->{+_LISTENERS}) {
337 $_->{code}->($self, $e, $count) for @{$self->{+_LISTENERS}};
343 my $f = $e->facet_data;
346 $fail = 1 if $f->{assert} && !$f->{assert}->{pass};
347 $fail = 1 if $f->{errors} && grep { $_->{fail} } @{$f->{errors}};
348 $fail = 0 if $f->{amnesty};
350 $self->{+COUNT}++ if $f->{assert};
351 $self->{+FAILED}++ if $fail && $f->{assert};
352 $self->{+_PASSING} = 0 if $fail;
354 my $code = $f->{control}->{terminate};
355 my $count = $self->{+COUNT};
357 if (my $plan = $f->{plan}) {
360 $self->set_skip_reason($plan->{details} || 1);
363 elsif ($plan->{none}) {
364 $self->plan('NO PLAN');
367 $self->plan($plan->{count});
371 $e->callback($self) if $f->{control}->{has_callback};
373 $self->{+_FORMATTER}->write($e, $count, $f) if $self->{+_FORMATTER};
375 if ($self->{+_LISTENERS}) {
376 $_->{code}->($self, $e, $count, $f) for @{$self->{+_LISTENERS}};
379 if ($f->{control}->{halt}) {
381 $self->set_bailed_out($e);
385 $self->{+_FORMATTER}->terminate($e, $f) if $self->{+_FORMATTER};
386 $self->terminate($code, $e, $f);
401 my $ipc = $self->{+IPC} || return;
402 return if $self->{+PID} != $$ || $self->{+TID} != get_tid();
404 # No need to do IPC checks on culled events
405 $self->process($_) for $ipc->cull($self->{+HID});
410 my ($trace, $do_plan) = @_;
414 my $plan = $self->{+_PLAN};
415 my $count = $self->{+COUNT};
416 my $failed = $self->{+FAILED};
417 my $active = $self->{+ACTIVE};
419 # return if NOTHING was done.
420 unless ($active || $do_plan || defined($plan) || $count || $failed) {
421 $self->{+_FORMATTER}->finalize($plan, $count, $failed, 0, $self->is_subtest) if $self->{+_FORMATTER};
425 unless ($self->{+ENDED}) {
426 if ($self->{+_FOLLOW_UPS}) {
427 $_->($trace, $self) for reverse @{$self->{+_FOLLOW_UPS}};
430 # These need to be refreshed now
431 $plan = $self->{+_PLAN};
432 $count = $self->{+COUNT};
433 $failed = $self->{+FAILED};
435 if (($plan && $plan eq 'NO PLAN') || ($do_plan && !$plan)) {
437 Test2::Event::Plan->new(
443 $plan = $self->{+_PLAN};
446 my $frame = $trace->frame;
447 if($self->{+ENDED}) {
448 my (undef, $ffile, $fline) = @{$self->{+ENDED}};
449 my (undef, $sfile, $sline) = @$frame;
453 First End: $ffile line $fline
454 Second End: $sfile line $sline
458 $self->{+ENDED} = $frame;
459 my $pass = $self->is_passing(); # Generate the final boolean.
461 $self->{+_FORMATTER}->finalize($plan, $count, $failed, $pass, $self->is_subtest) if $self->{+_FORMATTER};
469 ($self->{+_PASSING}) = @_ if @_;
471 # If we already failed just return 0.
472 my $pass = $self->{+_PASSING} or return 0;
473 return $self->{+_PASSING} = 0 if $self->{+FAILED};
475 my $count = $self->{+COUNT};
476 my $ended = $self->{+ENDED};
477 my $plan = $self->{+_PLAN};
479 return $pass if !$count && $plan && $plan =~ m/^SKIP$/;
481 return $self->{+_PASSING} = 0
482 if $ended && (!$count || !$plan);
484 return $pass unless $plan && $plan =~ m/^\d+$/;
487 return $self->{+_PASSING} = 0 if $count != $plan;
490 return $self->{+_PASSING} = 0 if $count > $plan;
499 return $self->{+_PLAN} unless @_;
503 confess "You cannot unset the plan"
504 unless defined $plan;
506 confess "You cannot change the plan"
507 if $self->{+_PLAN} && $self->{+_PLAN} !~ m/^NO PLAN$/;
509 confess "'$plan' is not a valid plan! Plan must be an integer greater than 0, 'NO PLAN', or 'SKIP'"
510 unless $plan =~ m/^(\d+|NO PLAN|SKIP)$/;
512 $self->{+_PLAN} = $plan;
518 return undef unless $self->{+ENDED};
519 my $plan = $self->{+_PLAN} || return undef;
521 return 1 if $plan !~ m/^\d+$/;
523 return 1 if $plan == $self->{+COUNT};
529 my $ipc = $self->{+IPC} || return;
530 return unless $$ == $self->{+PID};
531 return unless get_tid() == $self->{+TID};
532 $ipc->drop_hub($self->{+HID});
545 Test2::Hub - The conduit through which all events flow.
551 my $hub = Test2::Hub->new();
556 The hub is the place where all events get processed and handed off to the
557 formatter. The hub also tracks test state, and provides several hooks into the
562 =head2 SENDING EVENTS
566 The C<send()> method is used to issue an event to the hub. This method will
567 handle thread/fork sync, filters, listeners, TAP output, etc.
569 =head2 ALTERING OR REMOVING EVENTS
571 You can use either C<filter()> or C<pre_filter()>, depending on your
572 needs. Both have identical syntax, so only C<filter()> is shown here.
575 my ($hub, $event) = @_;
577 my $action = get_action($event);
579 # No action should be taken
580 return $event if $action eq 'none';
582 # You want your filter to remove the event
583 return undef if $action eq 'delete';
585 if ($action eq 'do_it') {
586 my $new_event = copy_event($event);
587 ... Change your copy of the event ...
591 die "Should not happen";
594 By default, filters are not inherited by child hubs. That means if you start a
595 subtest, the subtest will not inherit the filter. You can change this behavior
596 with the C<inherit> parameter:
598 $hub->filter(sub { ... }, inherit => 1);
600 =head2 LISTENING FOR EVENTS
603 my ($hub, $event, $number) = @_;
605 ... do whatever you want with the event ...
610 By default listeners are not inherited by child hubs. That means if you start a
611 subtest, the subtest will not inherit the listener. You can change this behavior
612 with the C<inherit> parameter:
614 $hub->listen(sub { ... }, inherit => 1);
617 =head2 POST-TEST BEHAVIORS
619 $hub->follow_up(sub {
620 my ($trace, $hub) = @_;
622 ... do whatever you need to ...
627 follow_up subs are called only once, either when done_testing is called, or in
630 =head2 SETTING THE FORMATTER
632 By default an instance of L<Test2::Formatter::TAP> is created and used.
634 my $old = $hub->format(My::Formatter->new);
636 Setting the formatter will REPLACE any existing formatter. You may set the
637 formatter to undef to prevent output. The old formatter will be returned if one
638 was already set. Only one formatter is allowed at a time.
644 =item $hub->send($event)
646 This is where all events enter the hub for processing.
648 =item $hub->process($event)
650 This is called by send after it does any IPC handling. You can use this to
651 bypass the IPC process, but in general you should avoid using this.
653 =item $old = $hub->format($formatter)
655 Replace the existing formatter instance with a new one. Formatters must be
656 objects that implement a C<< $formatter->write($event) >> method.
658 =item $sub = $hub->listen(sub { ... }, %optional_params)
660 You can use this to record all events AFTER they have been sent to the
661 formatter. No changes made here will be meaningful, except possibly to other
665 my ($hub, $event, $number) = @_;
667 ... do whatever you want with the event ...
672 Normally listeners are not inherited by child hubs such as subtests. You can
673 add the C<< inherit => 1 >> parameter to allow a listener to be inherited.
675 =item $hub->unlisten($sub)
677 You can use this to remove a listen callback. You must pass in the coderef
678 returned by the C<listen()> method.
680 =item $sub = $hub->filter(sub { ... }, %optional_params)
682 =item $sub = $hub->pre_filter(sub { ... }, %optional_params)
684 These can be used to add filters. Filters can modify, replace, or remove events
685 before anything else can see them.
689 my ($hub, $event) = @_;
691 return $event; # No Changes
692 return; # Remove the event
694 # Or you can modify an event before returning it.
700 If you are not using threads, forking, or IPC then the only difference between
701 a C<filter> and a C<pre_filter> is that C<pre_filter> subs run first. When you
702 are using threads, forking, or IPC, pre_filters happen to events before they
703 are sent to their destination proc/thread, ordinary filters happen only in the
704 destination hub/thread.
706 You cannot add a regular filter to a hub if the hub was created in another
707 process or thread. You can always add a pre_filter.
709 =item $hub->unfilter($sub)
711 =item $hub->pre_unfilter($sub)
713 These can be used to remove filters and pre_filters. The C<$sub> argument is
714 the reference returned by C<filter()> or C<pre_filter()>.
716 =item $hub->follow_op(sub { ... })
718 Use this to add behaviors that are called just before the hub is finalized. The
719 only argument to your codeblock will be a L<Test2::EventFacet::Trace> instance.
721 $hub->follow_up(sub {
722 my ($trace, $hub) = @_;
724 ... do whatever you need to ...
729 follow_up subs are called only once, ether when done_testing is called, or in
732 =item $sub = $hub->add_context_acquire(sub { ... });
734 Add a callback that will be called every time someone tries to acquire a
735 context. It gets a single argument, a reference of the hash of parameters
736 being used the construct the context. This is your chance to change the
737 parameters by directly altering the hash.
739 test2_add_callback_context_acquire(sub {
744 This is a very scary API function. Please do not use this unless you need to.
745 This is here for L<Test::Builder> and backwards compatibility. This has you
746 directly manipulate the hash instead of returning a new one for performance
749 B<Note> Using this hook could have a huge performance impact.
751 The coderef you provide is returned and can be used to remove the hook later.
753 =item $hub->remove_context_acquire($sub);
755 This can be used to remove a context acquire hook.
757 =item $sub = $hub->add_context_init(sub { ... });
759 This allows you to add callbacks that will trigger every time a new context is
760 created for the hub. The only argument to the sub will be the
761 L<Test2::API::Context> instance that was created.
763 B<Note> Using this hook could have a huge performance impact.
765 The coderef you provide is returned and can be used to remove the hook later.
767 =item $hub->remove_context_init($sub);
769 This can be used to remove a context init hook.
771 =item $sub = $hub->add_context_release(sub { ... });
773 This allows you to add callbacks that will trigger every time a context for
774 this hub is released. The only argument to the sub will be the
775 L<Test2::API::Context> instance that was released. These will run in reverse
778 B<Note> Using this hook could have a huge performance impact.
780 The coderef you provide is returned and can be used to remove the hook later.
782 =item $hub->remove_context_release($sub);
784 This can be used to remove a context release hook.
788 Cull any IPC events (and process them).
790 =item $pid = $hub->pid()
792 Get the process id under which the hub was created.
794 =item $tid = $hub->tid()
796 Get the thread id under which the hub was created.
798 =item $hud = $hub->hid()
800 Get the identifier string of the hub.
802 =item $uuid = $hub->uuid()
804 If UUID tagging is enabled (see L<Test2::API>) then the hub will have a UUID.
806 =item $ipc = $hub->ipc()
808 Get the IPC object used by the hub.
810 =item $hub->set_no_ending($bool)
812 =item $bool = $hub->no_ending
814 This can be used to disable auto-ending behavior for a hub. The auto-ending
815 behavior is triggered by an end block and is used to cull IPC events, and
816 output the final plan if the plan was 'no_plan'.
818 =item $bool = $hub->active
820 =item $hub->set_active($bool)
822 These are used to get/set the 'active' attribute. When true this attribute will
823 force C<< hub->finalize() >> to take action even if there is no plan, and no
824 tests have been run. This flag is useful for plugins that add follow-up
825 behaviors that need to run even if no events are seen.
833 =item $hub->reset_state()
835 Reset all state to the start. This sets the test count to 0, clears the plan,
836 removes the failures, etc.
838 =item $num = $hub->count
840 Get the number of tests that have been run.
842 =item $num = $hub->failed
844 Get the number of failures (Not all failures come from a test fail, so this
845 number can be larger than the count).
847 =item $bool = $hub->ended
849 True if the testing has ended. This MAY return the stack frame of the tool that
850 ended the test, but that is not guaranteed.
852 =item $bool = $hub->is_passing
854 =item $hub->is_passing($bool)
856 Check if the overall test run is a failure. Can also be used to set the
859 =item $hub->plan($plan)
861 =item $plan = $hub->plan
863 Get or set the plan. The plan must be an integer larger than 0, the string
864 'no_plan', or the string 'skip_all'.
866 =item $bool = $hub->check_plan
868 Check if the plan and counts match, but only if the tests have ended. If tests
869 have not ended this will return undef, otherwise it will be a true/false.
873 =head1 THIRD PARTY META-DATA
875 This object consumes L<Test2::Util::ExternalMeta> which provides a consistent
876 way for you to attach meta-data to instances of this class. This is useful for
877 tools, plugins, and other extensions.
881 The source code repository for Test2 can be found at
882 F<http://github.com/Test-More/test-more/>.
888 =item Chad Granum E<lt>exodist@cpan.orgE<gt>
896 =item Chad Granum E<lt>exodist@cpan.orgE<gt>
902 Copyright 2019 Chad Granum E<lt>exodist@cpan.orgE<gt>.
904 This program is free software; you can redistribute it and/or
905 modify it under the same terms as Perl itself.
907 See F<http://dev.perl.org/licenses/>