File Coverage

blib/lib/Test2/Hub.pm
Criterion Covered Total %
statement 301 302 99.6
branch 141 156 90.3
condition 105 136 77.2
subroutine 37 37 100.0
pod 20 27 74.0
total 604 658 91.7


line stmt bran cond sub pod time code
1             package Test2::Hub;
2 246     246   4046 use strict;
  246         446  
  246         7489  
3 246     246   1500 use warnings;
  246         466  
  246         10912  
4              
5             our $VERSION = '1.302180';
6              
7              
8 246     246   1496 use Carp qw/carp croak confess/;
  246         525  
  246         15575  
9 246     246   2262 use Test2::Util qw/get_tid gen_uid/;
  246         513  
  246         13126  
10              
11 246     246   1793 use Scalar::Util qw/weaken/;
  246         559  
  246         12760  
12 246     246   1748 use List::Util qw/first/;
  246         577  
  246         27887  
13              
14 246     246   103947 use Test2::Util::ExternalMeta qw/meta get_meta set_meta delete_meta/;
  246         602  
  246         19682  
15 246         1572 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   2203 };
  246         471  
38              
39             my $UUID_VIA;
40              
41             sub init {
42 728     728 0 1540 my $self = shift;
43              
44 728         3491 $self->{+PID} = $$;
45 728         1957 $self->{+TID} = get_tid();
46 728         3717 $self->{+HID} = gen_uid();
47              
48 728   66     3471 $UUID_VIA ||= Test2::API::_add_uuid_via_ref();
49 728 100       2159 $self->{+UUID} = ${$UUID_VIA}->('hub') if $$UUID_VIA;
  4         13  
50              
51 728 100       2698 $self->{+NESTED} = 0 unless defined $self->{+NESTED};
52 728 100       2342 $self->{+BUFFERED} = 0 unless defined $self->{+BUFFERED};
53              
54 728         1775 $self->{+COUNT} = 0;
55 728         1588 $self->{+FAILED} = 0;
56 728         2157 $self->{+_PASSING} = 1;
57              
58 728 100       2279 if (my $formatter = delete $self->{formatter}) {
59 52         203 $self->format($formatter);
60             }
61              
62 728 100       2812 if (my $ipc = $self->{+IPC}) {
63 15         58 $ipc->add_hub($self->{+HID});
64             }
65             }
66              
67 235     235 0 2648 sub is_subtest { 0 }
68              
69             sub _tb_reset {
70 55     55   137 my $self = shift;
71              
72             # Nothing to do
73 55 100 66     513 return if $self->{+PID} == $$ && $self->{+TID} == get_tid();
74              
75 1         19 $self->{+PID} = $$;
76 1         5 $self->{+TID} = get_tid();
77 1         25 $self->{+HID} = gen_uid();
78              
79 1 50       23 if (my $ipc = $self->{+IPC}) {
80 0         0 $ipc->add_hub($self->{+HID});
81             }
82             }
83              
84             sub reset_state {
85 58     58 1 152 my $self = shift;
86              
87 58         145 $self->{+COUNT} = 0;
88 58         146 $self->{+FAILED} = 0;
89 58         125 $self->{+_PASSING} = 1;
90              
91 58         145 delete $self->{+_PLAN};
92 58         124 delete $self->{+ENDED};
93 58         143 delete $self->{+BAILED_OUT};
94 58         153 delete $self->{+SKIP_REASON};
95             }
96              
97             sub inherit {
98 291     291 0 535 my $self = shift;
99 291         651 my ($from, %params) = @_;
100              
101 291   50     1514 $self->{+NESTED} ||= 0;
102              
103             $self->{+_FORMATTER} = $from->{+_FORMATTER}
104 291 100 66     1423 unless $self->{+_FORMATTER} || exists($params{formatter});
105              
106 291 100 66     1112 if ($from->{+IPC} && !$self->{+IPC} && !exists($params{ipc})) {
      100        
107 24         55 my $ipc = $from->{+IPC};
108 24         77 $self->{+IPC} = $ipc;
109 24         136 $ipc->add_hub($self->{+HID});
110             }
111              
112 291 100       863 if (my $ls = $from->{+_LISTENERS}) {
113 53         111 push @{$self->{+_LISTENERS}} => grep { $_->{inherit} } @$ls;
  53         207  
  55         165  
114             }
115              
116 291 100       846 if (my $pfs = $from->{+_PRE_FILTERS}) {
117 173         275 push @{$self->{+_PRE_FILTERS}} => grep { $_->{inherit} } @$pfs;
  173         563  
  253         669  
118             }
119              
120 291 100       1111 if (my $fs = $from->{+_FILTERS}) {
121 12         18 push @{$self->{+_FILTERS}} => grep { $_->{inherit} } @$fs;
  12         45  
  6         27  
122             }
123             }
124              
125             sub format {
126 3483     3483 1 5857 my $self = shift;
127              
128 3483         6108 my $old = $self->{+_FORMATTER};
129 3483 100       8706 ($self->{+_FORMATTER}) = @_ if @_;
130              
131 3483         9912 return $old;
132             }
133              
134             sub is_local {
135 126     126 0 259 my $self = shift;
136             return $$ == $self->{+PID}
137 126   66     1009 && get_tid() == $self->{+TID};
138             }
139              
140             sub listen {
141 342     342 1 656 my $self = shift;
142 342         769 my ($sub, %params) = @_;
143              
144             carp "Useless addition of a listener in a child process or thread!"
145 342 50 33     2067 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
146              
147 342 100 66     2040 croak "listen only takes coderefs for arguments, got '$sub'"
148             unless ref $sub && ref $sub eq 'CODE';
149              
150 341         626 push @{$self->{+_LISTENERS}} => { %params, code => $sub };
  341         1352  
151              
152 341         930 $sub; # Intentional return.
153             }
154              
155             sub unlisten {
156 1     1 1 16 my $self = shift;
157              
158             carp "Useless removal of a listener in a child process or thread!"
159 1 50 33     11 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
160              
161 1         4 my %subs = map {$_ => $_} @_;
  1         6  
162              
163 1         3 @{$self->{+_LISTENERS}} = grep { !$subs{$_->{code}} } @{$self->{+_LISTENERS}};
  1         7  
  2         13  
  1         12  
164             }
165              
166             sub filter {
167 11     11 1 140 my $self = shift;
168 11         36 my ($sub, %params) = @_;
169              
170             carp "Useless addition of a filter in a child process or thread!"
171 11 50 33     107 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
172              
173 11 100 66     174 croak "filter only takes coderefs for arguments, got '$sub'"
174             unless ref $sub && ref $sub eq 'CODE';
175              
176 10         21 push @{$self->{+_FILTERS}} => { %params, code => $sub };
  10         64  
177              
178 10         37 $sub; # Intentional Return
179             }
180              
181             sub unfilter {
182 2     2 1 18 my $self = shift;
183             carp "Useless removal of a filter in a child process or thread!"
184 2 50 33     29 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
185 2         12 my %subs = map {$_ => $_} @_;
  2         16  
186 2         6 @{$self->{+_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_FILTERS}};
  2         12  
  3         12  
  2         9  
187             }
188              
189             sub pre_filter {
190 482     482 1 1223 my $self = shift;
191 482         1738 my ($sub, %params) = @_;
192              
193 482 100 66     3340 croak "pre_filter only takes coderefs for arguments, got '$sub'"
194             unless ref $sub && ref $sub eq 'CODE';
195              
196 481         1034 push @{$self->{+_PRE_FILTERS}} => { %params, code => $sub };
  481         2607  
197              
198 481         2067 $sub; # Intentional Return
199             }
200              
201             sub pre_unfilter {
202 93     93 1 173 my $self = shift;
203 93         214 my %subs = map {$_ => $_} @_;
  93         424  
204 93         166 @{$self->{+_PRE_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_PRE_FILTERS}};
  93         351  
  211         596  
  93         205  
205             }
206              
207             sub follow_up {
208 4     4 0 26 my $self = shift;
209 4         8 my ($sub) = @_;
210              
211             carp "Useless addition of a follow-up in a child process or thread!"
212 4 50 33     18 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
213              
214 4 100 66     332 croak "follow_up only takes coderefs for arguments, got '$sub'"
215             unless ref $sub && ref $sub eq 'CODE';
216              
217 2         2 push @{$self->{+_FOLLOW_UPS}} => $sub;
  2         6  
218             }
219              
220             *add_context_aquire = \&add_context_acquire;
221             sub add_context_acquire {
222 1     1 1 31 my $self = shift;
223 1         3 my ($sub) = @_;
224              
225 1 50 33     8 croak "add_context_acquire only takes coderefs for arguments, got '$sub'"
226             unless ref $sub && ref $sub eq 'CODE';
227              
228 1         3 push @{$self->{+_CONTEXT_ACQUIRE}} => $sub;
  1         4  
229              
230 1         4 $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         4  
237 1         2 @{$self->{+_CONTEXT_ACQUIRE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_ACQUIRE}};
  1         3  
  1         3  
  1         3  
238             }
239              
240             sub add_context_init {
241 1     1 1 13 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         2 push @{$self->{+_CONTEXT_INIT}} => $sub;
  1         4  
248              
249 1         3 $sub; # Intentional return.
250             }
251              
252             sub remove_context_init {
253 1     1 1 12 my $self = shift;
254 1         4 my %subs = map {$_ => $_} @_;
  1         6  
255 1         3 @{$self->{+_CONTEXT_INIT}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_INIT}};
  1         5  
  1         5  
  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     6 croak "add_context_release only takes coderefs for arguments, got '$sub'"
263             unless ref $sub && ref $sub eq 'CODE';
264              
265 1         2 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         5  
273 1         3 @{$self->{+_CONTEXT_RELEASE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_RELEASE}};
  1         3  
  1         6  
  1         4  
274             }
275              
276             sub send {
277 6015     6015 1 11257 my $self = shift;
278 6015         10966 my ($e) = @_;
279              
280 6015         25736 $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 6015 100       60223 ipc => $self->{+IPC} ? 1 : 0,
294             }
295             );
296              
297 6015 100       16915 $e->set_uuid(${$UUID_VIA}->('event')) if $$UUID_VIA;
  43         148  
298              
299 6015 100       13580 if ($self->{+_PRE_FILTERS}) {
300 3798         5360 for (@{$self->{+_PRE_FILTERS}}) {
  3798         9016  
301 5279         16644 $e = $_->{code}->($self, $e);
302 5279 100       13162 return unless $e;
303             }
304             }
305              
306 6012   100     20502 my $ipc = $self->{+IPC} || return $self->process($e);
307              
308 692 100       2412 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     3384 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
315              
316 681         1738 $self->process($e);
317             }
318              
319             sub process {
320 6070     6070 1 9757 my $self = shift;
321 6070         10359 my ($e) = @_;
322              
323 6070 100       13413 if ($self->{+_FILTERS}) {
324 18         38 for (@{$self->{+_FILTERS}}) {
  18         55  
325 17         72 $e = $_->{code}->($self, $e);
326 17 100       114 return unless $e;
327             }
328             }
329              
330             # Optimize the most common case
331 6061         12056 my $type = ref($e);
332 6061 100 100     25858 if ($type eq 'Test2::Event::Pass' || ($type eq 'Test2::Event::Ok' && $e->{pass})) {
      100        
333 3557         7616 my $count = ++($self->{+COUNT});
334 3557 100       18906 $self->{+_FORMATTER}->write($e, $count) if $self->{+_FORMATTER};
335              
336 3557 100       10036 if ($self->{+_LISTENERS}) {
337 824         1125 $_->{code}->($self, $e, $count) for @{$self->{+_LISTENERS}};
  824         3120  
338             }
339              
340 3557         10923 return $e;
341             }
342              
343 2504         8328 my $f = $e->facet_data;
344              
345 2504         4193 my $fail = 0;
346 2504 100 100     8656 $fail = 1 if $f->{assert} && !$f->{assert}->{pass};
347 2504 100 100     6646 $fail = 1 if $f->{errors} && grep { $_->{fail} } @{$f->{errors}};
  8         41  
  6         16  
348 2504 100       5397 $fail = 0 if $f->{amnesty};
349              
350 2504 100       5633 $self->{+COUNT}++ if $f->{assert};
351 2504 100 100     6041 $self->{+FAILED}++ if $fail && $f->{assert};
352 2504 100       5201 $self->{+_PASSING} = 0 if $fail;
353              
354 2504 100       6246 my $code = $f->{control} ? $f->{control}->{terminate} : undef;
355 2504         4193 my $count = $self->{+COUNT};
356              
357 2504 100       5567 if (my $plan = $f->{plan}) {
358 549 100       2406 if ($plan->{skip}) {
    100          
359 24         139 $self->plan('SKIP');
360 24   100     210 $self->set_skip_reason($plan->{details} || 1);
361 24   50     158 $code ||= 0;
362             }
363             elsif ($plan->{none}) {
364 1         4 $self->plan('NO PLAN');
365             }
366             else {
367 524         2227 $self->plan($plan->{count});
368             }
369             }
370              
371 2504 50 66     8029 $e->callback($self) if $f->{control} && $f->{control}->{has_callback};
372              
373 2504 100       11764 $self->{+_FORMATTER}->write($e, $count, $f) if $self->{+_FORMATTER};
374              
375 2504 100       6912 if ($self->{+_LISTENERS}) {
376 772         1229 $_->{code}->($self, $e, $count, $f) for @{$self->{+_LISTENERS}};
  772         3189  
377             }
378              
379 2504 100 100     10785 if ($f->{control} && $f->{control}->{halt}) {
380 11   100     38 $code ||= 255;
381 11         59 $self->set_bailed_out($e);
382             }
383              
384 2504 100       5883 if (defined $code) {
385 35 100       388 $self->{+_FORMATTER}->terminate($e, $f) if $self->{+_FORMATTER};
386 35         196 $self->terminate($code, $e, $f);
387             }
388              
389 2474         24042 return $e;
390             }
391              
392             sub terminate {
393 15     15 0 54 my $self = shift;
394 15         57 my ($code) = @_;
395 15         294 exit($code);
396             }
397              
398             sub cull {
399 1222     1222 1 2475 my $self = shift;
400              
401 1222   100     3515 my $ipc = $self->{+IPC} || return;
402 744 100 66     3659 return if $self->{+PID} != $$ || $self->{+TID} != get_tid();
403              
404             # No need to do IPC checks on culled events
405 737         2664 $self->process($_) for $ipc->cull($self->{+HID});
406             }
407              
408             sub finalize {
409 468     468 0 1112 my $self = shift;
410 468         1257 my ($trace, $do_plan) = @_;
411              
412 468         2086 $self->cull();
413              
414 468         1176 my $plan = $self->{+_PLAN};
415 468         1239 my $count = $self->{+COUNT};
416 468         1303 my $failed = $self->{+FAILED};
417 468         1088 my $active = $self->{+ACTIVE};
418              
419             # return if NOTHING was done.
420 468 100 66     3531 unless ($active || $do_plan || defined($plan) || $count || $failed) {
      100        
      100        
      100        
421 12 50       140 $self->{+_FORMATTER}->finalize($plan, $count, $failed, 0, $self->is_subtest) if $self->{+_FORMATTER};
422 12         39 return;
423             }
424              
425 456 100       1714 unless ($self->{+ENDED}) {
426 453 100       1861 if ($self->{+_FOLLOW_UPS}) {
427 2         4 $_->($trace, $self) for reverse @{$self->{+_FOLLOW_UPS}};
  2         8  
428             }
429              
430             # These need to be refreshed now
431 453         1129 $plan = $self->{+_PLAN};
432 453         975 $count = $self->{+COUNT};
433 453         867 $failed = $self->{+FAILED};
434              
435 453 100 100     3745 if (($plan && $plan eq 'NO PLAN') || ($do_plan && !$plan)) {
      100        
      100        
436 312         2430 $self->send(
437             Test2::Event::Plan->new(
438             trace => $trace,
439             max => $count,
440             )
441             );
442             }
443 453         1901 $plan = $self->{+_PLAN};
444             }
445              
446 456         2066 my $frame = $trace->frame;
447 456 100       1604 if($self->{+ENDED}) {
448 3         5 my (undef, $ffile, $fline) = @{$self->{+ENDED}};
  3         12  
449 3         6 my (undef, $sfile, $sline) = @$frame;
450              
451 3         26 die <<" EOT"
452             Test already ended!
453             First End: $ffile line $fline
454             Second End: $sfile line $sline
455             EOT
456             }
457              
458 453         1202 $self->{+ENDED} = $frame;
459 453         1792 my $pass = $self->is_passing(); # Generate the final boolean.
460              
461 453 100       2727 $self->{+_FORMATTER}->finalize($plan, $count, $failed, $pass, $self->is_subtest) if $self->{+_FORMATTER};
462              
463 453         1280 return $pass;
464             }
465              
466             sub is_passing {
467 2196     2196 1 3748 my $self = shift;
468              
469 2196 100       5108 ($self->{+_PASSING}) = @_ if @_;
470              
471             # If we already failed just return 0.
472 2196 100       5820 my $pass = $self->{+_PASSING} or return 0;
473 1771 100       3944 return $self->{+_PASSING} = 0 if $self->{+FAILED};
474              
475 1764         2830 my $count = $self->{+COUNT};
476 1764         2617 my $ended = $self->{+ENDED};
477 1764         2836 my $plan = $self->{+_PLAN};
478              
479 1764 100 100     6202 return $pass if !$count && $plan && $plan =~ m/^SKIP$/;
      100        
480              
481 1723 100 100     7295 return $self->{+_PASSING} = 0
      100        
482             if $ended && (!$count || !$plan);
483              
484 1694 100 100     10281 return $pass unless $plan && $plan =~ m/^\d+$/;
485              
486 1548 100       3548 if ($ended) {
487 870 100       2145 return $self->{+_PASSING} = 0 if $count != $plan;
488             }
489             else {
490 678 100       1319 return $self->{+_PASSING} = 0 if $count > $plan;
491             }
492              
493 1544         5322 return $pass;
494             }
495              
496             sub plan {
497 1966     1966 1 3579 my $self = shift;
498              
499 1966 100       7732 return $self->{+_PLAN} unless @_;
500              
501 581         1519 my ($plan) = @_;
502              
503 581 50       1671 confess "You cannot unset the plan"
504             unless defined $plan;
505              
506             confess "You cannot change the plan"
507 581 100 100     2474 if $self->{+_PLAN} && $self->{+_PLAN} !~ m/^NO PLAN$/;
508              
509 580 100       4341 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 579         1910 $self->{+_PLAN} = $plan;
513             }
514              
515             sub check_plan {
516 123     123 1 249 my $self = shift;
517              
518 123 50       341 return undef unless $self->{+ENDED};
519 123   100     390 my $plan = $self->{+_PLAN} || return undef;
520              
521 114 50       610 return 1 if $plan !~ m/^\d+$/;
522              
523 114 100       472 return 1 if $plan == $self->{+COUNT};
524 1         3 return 0;
525             }
526              
527             sub DESTROY {
528 464     464   1899 my $self = shift;
529 464   100     15040 my $ipc = $self->{+IPC} || return;
530 51 100       257 return unless $$ == $self->{+PID};
531 50 50       167 return unless get_tid() == $self->{+TID};
532 50         252 $ipc->drop_hub($self->{+HID});
533             }
534              
535             1;
536              
537             __END__