| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Test2::Hub; | 
| 2 | 246 |  |  | 246 |  | 3958 | use strict; | 
|  | 246 |  |  |  |  | 500 |  | 
|  | 246 |  |  |  |  | 7888 |  | 
| 3 | 246 |  |  | 246 |  | 1641 | use warnings; | 
|  | 246 |  |  |  |  | 461 |  | 
|  | 246 |  |  |  |  | 11108 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | our $VERSION = '1.302182'; | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 246 |  |  | 246 |  | 1455 | use Carp qw/carp croak confess/; | 
|  | 246 |  |  |  |  | 520 |  | 
|  | 246 |  |  |  |  | 15686 |  | 
| 9 | 246 |  |  | 246 |  | 2094 | use Test2::Util qw/get_tid gen_uid/; | 
|  | 246 |  |  |  |  | 574 |  | 
|  | 246 |  |  |  |  | 13326 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 | 246 |  |  | 246 |  | 1665 | use Scalar::Util qw/weaken/; | 
|  | 246 |  |  |  |  | 496 |  | 
|  | 246 |  |  |  |  | 12518 |  | 
| 12 | 246 |  |  | 246 |  | 1594 | use List::Util qw/first/; | 
|  | 246 |  |  |  |  | 637 |  | 
|  | 246 |  |  |  |  | 28338 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 | 246 |  |  | 246 |  | 102059 | use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/; | 
|  | 246 |  |  |  |  | 598 |  | 
|  | 246 |  |  |  |  | 19809 |  | 
| 15 | 246 |  |  |  |  | 1513 | use Test2::Util::HashBase qw{ | 
| 16 |  |  |  |  |  |  | pid tid hid ipc | 
| 17 |  |  |  |  |  |  | nested buffered | 
| 18 |  |  |  |  |  |  | no_ending | 
| 19 |  |  |  |  |  |  | _filters | 
| 20 |  |  |  |  |  |  | _pre_filters | 
| 21 |  |  |  |  |  |  | _listeners | 
| 22 |  |  |  |  |  |  | _follow_ups | 
| 23 |  |  |  |  |  |  | _formatter | 
| 24 |  |  |  |  |  |  | _context_acquire | 
| 25 |  |  |  |  |  |  | _context_init | 
| 26 |  |  |  |  |  |  | _context_release | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | uuid | 
| 29 |  |  |  |  |  |  | active | 
| 30 |  |  |  |  |  |  | count | 
| 31 |  |  |  |  |  |  | failed | 
| 32 |  |  |  |  |  |  | ended | 
| 33 |  |  |  |  |  |  | bailed_out | 
| 34 |  |  |  |  |  |  | _passing | 
| 35 |  |  |  |  |  |  | _plan | 
| 36 |  |  |  |  |  |  | skip_reason | 
| 37 | 246 |  |  | 246 |  | 2098 | }; | 
|  | 246 |  |  |  |  | 479 |  | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | my $UUID_VIA; | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | sub init { | 
| 42 | 729 |  |  | 729 | 0 | 1545 | my $self = shift; | 
| 43 |  |  |  |  |  |  |  | 
| 44 | 729 |  |  |  |  | 3497 | $self->{+PID} = $$; | 
| 45 | 729 |  |  |  |  | 1960 | $self->{+TID} = get_tid(); | 
| 46 | 729 |  |  |  |  | 4025 | $self->{+HID} = gen_uid(); | 
| 47 |  |  |  |  |  |  |  | 
| 48 | 729 |  | 66 |  |  | 3683 | $UUID_VIA ||= Test2::API::_add_uuid_via_ref(); | 
| 49 | 729 | 100 |  |  |  | 2313 | $self->{+UUID} = ${$UUID_VIA}->('hub') if $$UUID_VIA; | 
|  | 4 |  |  |  |  | 10 |  | 
| 50 |  |  |  |  |  |  |  | 
| 51 | 729 | 100 |  |  |  | 2895 | $self->{+NESTED}   = 0 unless defined $self->{+NESTED}; | 
| 52 | 729 | 100 |  |  |  | 2527 | $self->{+BUFFERED} = 0 unless defined $self->{+BUFFERED}; | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 729 |  |  |  |  | 1806 | $self->{+COUNT}    = 0; | 
| 55 | 729 |  |  |  |  | 1628 | $self->{+FAILED}   = 0; | 
| 56 | 729 |  |  |  |  | 2142 | $self->{+_PASSING} = 1; | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 729 | 100 |  |  |  | 2373 | if (my $formatter = delete $self->{formatter}) { | 
| 59 | 52 |  |  |  |  | 218 | $self->format($formatter); | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 729 | 100 |  |  |  | 2807 | if (my $ipc = $self->{+IPC}) { | 
| 63 | 15 |  |  |  |  | 63 | $ipc->add_hub($self->{+HID}); | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 235 |  |  | 235 | 0 | 2845 | sub is_subtest { 0 } | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | sub _tb_reset { | 
| 70 | 55 |  |  | 55 |  | 164 | my $self = shift; | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | # Nothing to do | 
| 73 | 55 | 100 | 66 |  |  | 503 | return if $self->{+PID} == $$ && $self->{+TID} == get_tid(); | 
| 74 |  |  |  |  |  |  |  | 
| 75 | 1 |  |  |  |  | 32 | $self->{+PID} = $$; | 
| 76 | 1 |  |  |  |  | 22 | $self->{+TID} = get_tid(); | 
| 77 | 1 |  |  |  |  | 25 | $self->{+HID} = gen_uid(); | 
| 78 |  |  |  |  |  |  |  | 
| 79 | 1 | 50 |  |  |  | 32 | if (my $ipc = $self->{+IPC}) { | 
| 80 | 0 |  |  |  |  | 0 | $ipc->add_hub($self->{+HID}); | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | sub reset_state { | 
| 85 | 58 |  |  | 58 | 1 | 169 | my $self = shift; | 
| 86 |  |  |  |  |  |  |  | 
| 87 | 58 |  |  |  |  | 160 | $self->{+COUNT} = 0; | 
| 88 | 58 |  |  |  |  | 133 | $self->{+FAILED} = 0; | 
| 89 | 58 |  |  |  |  | 177 | $self->{+_PASSING} = 1; | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 58 |  |  |  |  | 151 | delete $self->{+_PLAN}; | 
| 92 | 58 |  |  |  |  | 121 | delete $self->{+ENDED}; | 
| 93 | 58 |  |  |  |  | 114 | delete $self->{+BAILED_OUT}; | 
| 94 | 58 |  |  |  |  | 150 | delete $self->{+SKIP_REASON}; | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | sub inherit { | 
| 98 | 292 |  |  | 292 | 0 | 551 | my $self = shift; | 
| 99 | 292 |  |  |  |  | 632 | my ($from, %params) = @_; | 
| 100 |  |  |  |  |  |  |  | 
| 101 | 292 |  | 50 |  |  | 1540 | $self->{+NESTED} ||= 0; | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | $self->{+_FORMATTER} = $from->{+_FORMATTER} | 
| 104 | 292 | 100 | 66 |  |  | 1558 | unless $self->{+_FORMATTER} || exists($params{formatter}); | 
| 105 |  |  |  |  |  |  |  | 
| 106 | 292 | 100 | 66 |  |  | 1097 | if ($from->{+IPC} && !$self->{+IPC} && !exists($params{ipc})) { | 
|  |  |  | 100 |  |  |  |  | 
| 107 | 24 |  |  |  |  | 55 | my $ipc = $from->{+IPC}; | 
| 108 | 24 |  |  |  |  | 55 | $self->{+IPC} = $ipc; | 
| 109 | 24 |  |  |  |  | 103 | $ipc->add_hub($self->{+HID}); | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 292 | 100 |  |  |  | 907 | if (my $ls = $from->{+_LISTENERS}) { | 
| 113 | 53 |  |  |  |  | 91 | push @{$self->{+_LISTENERS}} => grep { $_->{inherit} } @$ls; | 
|  | 53 |  |  |  |  | 229 |  | 
|  | 55 |  |  |  |  | 200 |  | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  |  | 
| 116 | 292 | 100 |  |  |  | 803 | if (my $pfs = $from->{+_PRE_FILTERS}) { | 
| 117 | 173 |  |  |  |  | 251 | push @{$self->{+_PRE_FILTERS}} => grep { $_->{inherit} } @$pfs; | 
|  | 173 |  |  |  |  | 519 |  | 
|  | 253 |  |  |  |  | 665 |  | 
| 118 |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  |  | 
| 120 | 292 | 100 |  |  |  | 1150 | if (my $fs = $from->{+_FILTERS}) { | 
| 121 | 12 |  |  |  |  | 21 | push @{$self->{+_FILTERS}} => grep { $_->{inherit} } @$fs; | 
|  | 12 |  |  |  |  | 48 |  | 
|  | 6 |  |  |  |  | 30 |  | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | sub format { | 
| 126 | 3485 |  |  | 3485 | 1 | 6068 | my $self = shift; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 3485 |  |  |  |  | 5972 | my $old = $self->{+_FORMATTER}; | 
| 129 | 3485 | 100 |  |  |  | 8405 | ($self->{+_FORMATTER}) = @_ if @_; | 
| 130 |  |  |  |  |  |  |  | 
| 131 | 3485 |  |  |  |  | 9984 | return $old; | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | sub is_local { | 
| 135 | 127 |  |  | 127 | 0 | 256 | my $self = shift; | 
| 136 |  |  |  |  |  |  | return $$ == $self->{+PID} | 
| 137 | 127 |  | 66 |  |  | 1081 | && get_tid() == $self->{+TID}; | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub listen { | 
| 141 | 343 |  |  | 343 | 1 | 644 | my $self = shift; | 
| 142 | 343 |  |  |  |  | 836 | my ($sub, %params) = @_; | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | carp "Useless addition of a listener in a child process or thread!" | 
| 145 | 343 | 50 | 33 |  |  | 1973 | if $$ != $self->{+PID} || get_tid() != $self->{+TID}; | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 343 | 100 | 66 |  |  | 2017 | croak "listen only takes coderefs for arguments, got '$sub'" | 
| 148 |  |  |  |  |  |  | unless ref $sub && ref $sub eq 'CODE'; | 
| 149 |  |  |  |  |  |  |  | 
| 150 | 342 |  |  |  |  | 586 | push @{$self->{+_LISTENERS}} => { %params, code => $sub }; | 
|  | 342 |  |  |  |  | 1492 |  | 
| 151 |  |  |  |  |  |  |  | 
| 152 | 342 |  |  |  |  | 915 | $sub; # Intentional return. | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | sub unlisten { | 
| 156 | 1 |  |  | 1 | 1 | 8 | my $self = shift; | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | carp "Useless removal of a listener in a child process or thread!" | 
| 159 | 1 | 50 | 33 |  |  | 23 | if $$ != $self->{+PID} || get_tid() != $self->{+TID}; | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 1 |  |  |  |  | 5 | my %subs = map {$_ => $_} @_; | 
|  | 1 |  |  |  |  | 10 |  | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 1 |  |  |  |  | 4 | @{$self->{+_LISTENERS}} = grep { !$subs{$_->{code}} } @{$self->{+_LISTENERS}}; | 
|  | 1 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 8 |  | 
|  | 1 |  |  |  |  | 8 |  | 
| 164 |  |  |  |  |  |  | } | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | sub filter { | 
| 167 | 11 |  |  | 11 | 1 | 77 | my $self = shift; | 
| 168 | 11 |  |  |  |  | 51 | my ($sub, %params) = @_; | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | carp "Useless addition of a filter in a child process or thread!" | 
| 171 | 11 | 50 | 33 |  |  | 115 | if $$ != $self->{+PID} || get_tid() != $self->{+TID}; | 
| 172 |  |  |  |  |  |  |  | 
| 173 | 11 | 100 | 66 |  |  | 192 | croak "filter only takes coderefs for arguments, got '$sub'" | 
| 174 |  |  |  |  |  |  | unless ref $sub && ref $sub eq 'CODE'; | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 10 |  |  |  |  | 18 | push @{$self->{+_FILTERS}} => { %params, code => $sub }; | 
|  | 10 |  |  |  |  | 67 |  | 
| 177 |  |  |  |  |  |  |  | 
| 178 | 10 |  |  |  |  | 52 | $sub; # Intentional Return | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | sub unfilter { | 
| 182 | 2 |  |  | 2 | 1 | 13 | my $self = shift; | 
| 183 |  |  |  |  |  |  | carp "Useless removal of a filter in a child process or thread!" | 
| 184 | 2 | 50 | 33 |  |  | 30 | if $$ != $self->{+PID} || get_tid() != $self->{+TID}; | 
| 185 | 2 |  |  |  |  | 11 | my %subs = map {$_ => $_} @_; | 
|  | 2 |  |  |  |  | 15 |  | 
| 186 | 2 |  |  |  |  | 8 | @{$self->{+_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_FILTERS}}; | 
|  | 2 |  |  |  |  | 15 |  | 
|  | 3 |  |  |  |  | 21 |  | 
|  | 2 |  |  |  |  | 12 |  | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | sub pre_filter { | 
| 190 | 482 |  |  | 482 | 1 | 1258 | my $self = shift; | 
| 191 | 482 |  |  |  |  | 1729 | my ($sub, %params) = @_; | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 482 | 100 | 66 |  |  | 3110 | croak "pre_filter only takes coderefs for arguments, got '$sub'" | 
| 194 |  |  |  |  |  |  | unless ref $sub && ref $sub eq 'CODE'; | 
| 195 |  |  |  |  |  |  |  | 
| 196 | 481 |  |  |  |  | 1065 | push @{$self->{+_PRE_FILTERS}} => { %params, code => $sub }; | 
|  | 481 |  |  |  |  | 2776 |  | 
| 197 |  |  |  |  |  |  |  | 
| 198 | 481 |  |  |  |  | 2059 | $sub; # Intentional Return | 
| 199 |  |  |  |  |  |  | } | 
| 200 |  |  |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | sub pre_unfilter { | 
| 202 | 93 |  |  | 93 | 1 | 167 | my $self = shift; | 
| 203 | 93 |  |  |  |  | 229 | my %subs = map {$_ => $_} @_; | 
|  | 93 |  |  |  |  | 421 |  | 
| 204 | 93 |  |  |  |  | 171 | @{$self->{+_PRE_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_PRE_FILTERS}}; | 
|  | 93 |  |  |  |  | 364 |  | 
|  | 211 |  |  |  |  | 589 |  | 
|  | 93 |  |  |  |  | 218 |  | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub follow_up { | 
| 208 | 4 |  |  | 4 | 0 | 32 | my $self = shift; | 
| 209 | 4 |  |  |  |  | 10 | my ($sub) = @_; | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | carp "Useless addition of a follow-up in a child process or thread!" | 
| 212 | 4 | 50 | 33 |  |  | 22 | if $$ != $self->{+PID} || get_tid() != $self->{+TID}; | 
| 213 |  |  |  |  |  |  |  | 
| 214 | 4 | 100 | 66 |  |  | 386 | croak "follow_up only takes coderefs for arguments, got '$sub'" | 
| 215 |  |  |  |  |  |  | unless ref $sub && ref $sub eq 'CODE'; | 
| 216 |  |  |  |  |  |  |  | 
| 217 | 2 |  |  |  |  | 4 | push @{$self->{+_FOLLOW_UPS}} => $sub; | 
|  | 2 |  |  |  |  | 10 |  | 
| 218 |  |  |  |  |  |  | } | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | *add_context_aquire = \&add_context_acquire; | 
| 221 |  |  |  |  |  |  | sub add_context_acquire { | 
| 222 | 1 |  |  | 1 | 1 | 9 | my $self = shift; | 
| 223 | 1 |  |  |  |  | 2 | my ($sub) = @_; | 
| 224 |  |  |  |  |  |  |  | 
| 225 | 1 | 50 | 33 |  |  | 6 | croak "add_context_acquire only takes coderefs for arguments, got '$sub'" | 
| 226 |  |  |  |  |  |  | unless ref $sub && ref $sub eq 'CODE'; | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 1 |  |  |  |  | 2 | push @{$self->{+_CONTEXT_ACQUIRE}} => $sub; | 
|  | 1 |  |  |  |  | 15 |  | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 1 |  |  |  |  | 5 | $sub; # Intentional return. | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | *remove_context_aquire = \&remove_context_acquire; | 
| 234 |  |  |  |  |  |  | sub remove_context_acquire { | 
| 235 | 1 |  |  | 1 | 1 | 6 | my $self = shift; | 
| 236 | 1 |  |  |  |  | 2 | my %subs = map {$_ => $_} @_; | 
|  | 1 |  |  |  |  | 5 |  | 
| 237 | 1 |  |  |  |  | 2 | @{$self->{+_CONTEXT_ACQUIRE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_ACQUIRE}}; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 4 |  | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | sub add_context_init { | 
| 241 | 1 |  |  | 1 | 1 | 11 | my $self = shift; | 
| 242 | 1 |  |  |  |  | 3 | my ($sub) = @_; | 
| 243 |  |  |  |  |  |  |  | 
| 244 | 1 | 50 | 33 |  |  | 8 | croak "add_context_init only takes coderefs for arguments, got '$sub'" | 
| 245 |  |  |  |  |  |  | unless ref $sub && ref $sub eq 'CODE'; | 
| 246 |  |  |  |  |  |  |  | 
| 247 | 1 |  |  |  |  | 3 | push @{$self->{+_CONTEXT_INIT}} => $sub; | 
|  | 1 |  |  |  |  | 4 |  | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 1 |  |  |  |  | 4 | $sub; # Intentional return. | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | sub remove_context_init { | 
| 253 | 1 |  |  | 1 | 1 | 10 | my $self = shift; | 
| 254 | 1 |  |  |  |  | 17 | my %subs = map {$_ => $_} @_; | 
|  | 1 |  |  |  |  | 6 |  | 
| 255 | 1 |  |  |  |  | 3 | @{$self->{+_CONTEXT_INIT}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_INIT}}; | 
|  | 1 |  |  |  |  | 5 |  | 
|  | 1 |  |  |  |  | 6 |  | 
|  | 1 |  |  |  |  | 4 |  | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | sub add_context_release { | 
| 259 | 1 |  |  | 1 | 1 | 8 | my $self = shift; | 
| 260 | 1 |  |  |  |  | 3 | my ($sub) = @_; | 
| 261 |  |  |  |  |  |  |  | 
| 262 | 1 | 50 | 33 |  |  | 5 | croak "add_context_release only takes coderefs for arguments, got '$sub'" | 
| 263 |  |  |  |  |  |  | unless ref $sub && ref $sub eq 'CODE'; | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 1 |  |  |  |  | 3 | push @{$self->{+_CONTEXT_RELEASE}} => $sub; | 
|  | 1 |  |  |  |  | 3 |  | 
| 266 |  |  |  |  |  |  |  | 
| 267 | 1 |  |  |  |  | 3 | $sub; # Intentional return. | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | sub remove_context_release { | 
| 271 | 1 |  |  | 1 | 1 | 6 | my $self = shift; | 
| 272 | 1 |  |  |  |  | 3 | my %subs = map {$_ => $_} @_; | 
|  | 1 |  |  |  |  | 4 |  | 
| 273 | 1 |  |  |  |  | 3 | @{$self->{+_CONTEXT_RELEASE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_RELEASE}}; | 
|  | 1 |  |  |  |  | 5 |  | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 3 |  | 
| 274 |  |  |  |  |  |  | } | 
| 275 |  |  |  |  |  |  |  | 
| 276 |  |  |  |  |  |  | sub send { | 
| 277 | 6019 |  |  | 6019 | 1 | 12088 | my $self = shift; | 
| 278 | 6019 |  |  |  |  | 10852 | my ($e) = @_; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 6019 |  |  |  |  | 26309 | $e->eid; | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | $e->add_hub( | 
| 283 |  |  |  |  |  |  | { | 
| 284 |  |  |  |  |  |  | details => ref($self), | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | buffered => $self->{+BUFFERED}, | 
| 287 |  |  |  |  |  |  | hid      => $self->{+HID}, | 
| 288 |  |  |  |  |  |  | nested   => $self->{+NESTED}, | 
| 289 |  |  |  |  |  |  | pid      => $self->{+PID}, | 
| 290 |  |  |  |  |  |  | tid      => $self->{+TID}, | 
| 291 |  |  |  |  |  |  | uuid     => $self->{+UUID}, | 
| 292 |  |  |  |  |  |  |  | 
| 293 | 6019 | 100 |  |  |  | 61155 | ipc => $self->{+IPC} ? 1 : 0, | 
| 294 |  |  |  |  |  |  | } | 
| 295 |  |  |  |  |  |  | ); | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 6019 | 100 |  |  |  | 15542 | $e->set_uuid(${$UUID_VIA}->('event')) if $$UUID_VIA; | 
|  | 43 |  |  |  |  | 98 |  | 
| 298 |  |  |  |  |  |  |  | 
| 299 | 6019 | 100 |  |  |  | 14006 | if ($self->{+_PRE_FILTERS}) { | 
| 300 | 3798 |  |  |  |  | 5298 | for (@{$self->{+_PRE_FILTERS}}) { | 
|  | 3798 |  |  |  |  | 8718 |  | 
| 301 | 5279 |  |  |  |  | 16849 | $e = $_->{code}->($self, $e); | 
| 302 | 5279 | 100 |  |  |  | 13483 | return unless $e; | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 6016 |  | 100 |  |  | 21214 | my $ipc = $self->{+IPC} || return $self->process($e); | 
| 307 |  |  |  |  |  |  |  | 
| 308 | 692 | 100 |  |  |  | 2432 | if($e->global) { | 
| 309 | 1 |  |  |  |  | 7 | $ipc->send($self->{+HID}, $e, 'GLOBAL'); | 
| 310 | 1 |  |  |  |  | 6 | return $self->process($e); | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | return $ipc->send($self->{+HID}, $e) | 
| 314 | 691 | 100 | 66 |  |  | 3449 | if $$ != $self->{+PID} || get_tid() != $self->{+TID}; | 
| 315 |  |  |  |  |  |  |  | 
| 316 | 681 |  |  |  |  | 1795 | $self->process($e); | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | sub process { | 
| 320 | 6074 |  |  | 6074 | 1 | 9849 | my $self = shift; | 
| 321 | 6074 |  |  |  |  | 11421 | my ($e) = @_; | 
| 322 |  |  |  |  |  |  |  | 
| 323 | 6074 | 100 |  |  |  | 13086 | if ($self->{+_FILTERS}) { | 
| 324 | 18 |  |  |  |  | 31 | for (@{$self->{+_FILTERS}}) { | 
|  | 18 |  |  |  |  | 58 |  | 
| 325 | 17 |  |  |  |  | 70 | $e = $_->{code}->($self, $e); | 
| 326 | 17 | 100 |  |  |  | 146 | return unless $e; | 
| 327 |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  | } | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | # Optimize the most common case | 
| 331 | 6065 |  |  |  |  | 12221 | my $type = ref($e); | 
| 332 | 6065 | 100 | 100 |  |  | 24862 | if ($type eq 'Test2::Event::Pass' || ($type eq 'Test2::Event::Ok' && $e->{pass})) { | 
|  |  |  | 100 |  |  |  |  | 
| 333 | 3573 |  |  |  |  | 6892 | my $count = ++($self->{+COUNT}); | 
| 334 | 3573 | 100 |  |  |  | 19162 | $self->{+_FORMATTER}->write($e, $count) if $self->{+_FORMATTER}; | 
| 335 |  |  |  |  |  |  |  | 
| 336 | 3573 | 100 |  |  |  | 10251 | if ($self->{+_LISTENERS}) { | 
| 337 | 826 |  |  |  |  | 1299 | $_->{code}->($self, $e, $count) for @{$self->{+_LISTENERS}}; | 
|  | 826 |  |  |  |  | 3439 |  | 
| 338 |  |  |  |  |  |  | } | 
| 339 |  |  |  |  |  |  |  | 
| 340 | 3573 |  |  |  |  | 11099 | return $e; | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  |  | 
| 343 | 2492 |  |  |  |  | 8076 | my $f = $e->facet_data; | 
| 344 |  |  |  |  |  |  |  | 
| 345 | 2492 |  |  |  |  | 4309 | my $fail = 0; | 
| 346 | 2492 | 100 | 100 |  |  | 8277 | $fail = 1 if $f->{assert} && !$f->{assert}->{pass}; | 
| 347 | 2492 | 100 | 100 |  |  | 6468 | $fail = 1 if $f->{errors} && grep { $_->{fail} } @{$f->{errors}}; | 
|  | 8 |  |  |  |  | 29 |  | 
|  | 6 |  |  |  |  | 19 |  | 
| 348 | 2492 | 100 |  |  |  | 5499 | $fail = 0 if $f->{amnesty}; | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 2492 | 100 |  |  |  | 5571 | $self->{+COUNT}++ if $f->{assert}; | 
| 351 | 2492 | 100 | 100 |  |  | 6024 | $self->{+FAILED}++ if $fail && $f->{assert}; | 
| 352 | 2492 | 100 |  |  |  | 5246 | $self->{+_PASSING} = 0 if $fail; | 
| 353 |  |  |  |  |  |  |  | 
| 354 | 2492 | 100 |  |  |  | 6270 | my $code = $f->{control} ? $f->{control}->{terminate} : undef; | 
| 355 | 2492 |  |  |  |  | 4146 | my $count = $self->{+COUNT}; | 
| 356 |  |  |  |  |  |  |  | 
| 357 | 2492 | 100 |  |  |  | 5853 | if (my $plan = $f->{plan}) { | 
| 358 | 550 | 100 |  |  |  | 2688 | if ($plan->{skip}) { | 
|  |  | 100 |  |  |  |  |  | 
| 359 | 24 |  |  |  |  | 132 | $self->plan('SKIP'); | 
| 360 | 24 |  | 100 |  |  | 205 | $self->set_skip_reason($plan->{details} || 1); | 
| 361 | 24 |  | 50 |  |  | 160 | $code ||= 0; | 
| 362 |  |  |  |  |  |  | } | 
| 363 |  |  |  |  |  |  | elsif ($plan->{none}) { | 
| 364 | 1 |  |  |  |  | 5 | $self->plan('NO PLAN'); | 
| 365 |  |  |  |  |  |  | } | 
| 366 |  |  |  |  |  |  | else { | 
| 367 | 525 |  |  |  |  | 2254 | $self->plan($plan->{count}); | 
| 368 |  |  |  |  |  |  | } | 
| 369 |  |  |  |  |  |  | } | 
| 370 |  |  |  |  |  |  |  | 
| 371 | 2492 | 50 | 66 |  |  | 8037 | $e->callback($self) if $f->{control} && $f->{control}->{has_callback}; | 
| 372 |  |  |  |  |  |  |  | 
| 373 | 2492 | 100 |  |  |  | 12133 | $self->{+_FORMATTER}->write($e, $count, $f) if $self->{+_FORMATTER}; | 
| 374 |  |  |  |  |  |  |  | 
| 375 | 2492 | 100 |  |  |  | 7002 | if ($self->{+_LISTENERS}) { | 
| 376 | 773 |  |  |  |  | 1394 | $_->{code}->($self, $e, $count, $f) for @{$self->{+_LISTENERS}}; | 
|  | 773 |  |  |  |  | 3275 |  | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  |  | 
| 379 | 2492 | 100 | 100 |  |  | 10893 | if ($f->{control} && $f->{control}->{halt}) { | 
| 380 | 11 |  | 100 |  |  | 44 | $code ||= 255; | 
| 381 | 11 |  |  |  |  | 61 | $self->set_bailed_out($e); | 
| 382 |  |  |  |  |  |  | } | 
| 383 |  |  |  |  |  |  |  | 
| 384 | 2492 | 100 |  |  |  | 5922 | if (defined $code) { | 
| 385 | 35 | 100 |  |  |  | 400 | $self->{+_FORMATTER}->terminate($e, $f) if $self->{+_FORMATTER}; | 
| 386 | 35 |  |  |  |  | 181 | $self->terminate($code, $e, $f); | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  | 
| 389 | 2462 |  |  |  |  | 24987 | return $e; | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | sub terminate { | 
| 393 | 15 |  |  | 15 | 0 | 44 | my $self = shift; | 
| 394 | 15 |  |  |  |  | 43 | my ($code) = @_; | 
| 395 | 15 |  |  |  |  | 270 | exit($code); | 
| 396 |  |  |  |  |  |  | } | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | sub cull { | 
| 399 | 1223 |  |  | 1223 | 1 | 2404 | my $self = shift; | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 1223 |  | 100 |  |  | 3674 | my $ipc = $self->{+IPC} || return; | 
| 402 | 744 | 100 | 66 |  |  | 3629 | return if $self->{+PID} != $$ || $self->{+TID} != get_tid(); | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | # No need to do IPC checks on culled events | 
| 405 | 737 |  |  |  |  | 2533 | $self->process($_) for $ipc->cull($self->{+HID}); | 
| 406 |  |  |  |  |  |  | } | 
| 407 |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  | sub finalize { | 
| 409 | 469 |  |  | 469 | 0 | 1166 | my $self = shift; | 
| 410 | 469 |  |  |  |  | 1235 | my ($trace, $do_plan) = @_; | 
| 411 |  |  |  |  |  |  |  | 
| 412 | 469 |  |  |  |  | 2248 | $self->cull(); | 
| 413 |  |  |  |  |  |  |  | 
| 414 | 469 |  |  |  |  | 1173 | my $plan   = $self->{+_PLAN}; | 
| 415 | 469 |  |  |  |  | 1247 | my $count  = $self->{+COUNT}; | 
| 416 | 469 |  |  |  |  | 1152 | my $failed = $self->{+FAILED}; | 
| 417 | 469 |  |  |  |  | 993 | my $active = $self->{+ACTIVE}; | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | # return if NOTHING was done. | 
| 420 | 469 | 100 | 66 |  |  | 4068 | unless ($active || $do_plan || defined($plan) || $count || $failed) { | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 421 | 12 | 50 |  |  |  | 118 | $self->{+_FORMATTER}->finalize($plan, $count, $failed, 0, $self->is_subtest) if $self->{+_FORMATTER}; | 
| 422 | 12 |  |  |  |  | 37 | return; | 
| 423 |  |  |  |  |  |  | } | 
| 424 |  |  |  |  |  |  |  | 
| 425 | 457 | 100 |  |  |  | 1788 | unless ($self->{+ENDED}) { | 
| 426 | 454 | 100 |  |  |  | 1646 | if ($self->{+_FOLLOW_UPS}) { | 
| 427 | 2 |  |  |  |  | 4 | $_->($trace, $self) for reverse @{$self->{+_FOLLOW_UPS}}; | 
|  | 2 |  |  |  |  | 12 |  | 
| 428 |  |  |  |  |  |  | } | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | # These need to be refreshed now | 
| 431 | 454 |  |  |  |  | 1210 | $plan   = $self->{+_PLAN}; | 
| 432 | 454 |  |  |  |  | 1006 | $count  = $self->{+COUNT}; | 
| 433 | 454 |  |  |  |  | 928 | $failed = $self->{+FAILED}; | 
| 434 |  |  |  |  |  |  |  | 
| 435 | 454 | 100 | 100 |  |  | 4070 | if (($plan && $plan eq 'NO PLAN') || ($do_plan && !$plan)) { | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 436 | 313 |  |  |  |  | 2590 | $self->send( | 
| 437 |  |  |  |  |  |  | Test2::Event::Plan->new( | 
| 438 |  |  |  |  |  |  | trace => $trace, | 
| 439 |  |  |  |  |  |  | max => $count, | 
| 440 |  |  |  |  |  |  | ) | 
| 441 |  |  |  |  |  |  | ); | 
| 442 |  |  |  |  |  |  | } | 
| 443 | 454 |  |  |  |  | 2071 | $plan = $self->{+_PLAN}; | 
| 444 |  |  |  |  |  |  | } | 
| 445 |  |  |  |  |  |  |  | 
| 446 | 457 |  |  |  |  | 2183 | my $frame = $trace->frame; | 
| 447 | 457 | 100 |  |  |  | 1665 | if($self->{+ENDED}) { | 
| 448 | 3 |  |  |  |  | 8 | my (undef, $ffile, $fline) = @{$self->{+ENDED}}; | 
|  | 3 |  |  |  |  | 12 |  | 
| 449 | 3 |  |  |  |  | 11 | my (undef, $sfile, $sline) = @$frame; | 
| 450 |  |  |  |  |  |  |  | 
| 451 | 3 |  |  |  |  | 27 | die <<"        EOT" | 
| 452 |  |  |  |  |  |  | Test already ended! | 
| 453 |  |  |  |  |  |  | First End:  $ffile line $fline | 
| 454 |  |  |  |  |  |  | Second End: $sfile line $sline | 
| 455 |  |  |  |  |  |  | EOT | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  |  | 
| 458 | 454 |  |  |  |  | 1371 | $self->{+ENDED} = $frame; | 
| 459 | 454 |  |  |  |  | 1882 | my $pass = $self->is_passing(); # Generate the final boolean. | 
| 460 |  |  |  |  |  |  |  | 
| 461 | 454 | 100 |  |  |  | 2718 | $self->{+_FORMATTER}->finalize($plan, $count, $failed, $pass, $self->is_subtest) if $self->{+_FORMATTER}; | 
| 462 |  |  |  |  |  |  |  | 
| 463 | 454 |  |  |  |  | 1424 | return $pass; | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | sub is_passing { | 
| 467 | 2198 |  |  | 2198 | 1 | 4021 | my $self = shift; | 
| 468 |  |  |  |  |  |  |  | 
| 469 | 2198 | 100 |  |  |  | 5035 | ($self->{+_PASSING}) = @_ if @_; | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | # If we already failed just return 0. | 
| 472 | 2198 | 100 |  |  |  | 5797 | my $pass = $self->{+_PASSING} or return 0; | 
| 473 | 1773 | 100 |  |  |  | 4005 | return $self->{+_PASSING} = 0 if $self->{+FAILED}; | 
| 474 |  |  |  |  |  |  |  | 
| 475 | 1766 |  |  |  |  | 2918 | my $count = $self->{+COUNT}; | 
| 476 | 1766 |  |  |  |  | 2781 | my $ended = $self->{+ENDED}; | 
| 477 | 1766 |  |  |  |  | 2905 | my $plan = $self->{+_PLAN}; | 
| 478 |  |  |  |  |  |  |  | 
| 479 | 1766 | 100 | 100 |  |  | 6310 | return $pass if !$count && $plan && $plan =~ m/^SKIP$/; | 
|  |  |  | 100 |  |  |  |  | 
| 480 |  |  |  |  |  |  |  | 
| 481 | 1725 | 100 | 100 |  |  | 7122 | return $self->{+_PASSING} = 0 | 
|  |  |  | 100 |  |  |  |  | 
| 482 |  |  |  |  |  |  | if $ended && (!$count || !$plan); | 
| 483 |  |  |  |  |  |  |  | 
| 484 | 1696 | 100 | 100 |  |  | 10465 | return $pass unless $plan && $plan =~ m/^\d+$/; | 
| 485 |  |  |  |  |  |  |  | 
| 486 | 1550 | 100 |  |  |  | 3675 | if ($ended) { | 
| 487 | 872 | 100 |  |  |  | 2292 | return $self->{+_PASSING} = 0 if $count != $plan; | 
| 488 |  |  |  |  |  |  | } | 
| 489 |  |  |  |  |  |  | else { | 
| 490 | 678 | 100 |  |  |  | 1255 | return $self->{+_PASSING} = 0 if $count > $plan; | 
| 491 |  |  |  |  |  |  | } | 
| 492 |  |  |  |  |  |  |  | 
| 493 | 1546 |  |  |  |  | 5118 | return $pass; | 
| 494 |  |  |  |  |  |  | } | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | sub plan { | 
| 497 | 1967 |  |  | 1967 | 1 | 3638 | my $self = shift; | 
| 498 |  |  |  |  |  |  |  | 
| 499 | 1967 | 100 |  |  |  | 7603 | return $self->{+_PLAN} unless @_; | 
| 500 |  |  |  |  |  |  |  | 
| 501 | 582 |  |  |  |  | 1584 | my ($plan) = @_; | 
| 502 |  |  |  |  |  |  |  | 
| 503 | 582 | 50 |  |  |  | 1767 | confess "You cannot unset the plan" | 
| 504 |  |  |  |  |  |  | unless defined $plan; | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | confess "You cannot change the plan" | 
| 507 | 582 | 100 | 100 |  |  | 2716 | if $self->{+_PLAN} && $self->{+_PLAN} !~ m/^NO PLAN$/; | 
| 508 |  |  |  |  |  |  |  | 
| 509 | 581 | 100 |  |  |  | 4401 | 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)$/; | 
| 511 |  |  |  |  |  |  |  | 
| 512 | 580 |  |  |  |  | 1945 | $self->{+_PLAN} = $plan; | 
| 513 |  |  |  |  |  |  | } | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | sub check_plan { | 
| 516 | 124 |  |  | 124 | 1 | 260 | my $self = shift; | 
| 517 |  |  |  |  |  |  |  | 
| 518 | 124 | 50 |  |  |  | 363 | return undef unless $self->{+ENDED}; | 
| 519 | 124 |  | 100 |  |  | 361 | my $plan = $self->{+_PLAN} || return undef; | 
| 520 |  |  |  |  |  |  |  | 
| 521 | 115 | 50 |  |  |  | 633 | return 1 if $plan !~ m/^\d+$/; | 
| 522 |  |  |  |  |  |  |  | 
| 523 | 115 | 100 |  |  |  | 512 | return 1 if $plan == $self->{+COUNT}; | 
| 524 | 1 |  |  |  |  | 4 | return 0; | 
| 525 |  |  |  |  |  |  | } | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | sub DESTROY { | 
| 528 | 465 |  |  | 465 |  | 1891 | my $self = shift; | 
| 529 | 465 |  | 100 |  |  | 15462 | my $ipc = $self->{+IPC} || return; | 
| 530 | 51 | 100 |  |  |  | 312 | return unless $$ == $self->{+PID}; | 
| 531 | 50 | 50 |  |  |  | 153 | return unless get_tid() == $self->{+TID}; | 
| 532 | 50 |  |  |  |  | 269 | $ipc->drop_hub($self->{+HID}); | 
| 533 |  |  |  |  |  |  | } | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  | 1; | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  | __END__ | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | =pod | 
| 540 |  |  |  |  |  |  |  | 
| 541 |  |  |  |  |  |  | =encoding UTF-8 | 
| 542 |  |  |  |  |  |  |  | 
| 543 |  |  |  |  |  |  | =head1 NAME | 
| 544 |  |  |  |  |  |  |  | 
| 545 |  |  |  |  |  |  | Test2::Hub - The conduit through which all events flow. | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 548 |  |  |  |  |  |  |  | 
| 549 |  |  |  |  |  |  | use Test2::Hub; | 
| 550 |  |  |  |  |  |  |  | 
| 551 |  |  |  |  |  |  | my $hub = Test2::Hub->new(); | 
| 552 |  |  |  |  |  |  | $hub->send(...); | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 555 |  |  |  |  |  |  |  | 
| 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 | 
| 558 |  |  |  |  |  |  | event pipeline. | 
| 559 |  |  |  |  |  |  |  | 
| 560 |  |  |  |  |  |  | =head1 COMMON TASKS | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | =head2 SENDING EVENTS | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | $hub->send($event) | 
| 565 |  |  |  |  |  |  |  | 
| 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. | 
| 568 |  |  |  |  |  |  |  | 
| 569 |  |  |  |  |  |  | =head2 ALTERING OR REMOVING EVENTS | 
| 570 |  |  |  |  |  |  |  | 
| 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. | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | $hub->filter(sub { | 
| 575 |  |  |  |  |  |  | my ($hub, $event) = @_; | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | my $action = get_action($event); | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | # No action should be taken | 
| 580 |  |  |  |  |  |  | return $event if $action eq 'none'; | 
| 581 |  |  |  |  |  |  |  | 
| 582 |  |  |  |  |  |  | # You want your filter to remove the event | 
| 583 |  |  |  |  |  |  | return undef if $action eq 'delete'; | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | if ($action eq 'do_it') { | 
| 586 |  |  |  |  |  |  | my $new_event = copy_event($event); | 
| 587 |  |  |  |  |  |  | ... Change your copy of the event ... | 
| 588 |  |  |  |  |  |  | return $new_event; | 
| 589 |  |  |  |  |  |  | } | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | die "Should not happen"; | 
| 592 |  |  |  |  |  |  | }); | 
| 593 |  |  |  |  |  |  |  | 
| 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: | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | $hub->filter(sub { ... }, inherit => 1); | 
| 599 |  |  |  |  |  |  |  | 
| 600 |  |  |  |  |  |  | =head2 LISTENING FOR EVENTS | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | $hub->listen(sub { | 
| 603 |  |  |  |  |  |  | my ($hub, $event, $number) = @_; | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | ... do whatever you want with the event ... | 
| 606 |  |  |  |  |  |  |  | 
| 607 |  |  |  |  |  |  | # return is ignored | 
| 608 |  |  |  |  |  |  | }); | 
| 609 |  |  |  |  |  |  |  | 
| 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: | 
| 613 |  |  |  |  |  |  |  | 
| 614 |  |  |  |  |  |  | $hub->listen(sub { ... }, inherit => 1); | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | =head2 POST-TEST BEHAVIORS | 
| 618 |  |  |  |  |  |  |  | 
| 619 |  |  |  |  |  |  | $hub->follow_up(sub { | 
| 620 |  |  |  |  |  |  | my ($trace, $hub) = @_; | 
| 621 |  |  |  |  |  |  |  | 
| 622 |  |  |  |  |  |  | ... do whatever you need to ... | 
| 623 |  |  |  |  |  |  |  | 
| 624 |  |  |  |  |  |  | # Return is ignored | 
| 625 |  |  |  |  |  |  | }); | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | follow_up subs are called only once, either when done_testing is called, or in | 
| 628 |  |  |  |  |  |  | an END block. | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | =head2 SETTING THE FORMATTER | 
| 631 |  |  |  |  |  |  |  | 
| 632 |  |  |  |  |  |  | By default an instance of L<Test2::Formatter::TAP> is created and used. | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | my $old = $hub->format(My::Formatter->new); | 
| 635 |  |  |  |  |  |  |  | 
| 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. | 
| 639 |  |  |  |  |  |  |  | 
| 640 |  |  |  |  |  |  | =head1 METHODS | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | =over 4 | 
| 643 |  |  |  |  |  |  |  | 
| 644 |  |  |  |  |  |  | =item $hub->send($event) | 
| 645 |  |  |  |  |  |  |  | 
| 646 |  |  |  |  |  |  | This is where all events enter the hub for processing. | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | =item $hub->process($event) | 
| 649 |  |  |  |  |  |  |  | 
| 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. | 
| 652 |  |  |  |  |  |  |  | 
| 653 |  |  |  |  |  |  | =item $old = $hub->format($formatter) | 
| 654 |  |  |  |  |  |  |  | 
| 655 |  |  |  |  |  |  | Replace the existing formatter instance with a new one. Formatters must be | 
| 656 |  |  |  |  |  |  | objects that implement a C<< $formatter->write($event) >> method. | 
| 657 |  |  |  |  |  |  |  | 
| 658 |  |  |  |  |  |  | =item $sub = $hub->listen(sub { ... }, %optional_params) | 
| 659 |  |  |  |  |  |  |  | 
| 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 | 
| 662 |  |  |  |  |  |  | listeners. | 
| 663 |  |  |  |  |  |  |  | 
| 664 |  |  |  |  |  |  | $hub->listen(sub { | 
| 665 |  |  |  |  |  |  | my ($hub, $event, $number) = @_; | 
| 666 |  |  |  |  |  |  |  | 
| 667 |  |  |  |  |  |  | ... do whatever you want with the event ... | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  | # return is ignored | 
| 670 |  |  |  |  |  |  | }); | 
| 671 |  |  |  |  |  |  |  | 
| 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. | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | =item $hub->unlisten($sub) | 
| 676 |  |  |  |  |  |  |  | 
| 677 |  |  |  |  |  |  | You can use this to remove a listen callback. You must pass in the coderef | 
| 678 |  |  |  |  |  |  | returned by the C<listen()> method. | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | =item $sub = $hub->filter(sub { ... }, %optional_params) | 
| 681 |  |  |  |  |  |  |  | 
| 682 |  |  |  |  |  |  | =item $sub = $hub->pre_filter(sub { ... }, %optional_params) | 
| 683 |  |  |  |  |  |  |  | 
| 684 |  |  |  |  |  |  | These can be used to add filters. Filters can modify, replace, or remove events | 
| 685 |  |  |  |  |  |  | before anything else can see them. | 
| 686 |  |  |  |  |  |  |  | 
| 687 |  |  |  |  |  |  | $hub->filter( | 
| 688 |  |  |  |  |  |  | sub { | 
| 689 |  |  |  |  |  |  | my ($hub, $event) = @_; | 
| 690 |  |  |  |  |  |  |  | 
| 691 |  |  |  |  |  |  | return $event;    # No Changes | 
| 692 |  |  |  |  |  |  | return;           # Remove the event | 
| 693 |  |  |  |  |  |  |  | 
| 694 |  |  |  |  |  |  | # Or you can modify an event before returning it. | 
| 695 |  |  |  |  |  |  | $event->modify; | 
| 696 |  |  |  |  |  |  | return $event; | 
| 697 |  |  |  |  |  |  | } | 
| 698 |  |  |  |  |  |  | ); | 
| 699 |  |  |  |  |  |  |  | 
| 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. | 
| 705 |  |  |  |  |  |  |  | 
| 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. | 
| 708 |  |  |  |  |  |  |  | 
| 709 |  |  |  |  |  |  | =item $hub->unfilter($sub) | 
| 710 |  |  |  |  |  |  |  | 
| 711 |  |  |  |  |  |  | =item $hub->pre_unfilter($sub) | 
| 712 |  |  |  |  |  |  |  | 
| 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()>. | 
| 715 |  |  |  |  |  |  |  | 
| 716 |  |  |  |  |  |  | =item $hub->follow_op(sub { ... }) | 
| 717 |  |  |  |  |  |  |  | 
| 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. | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  | $hub->follow_up(sub { | 
| 722 |  |  |  |  |  |  | my ($trace, $hub) = @_; | 
| 723 |  |  |  |  |  |  |  | 
| 724 |  |  |  |  |  |  | ... do whatever you need to ... | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | # Return is ignored | 
| 727 |  |  |  |  |  |  | }); | 
| 728 |  |  |  |  |  |  |  | 
| 729 |  |  |  |  |  |  | follow_up subs are called only once, ether when done_testing is called, or in | 
| 730 |  |  |  |  |  |  | an END block. | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | =item $sub = $hub->add_context_acquire(sub { ... }); | 
| 733 |  |  |  |  |  |  |  | 
| 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. | 
| 738 |  |  |  |  |  |  |  | 
| 739 |  |  |  |  |  |  | test2_add_callback_context_acquire(sub { | 
| 740 |  |  |  |  |  |  | my $params = shift; | 
| 741 |  |  |  |  |  |  | $params->{level}++; | 
| 742 |  |  |  |  |  |  | }); | 
| 743 |  |  |  |  |  |  |  | 
| 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 | 
| 747 |  |  |  |  |  |  | reasons. | 
| 748 |  |  |  |  |  |  |  | 
| 749 |  |  |  |  |  |  | B<Note> Using this hook could have a huge performance impact. | 
| 750 |  |  |  |  |  |  |  | 
| 751 |  |  |  |  |  |  | The coderef you provide is returned and can be used to remove the hook later. | 
| 752 |  |  |  |  |  |  |  | 
| 753 |  |  |  |  |  |  | =item $hub->remove_context_acquire($sub); | 
| 754 |  |  |  |  |  |  |  | 
| 755 |  |  |  |  |  |  | This can be used to remove a context acquire hook. | 
| 756 |  |  |  |  |  |  |  | 
| 757 |  |  |  |  |  |  | =item $sub = $hub->add_context_init(sub { ... }); | 
| 758 |  |  |  |  |  |  |  | 
| 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. | 
| 762 |  |  |  |  |  |  |  | 
| 763 |  |  |  |  |  |  | B<Note> Using this hook could have a huge performance impact. | 
| 764 |  |  |  |  |  |  |  | 
| 765 |  |  |  |  |  |  | The coderef you provide is returned and can be used to remove the hook later. | 
| 766 |  |  |  |  |  |  |  | 
| 767 |  |  |  |  |  |  | =item $hub->remove_context_init($sub); | 
| 768 |  |  |  |  |  |  |  | 
| 769 |  |  |  |  |  |  | This can be used to remove a context init hook. | 
| 770 |  |  |  |  |  |  |  | 
| 771 |  |  |  |  |  |  | =item $sub = $hub->add_context_release(sub { ... }); | 
| 772 |  |  |  |  |  |  |  | 
| 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 | 
| 776 |  |  |  |  |  |  | order. | 
| 777 |  |  |  |  |  |  |  | 
| 778 |  |  |  |  |  |  | B<Note> Using this hook could have a huge performance impact. | 
| 779 |  |  |  |  |  |  |  | 
| 780 |  |  |  |  |  |  | The coderef you provide is returned and can be used to remove the hook later. | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | =item $hub->remove_context_release($sub); | 
| 783 |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  | This can be used to remove a context release hook. | 
| 785 |  |  |  |  |  |  |  | 
| 786 |  |  |  |  |  |  | =item $hub->cull() | 
| 787 |  |  |  |  |  |  |  | 
| 788 |  |  |  |  |  |  | Cull any IPC events (and process them). | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | =item $pid = $hub->pid() | 
| 791 |  |  |  |  |  |  |  | 
| 792 |  |  |  |  |  |  | Get the process id under which the hub was created. | 
| 793 |  |  |  |  |  |  |  | 
| 794 |  |  |  |  |  |  | =item $tid = $hub->tid() | 
| 795 |  |  |  |  |  |  |  | 
| 796 |  |  |  |  |  |  | Get the thread id under which the hub was created. | 
| 797 |  |  |  |  |  |  |  | 
| 798 |  |  |  |  |  |  | =item $hud = $hub->hid() | 
| 799 |  |  |  |  |  |  |  | 
| 800 |  |  |  |  |  |  | Get the identifier string of the hub. | 
| 801 |  |  |  |  |  |  |  | 
| 802 |  |  |  |  |  |  | =item $uuid = $hub->uuid() | 
| 803 |  |  |  |  |  |  |  | 
| 804 |  |  |  |  |  |  | If UUID tagging is enabled (see L<Test2::API>) then the hub will have a UUID. | 
| 805 |  |  |  |  |  |  |  | 
| 806 |  |  |  |  |  |  | =item $ipc = $hub->ipc() | 
| 807 |  |  |  |  |  |  |  | 
| 808 |  |  |  |  |  |  | Get the IPC object used by the hub. | 
| 809 |  |  |  |  |  |  |  | 
| 810 |  |  |  |  |  |  | =item $hub->set_no_ending($bool) | 
| 811 |  |  |  |  |  |  |  | 
| 812 |  |  |  |  |  |  | =item $bool = $hub->no_ending | 
| 813 |  |  |  |  |  |  |  | 
| 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'. | 
| 817 |  |  |  |  |  |  |  | 
| 818 |  |  |  |  |  |  | =item $bool = $hub->active | 
| 819 |  |  |  |  |  |  |  | 
| 820 |  |  |  |  |  |  | =item $hub->set_active($bool) | 
| 821 |  |  |  |  |  |  |  | 
| 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. | 
| 826 |  |  |  |  |  |  |  | 
| 827 |  |  |  |  |  |  | =back | 
| 828 |  |  |  |  |  |  |  | 
| 829 |  |  |  |  |  |  | =head2 STATE METHODS | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | =over 4 | 
| 832 |  |  |  |  |  |  |  | 
| 833 |  |  |  |  |  |  | =item $hub->reset_state() | 
| 834 |  |  |  |  |  |  |  | 
| 835 |  |  |  |  |  |  | Reset all state to the start. This sets the test count to 0, clears the plan, | 
| 836 |  |  |  |  |  |  | removes the failures, etc. | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | =item $num = $hub->count | 
| 839 |  |  |  |  |  |  |  | 
| 840 |  |  |  |  |  |  | Get the number of tests that have been run. | 
| 841 |  |  |  |  |  |  |  | 
| 842 |  |  |  |  |  |  | =item $num = $hub->failed | 
| 843 |  |  |  |  |  |  |  | 
| 844 |  |  |  |  |  |  | Get the number of failures (Not all failures come from a test fail, so this | 
| 845 |  |  |  |  |  |  | number can be larger than the count). | 
| 846 |  |  |  |  |  |  |  | 
| 847 |  |  |  |  |  |  | =item $bool = $hub->ended | 
| 848 |  |  |  |  |  |  |  | 
| 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. | 
| 851 |  |  |  |  |  |  |  | 
| 852 |  |  |  |  |  |  | =item $bool = $hub->is_passing | 
| 853 |  |  |  |  |  |  |  | 
| 854 |  |  |  |  |  |  | =item $hub->is_passing($bool) | 
| 855 |  |  |  |  |  |  |  | 
| 856 |  |  |  |  |  |  | Check if the overall test run is a failure. Can also be used to set the | 
| 857 |  |  |  |  |  |  | pass/fail status. | 
| 858 |  |  |  |  |  |  |  | 
| 859 |  |  |  |  |  |  | =item $hub->plan($plan) | 
| 860 |  |  |  |  |  |  |  | 
| 861 |  |  |  |  |  |  | =item $plan = $hub->plan | 
| 862 |  |  |  |  |  |  |  | 
| 863 |  |  |  |  |  |  | Get or set the plan. The plan must be an integer larger than 0, the string | 
| 864 |  |  |  |  |  |  | 'NO PLAN', or the string 'SKIP'. | 
| 865 |  |  |  |  |  |  |  | 
| 866 |  |  |  |  |  |  | =item $bool = $hub->check_plan | 
| 867 |  |  |  |  |  |  |  | 
| 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. | 
| 870 |  |  |  |  |  |  |  | 
| 871 |  |  |  |  |  |  | =back | 
| 872 |  |  |  |  |  |  |  | 
| 873 |  |  |  |  |  |  | =head1 THIRD PARTY META-DATA | 
| 874 |  |  |  |  |  |  |  | 
| 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. | 
| 878 |  |  |  |  |  |  |  | 
| 879 |  |  |  |  |  |  | =head1 SOURCE | 
| 880 |  |  |  |  |  |  |  | 
| 881 |  |  |  |  |  |  | The source code repository for Test2 can be found at | 
| 882 |  |  |  |  |  |  | F<http://github.com/Test-More/test-more/>. | 
| 883 |  |  |  |  |  |  |  | 
| 884 |  |  |  |  |  |  | =head1 MAINTAINERS | 
| 885 |  |  |  |  |  |  |  | 
| 886 |  |  |  |  |  |  | =over 4 | 
| 887 |  |  |  |  |  |  |  | 
| 888 |  |  |  |  |  |  | =item Chad Granum E<lt>exodist@cpan.orgE<gt> | 
| 889 |  |  |  |  |  |  |  | 
| 890 |  |  |  |  |  |  | =back | 
| 891 |  |  |  |  |  |  |  | 
| 892 |  |  |  |  |  |  | =head1 AUTHORS | 
| 893 |  |  |  |  |  |  |  | 
| 894 |  |  |  |  |  |  | =over 4 | 
| 895 |  |  |  |  |  |  |  | 
| 896 |  |  |  |  |  |  | =item Chad Granum E<lt>exodist@cpan.orgE<gt> | 
| 897 |  |  |  |  |  |  |  | 
| 898 |  |  |  |  |  |  | =back | 
| 899 |  |  |  |  |  |  |  | 
| 900 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 901 |  |  |  |  |  |  |  | 
| 902 |  |  |  |  |  |  | Copyright 2020 Chad Granum E<lt>exodist@cpan.orgE<gt>. | 
| 903 |  |  |  |  |  |  |  | 
| 904 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or | 
| 905 |  |  |  |  |  |  | modify it under the same terms as Perl itself. | 
| 906 |  |  |  |  |  |  |  | 
| 907 |  |  |  |  |  |  | See F<http://dev.perl.org/licenses/> | 
| 908 |  |  |  |  |  |  |  | 
| 909 |  |  |  |  |  |  | =cut |