File Coverage

blib/lib/Test/Stream/Hub.pm
Criterion Covered Total %
statement 229 232 98.7
branch 82 94 87.2
condition 60 93 64.5
subroutine 33 33 100.0
pod 17 25 68.0
total 421 477 88.2


line stmt bran cond sub pod time code
1             package Test::Stream::Hub;
2 109     109   693 use strict;
  109         113  
  109         2388  
3 109     109   327 use warnings;
  109         102  
  109         2247  
4              
5 109     109   308 use Carp qw/carp croak/;
  109         114  
  109         4288  
6 109     109   35866 use Test::Stream::State();
  109         172  
  109         1984  
7 109     109   494 use Test::Stream::Util qw/get_tid/;
  109         104  
  109         554  
8              
9 109     109   421 use Scalar::Util qw/weaken/;
  109         114  
  109         5360  
10              
11             use Test::Stream::HashBase(
12 109         460 accessors => [qw{
13             pid tid hid ipc
14             state
15             no_ending
16             _todo _meta parent_todo
17             _mungers
18             _filters
19             _listeners
20             _follow_ups
21             _formatter
22             _context_init
23             _context_release
24             }],
25 109     109   389 );
  109         122  
26              
27             my $ID_POSTFIX = 1;
28             sub init {
29 524     524 0 620 my $self = shift;
30              
31 524         1480 $self->{+PID} = $$;
32 524         790 $self->{+TID} = get_tid();
33 524         1781 $self->{+HID} = join '-', $self->{+PID}, $self->{+TID}, $ID_POSTFIX++;
34              
35 524         947 $self->{+_TODO} = [];
36 524         847 $self->{+_META} = {};
37              
38 524   33     3422 $self->{+STATE} ||= Test::Stream::State->new;
39              
40 524 100       1154 if (my $formatter = delete $self->{formatter}) {
41 5         14 $self->format($formatter);
42             }
43              
44 524 100       1357 if (my $ipc = $self->{+IPC}) {
45 137         415 $ipc->add_hub($self->{+HID});
46             }
47             }
48              
49             sub inherit {
50 241     241 1 253 my $self = shift;
51 241         287 my ($from, %params) = @_;
52              
53             $self->{+_FORMATTER} = $from->{+_FORMATTER}
54 241 100 33     967 unless $self->{+_FORMATTER} || exists($params{formatter});
55              
56 241 100 66     1460 if ($from->{+IPC} && !$self->{+IPC} && !exists($params{ipc})) {
      100        
57 233         238 my $ipc = $from->{+IPC};
58 233         436 $self->{+IPC} = $ipc;
59 233         670 $ipc->add_hub($self->{+HID});
60             }
61              
62 241 100       823 if (my $ls = $from->{+_LISTENERS}) {
63 222         254 push @{$self->{+_LISTENERS}} => grep { $_->{inherit} } @$ls;
  222         710  
  295         524  
64             }
65              
66 241 50       528 if (my $ms = $from->{+_MUNGERS}) {
67 0         0 push @{$self->{+_MUNGERS}} => grep { $_->{inherit} } @$ms;
  0         0  
  0         0  
68             }
69              
70 241 100       809 if (my $fs = $from->{+_FILTERS}) {
71 12         9 push @{$self->{+_FILTERS}} => grep { $_->{inherit} } @$fs;
  12         36  
  6         24  
72             }
73             }
74              
75             sub debug_todo {
76 4014     4014 0 7069 my ($self) = @_;
77 4014         4440 my $array = $self->{+_TODO};
78 4014   100     8273 pop @$array while @$array && !defined $array->[-1];
79             return (
80             parent_todo => $self->{+PARENT_TODO},
81 4014 100       22482 todo => @$array ? ${$array->[-1]} : undef,
  17         95  
82             )
83             }
84              
85             sub meta {
86 7     7 1 22 my $self = shift;
87 7         11 my ($key, $default) = @_;
88              
89 7 100       161 croak "Invalid key '" . (defined($key) ? $key : '(UNDEF)') . "'"
    100          
90             unless $key;
91              
92 5         30 my $exists = $self->{+_META}->{$key};
93 5 100 100     88 return undef unless $default || $exists;
94              
95 4 100       9 $self->{+_META}->{$key} = $default unless $exists;
96              
97 4         12 return $self->{+_META}->{$key};
98             }
99              
100             sub delete_meta {
101 3     3 1 14 my $self = shift;
102 3         3 my ($key) = @_;
103              
104 3 100       139 croak "Invalid key '" . (defined($key) ? $key : '(UNDEF)') . "'"
    100          
105             unless $key;
106              
107 1         2 delete $self->{+_META}->{$key};
108             }
109              
110             sub set_todo {
111 22     22 1 79 my $self = shift;
112 22         34 my ($reason) = @_;
113              
114 22 100       54 unless (defined wantarray) {
115 1         101 carp "set_todo(...) called in void context, todo not set!";
116 1         2 return;
117             }
118              
119 21 100       50 unless(defined $reason) {
120 1         67 carp "set_todo() called with undefined argument, todo not set!";
121 1         3 return;
122             }
123              
124 20         35 my $ref = \$reason;
125 20         29 push @{$self->{+_TODO}} => $ref;
  20         44  
126 20         63 weaken($self->{+_TODO}->[-1]);
127 20         42 return $ref;
128             }
129              
130             sub get_todo {
131 6     6 1 20 my $self = shift;
132 6         6 my $array = $self->{+_TODO};
133 6   100     31 pop @$array while @$array && !defined($array->[-1]);
134 6 100       18 return undef unless @$array;
135 3         3 return ${$array->[-1]};
  3         15  
136             }
137              
138             sub format {
139 599     599 1 683 my $self = shift;
140              
141 599         761 my $old = $self->{+_FORMATTER};
142 599 100       1506 ($self->{+_FORMATTER}) = @_ if @_;
143              
144 599         2062 return $old;
145             }
146              
147             sub is_local {
148 317     317 0 255 my $self = shift;
149             return $$ == $self->{+PID}
150 317   33     1996 && get_tid() == $self->{+TID};
151             }
152              
153             sub listen {
154 684     684 1 709 my $self = shift;
155 684         915 my ($sub, %params) = @_;
156              
157             carp "Useless addition of a listener in a child process or thread!"
158 684 50 33     3194 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
159              
160 684 100 66     2715 croak "listen only takes coderefs for arguments, got '$sub'"
161             unless ref $sub && ref $sub eq 'CODE';
162              
163 683         571 push @{$self->{+_LISTENERS}} => { %params, code => $sub };
  683         2007  
164              
165 683         1328 $sub; # Intentional return.
166             }
167              
168             sub unlisten {
169 314     314 1 320 my $self = shift;
170              
171             carp "Useless removal of a listener in a child process or thread!"
172 314 50 33     1337 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
173              
174 314         421 my %subs = map {$_ => $_} @_;
  314         1047  
175              
176 314         302 @{$self->{+_LISTENERS}} = grep { !$subs{$_->{code}} } @{$self->{+_LISTENERS}};
  314         1849  
  652         1107  
  314         431  
177             }
178              
179             sub munge {
180 4     4 1 30 my $self = shift;
181 4         6 my ($sub, %params) = @_;
182              
183 4         287 carp "use of mungers is deprecated, look at filters instead. mungers will be removed in the near future.";
184              
185             carp "Useless addition of a munger in a child process or thread!"
186 4 50 33     270 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
187              
188 4 100 66     107 croak "munge only takes coderefs for arguments, got '$sub'"
189             unless ref $sub && ref $sub eq 'CODE';
190              
191 3         5 push @{$self->{+_MUNGERS}} => { %params, code => $sub };
  3         10  
192              
193 3         7 $sub; # Intentional Return
194             }
195              
196             sub unmunge {
197 1     1 1 6 my $self = shift;
198             carp "Useless removal of a munger in a child process or thread!"
199 1 50 33     11 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
200 1         3 my %subs = map {$_ => $_} @_;
  1         3  
201 1         2 @{$self->{+_MUNGERS}} = grep { !$subs{$_->{code}} } @{$self->{+_MUNGERS}};
  1         3  
  2         4  
  1         3  
202             }
203              
204             sub filter {
205 10     10 0 48 my $self = shift;
206 10         18 my ($sub, %params) = @_;
207              
208             carp "Useless addition of a filter in a child process or thread!"
209 10 50 33     58 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
210              
211 10 100 66     174 croak "filter only takes coderefs for arguments, got '$sub'"
212             unless ref $sub && ref $sub eq 'CODE';
213              
214 9         8 push @{$self->{+_FILTERS}} => { %params, code => $sub };
  9         41  
215              
216 9         25 $sub; # Intentional Return
217             }
218              
219             sub unfilter {
220 1     1 0 5 my $self = shift;
221             carp "Useless removal of a filter in a child process or thread!"
222 1 50 33     12 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
223 1         2 my %subs = map {$_ => $_} @_;
  1         5  
224 1         2 @{$self->{+_FILTERS}} = grep { !$subs{$_->{code}} } @{$self->{+_FILTERS}};
  1         4  
  2         6  
  1         3  
225             }
226              
227             sub follow_up {
228 38     38 0 73 my $self = shift;
229 38         53 my ($sub) = @_;
230              
231             carp "Useless addition of a follow-up in a child process or thread!"
232 38 50 33     263 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
233              
234 38 100 66     467 croak "follow_up only takes coderefs for arguments, got '$sub'"
235             unless ref $sub && ref $sub eq 'CODE';
236              
237 36         54 push @{$self->{+_FOLLOW_UPS}} => $sub;
  36         119  
238             }
239              
240             sub add_context_init {
241 1     1 1 8 my $self = shift;
242 1         2 my ($sub) = @_;
243              
244 1 50 33     6 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 6 my $self = shift;
254 1         2 my %subs = map {$_ => $_} @_;
  1         5  
255 1         2 @{$self->{+_CONTEXT_INIT}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_INIT}};
  1         3  
  1         8  
  1         2  
256             }
257              
258             sub add_context_release {
259 1     1 1 6 my $self = shift;
260 1         2 my ($sub) = @_;
261              
262 1 50 33     11 croak "add_context_release only takes coderefs for arguments, got '$sub'"
263             unless ref $sub && ref $sub eq 'CODE';
264              
265 1         1 push @{$self->{+_CONTEXT_RELEASE}} => $sub;
  1         3  
266              
267 1         2 $sub; # Intentional return.
268             }
269              
270             sub remove_context_release {
271 1     1 1 4 my $self = shift;
272 1         1 my %subs = map {$_ => $_} @_;
  1         3  
273 1         2 @{$self->{+_CONTEXT_RELEASE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_RELEASE}};
  1         3  
  1         2  
  1         2  
274             }
275              
276             sub send {
277 3636     3636 1 4608 my $self = shift;
278 3636         3164 my ($e) = @_;
279              
280 3636   100     6787 my $ipc = $self->{+IPC} || return $self->process($e);
281              
282 3528 100       7747 if($e->global) {
283 25         77 $ipc->send('GLOBAL', $e);
284 25         81 return $self->process($e);
285             }
286              
287             return $ipc->send($self->{+HID}, $e)
288 3503 100 66     14050 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
289              
290 3497         7037 $self->process($e);
291             }
292              
293             sub process {
294 3635     3635 1 2907 my $self = shift;
295 3635         2942 my ($e) = @_;
296              
297 3635 100       5518 if ($self->{+_MUNGERS}) {
298 6         5 for (@{$self->{+_MUNGERS}}) {
  6         14  
299 8         14 $_->{code}->($self, $e);
300 8 100       23 return unless $e;
301             }
302             }
303              
304 3632 100       4946 if ($self->{+_FILTERS}) {
305 12         18 for (@{$self->{+_FILTERS}}) {
  12         25  
306 14         31 $e = $_->{code}->($self, $e);
307 14 100       70 return unless $e;
308             }
309             }
310              
311 3623         3118 my $state = $self->{+STATE};
312 3623         7791 $e->update_state($state);
313 3623         7829 my $count = $state->count;
314              
315 3623 100       13360 $self->{+_FORMATTER}->write($e, $count) if $self->{+_FORMATTER};
316              
317 3623 100       8067 if ($self->{+_LISTENERS}) {
318 2044         1487 $_->{code}->($self, $e, $count) for @{$self->{+_LISTENERS}};
  2044         7035  
319             }
320              
321 3623         8718 my $code = $e->terminate;
322 3623 100       5587 $self->terminate($code, $e) if defined $code;
323              
324 3597         11305 return $e;
325             }
326              
327             sub terminate {
328 3     3 0 4 my $self = shift;
329 3         4 my ($code) = @_;
330 3         22 exit($code);
331             }
332              
333             sub cull {
334 816     816 1 813 my $self = shift;
335              
336 816   100     1758 my $ipc = $self->{+IPC} || return;
337 794 50 33     3472 return if $self->{+PID} != $$ || $self->{+TID} != get_tid();
338              
339             # No need to do IPC checks on culled events
340 794         2319 $self->process($_) for $ipc->cull($self->{+HID});
341             }
342              
343             sub finalize {
344 349     349 0 3661 my $self = shift;
345 349         821 my ($dbg, $do_plan) = @_;
346              
347 349         802 $self->cull();
348 349         591 my $state = $self->{+STATE};
349              
350 349         1483 my $plan = $state->plan;
351 349         933 my $count = $state->count;
352 349         1323 my $failed = $state->failed;
353              
354             # return if NOTHING was done.
355 349 100 100     1567 return unless $do_plan || defined($plan) || $count || $failed;
      100        
      100        
356              
357 337 100       1036 unless ($state->ended) {
358 335 100       1591 if ($self->{+_FOLLOW_UPS}) {
359 33         50 $_->($dbg, $self) for reverse @{$self->{+_FOLLOW_UPS}};
  33         171  
360             }
361              
362             # These need to be refreshed now
363 334         753 $plan = $state->plan;
364 334         707 $count = $state->count;
365 334         1018 $failed = $state->failed;
366              
367 334 100 100     2676 if (($plan && $plan eq 'NO PLAN') || ($do_plan && !$plan)) {
      100        
      66        
368 317         2054 $self->send(
369             Test::Stream::Event::Plan->new(
370             debug => $dbg,
371             max => $count,
372             )
373             );
374 317         1180 $plan = $state->plan;
375             }
376             }
377              
378 336         1045 $state->finish($dbg->frame);
379             }
380              
381             sub DESTROY {
382 415     415   726 my $self = shift;
383 415   100     1132 my $ipc = $self->{+IPC} || return;
384 381 100       1058 return unless $$ == $self->{+PID};
385 380 50       718 return unless get_tid() == $self->{+TID};
386              
387 380         994 local $?;
388 380         1154 $ipc->drop_hub($self->{+HID});
389             }
390              
391             1;
392              
393             __END__