File Coverage

blib/lib/Test/Stream/Hub.pm
Criterion Covered Total %
statement 207 207 100.0
branch 73 82 89.0
condition 56 84 66.6
subroutine 31 31 100.0
pod 17 23 73.9
total 384 427 89.9


line stmt bran cond sub pod time code
1             package Test::Stream::Hub;
2 109     109   2258 use strict;
  109         187  
  109         2569  
3 109     109   533 use warnings;
  109         177  
  109         2823  
4              
5 109     109   598 use Carp qw/carp croak/;
  109         171  
  109         5769  
6 109     109   56481 use Test::Stream::State;
  109         251  
  109         3371  
7 109     109   635 use Test::Stream::Util qw/get_tid/;
  109         183  
  109         826  
8              
9 109     109   580 use Scalar::Util qw/weaken/;
  109         182  
  109         6791  
10              
11             use Test::Stream::HashBase(
12 109         663 accessors => [qw{
13             pid tid hid ipc
14             state
15             no_ending
16             _todo _meta parent_todo
17             _mungers
18             _listeners
19             _follow_ups
20             _formatter
21             _context_init
22             _context_release
23             }],
24 109     109   547 );
  109         194  
25              
26             my $ID_POSTFIX = 1;
27             sub init {
28 520     520 0 914 my $self = shift;
29              
30 520         2099 $self->{+PID} = $$;
31 520         1293 $self->{+TID} = get_tid();
32 520         2619 $self->{+HID} = join '-', $self->{+PID}, $self->{+TID}, $ID_POSTFIX++;
33              
34 520         1349 $self->{+_TODO} = [];
35 520         1315 $self->{+_META} = {};
36              
37 520   33     4898 $self->{+STATE} ||= Test::Stream::State->new;
38              
39 520 100       1674 if (my $formatter = delete $self->{formatter}) {
40 5         18 $self->format($formatter);
41             }
42              
43 520 100       2163 if (my $ipc = $self->{+IPC}) {
44 136         989 $ipc->add_hub($self->{+HID});
45             }
46             }
47              
48             sub inherit {
49 240     240 1 363 my $self = shift;
50 240         456 my ($from, %params) = @_;
51              
52             $self->{+_FORMATTER} = $from->{+_FORMATTER}
53 240 100 33     1327 unless $self->{+_FORMATTER} || exists($params{formatter});
54              
55 240 100 66     1909 if ($from->{+IPC} && !$self->{+IPC} && !exists($params{ipc})) {
      100        
56 232         382 my $ipc = $from->{+IPC};
57 232         621 $self->{+IPC} = $ipc;
58 232         984 $ipc->add_hub($self->{+HID});
59             }
60              
61 240 100       963 if (my $ls = $from->{+_LISTENERS}) {
62 221         354 push @{$self->{+_LISTENERS}} => grep { $_->{inherit} } @$ls;
  221         827  
  294         736  
63             }
64              
65 240 100       1284 if (my $ms = $from->{+_MUNGERS}) {
66 12         12 push @{$self->{+_MUNGERS}} => grep { $_->{inherit} } @$ms;
  12         45  
  6         27  
67             }
68             }
69              
70             sub debug_todo {
71 3983     3983 0 10617 my ($self) = @_;
72 3983         6457 my $array = $self->{+_TODO};
73 3983   100     12204 pop @$array while @$array && !defined $array->[-1];
74             return (
75             parent_todo => $self->{+PARENT_TODO},
76 3983 100       32324 todo => @$array ? ${$array->[-1]} : undef,
  17         125  
77             )
78             }
79              
80             sub meta {
81 7     7 1 34 my $self = shift;
82 7         16 my ($key, $default) = @_;
83              
84 7 100       218 croak "Invalid key '" . (defined($key) ? $key : '(UNDEF)') . "'"
    100          
85             unless $key;
86              
87 5         11 my $exists = $self->{+_META}->{$key};
88 5 100 100     30 return undef unless $default || $exists;
89              
90 4 100       18 $self->{+_META}->{$key} = $default unless $exists;
91              
92 4         17 return $self->{+_META}->{$key};
93             }
94              
95             sub delete_meta {
96 3     3 1 15 my $self = shift;
97 3         12 my ($key) = @_;
98              
99 3 100       201 croak "Invalid key '" . (defined($key) ? $key : '(UNDEF)') . "'"
    100          
100             unless $key;
101              
102 1         6 delete $self->{+_META}->{$key};
103             }
104              
105             sub set_todo {
106 22     22 1 95 my $self = shift;
107 22         42 my ($reason) = @_;
108              
109 22 100       68 unless (defined wantarray) {
110 1         143 carp "set_todo(...) called in void context, todo not set!";
111 1         4 return;
112             }
113              
114 21 100       74 unless(defined $reason) {
115 1         101 carp "set_todo() called with undefined argument, todo not set!";
116 1         4 return;
117             }
118              
119 20         36 my $ref = \$reason;
120 20         36 push @{$self->{+_TODO}} => $ref;
  20         50  
121 20         82 weaken($self->{+_TODO}->[-1]);
122 20         56 return $ref;
123             }
124              
125             sub get_todo {
126 6     6 1 30 my $self = shift;
127 6         9 my $array = $self->{+_TODO};
128 6   100     42 pop @$array while @$array && !defined($array->[-1]);
129 6 100       28 return undef unless @$array;
130 3         5 return ${$array->[-1]};
  3         25  
131             }
132              
133             sub format {
134 597     597 1 1107 my $self = shift;
135              
136 597         1100 my $old = $self->{+_FORMATTER};
137 597 100       2209 ($self->{+_FORMATTER}) = @_ if @_;
138              
139 597         3455 return $old;
140             }
141              
142             sub is_local {
143 316     316 0 507 my $self = shift;
144             return $$ == $self->{+PID}
145 316   33     2864 && get_tid() == $self->{+TID};
146             }
147              
148             sub listen {
149 680     680 1 1195 my $self = shift;
150 680         1331 my ($sub, %params) = @_;
151              
152             carp "Useless addition of a listener in a child process or thread!"
153 680 50 33     4141 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
154              
155 680 100 66     3722 croak "listen only takes coderefs for arguments, got '$sub'"
156             unless ref $sub && ref $sub eq 'CODE';
157              
158 679         871 push @{$self->{+_LISTENERS}} => { %params, code => $sub };
  679         2723  
159              
160 679         2133 $sub; # Intentional return.
161             }
162              
163             sub unlisten {
164 313     313 1 509 my $self = shift;
165              
166             carp "Useless removal of a listener in a child process or thread!"
167 313 50 33     1920 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
168              
169 313         632 my %subs = map {$_ => $_} @_;
  313         1471  
170              
171 313         513 @{$self->{+_LISTENERS}} = grep { !$subs{$_->{code}} } @{$self->{+_LISTENERS}};
  313         2585  
  650         2000  
  313         688  
172             }
173              
174             sub munge {
175 10     10 1 52 my $self = shift;
176 10         19 my ($sub, %params) = @_;
177              
178             carp "Useless addition of a munger in a child process or thread!"
179 10 50 33     84 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
180              
181 10 100 66     209 croak "munge only takes coderefs for arguments, got '$sub'"
182             unless ref $sub && ref $sub eq 'CODE';
183              
184 9         14 push @{$self->{+_MUNGERS}} => { %params, code => $sub };
  9         40  
185              
186 9         69 $sub; # Intentional Return
187             }
188              
189             sub unmunge {
190 1     1 1 6 my $self = shift;
191             carp "Useless removal of a munger in a child process or thread!"
192 1 50 33     13 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
193 1         4 my %subs = map {$_ => $_} @_;
  1         7  
194 1         3 @{$self->{+_MUNGERS}} = grep { !$subs{$_->{code}} } @{$self->{+_MUNGERS}};
  1         6  
  2         7  
  1         2  
195             }
196              
197             sub follow_up {
198 38     38 0 103 my $self = shift;
199 38         84 my ($sub) = @_;
200              
201             carp "Useless addition of a follow-up in a child process or thread!"
202 38 50 33     373 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
203              
204 38 100 66     728 croak "follow_up only takes coderefs for arguments, got '$sub'"
205             unless ref $sub && ref $sub eq 'CODE';
206              
207 36         81 push @{$self->{+_FOLLOW_UPS}} => $sub;
  36         175  
208             }
209              
210             sub add_context_init {
211 1     1 1 8 my $self = shift;
212 1         2 my ($sub) = @_;
213              
214 1 50 33     9 croak "add_context_init only takes coderefs for arguments, got '$sub'"
215             unless ref $sub && ref $sub eq 'CODE';
216              
217 1         2 push @{$self->{+_CONTEXT_INIT}} => $sub;
  1         4  
218              
219 1         3 $sub; # Intentional return.
220             }
221              
222             sub remove_context_init {
223 1     1 1 9 my $self = shift;
224 1         4 my %subs = map {$_ => $_} @_;
  1         4  
225 1         3 @{$self->{+_CONTEXT_INIT}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_INIT}};
  1         5  
  1         4  
  1         3  
226             }
227              
228             sub add_context_release {
229 1     1 1 8 my $self = shift;
230 1         2 my ($sub) = @_;
231              
232 1 50 33     18 croak "add_context_release only takes coderefs for arguments, got '$sub'"
233             unless ref $sub && ref $sub eq 'CODE';
234              
235 1         2 push @{$self->{+_CONTEXT_RELEASE}} => $sub;
  1         3  
236              
237 1         3 $sub; # Intentional return.
238             }
239              
240             sub remove_context_release {
241 1     1 1 5 my $self = shift;
242 1         7 my %subs = map {$_ => $_} @_;
  1         5  
243 1         3 @{$self->{+_CONTEXT_RELEASE}} = grep { !$subs{$_} == $_ } @{$self->{+_CONTEXT_RELEASE}};
  1         4  
  1         4  
  1         2  
244             }
245              
246             sub send {
247 3599     3599 1 7408 my $self = shift;
248 3599         5129 my ($e) = @_;
249              
250 3599   100     9907 my $ipc = $self->{+IPC} || return $self->process($e);
251              
252 3500 100       11178 if($e->global) {
253 25         106 $ipc->send('GLOBAL', $e);
254 25         102 return $self->process($e);
255             }
256              
257             return $ipc->send($self->{+HID}, $e)
258 3475 100 66     19291 if $$ != $self->{+PID} || get_tid() != $self->{+TID};
259              
260 3469         9793 $self->process($e);
261             }
262              
263             sub process {
264 3598     3598 1 5209 my $self = shift;
265 3598         4947 my ($e) = @_;
266              
267 3598 100       8587 if ($self->{+_MUNGERS}) {
268 12         23 for (@{$self->{+_MUNGERS}}) {
  12         34  
269 14         43 $_->{code}->($self, $e);
270 14 100       193 return unless $e;
271             }
272             }
273              
274 3589         5114 my $state = $self->{+STATE};
275 3589         10712 $e->update_state($state);
276 3589         11575 my $count = $state->count;
277              
278 3589 100       19878 $self->{+_FORMATTER}->write($e, $count) if $self->{+_FORMATTER};
279              
280 3589 100       10575 if ($self->{+_LISTENERS}) {
281 2023         2540 $_->{code}->($self, $e, $count) for @{$self->{+_LISTENERS}};
  2023         9579  
282             }
283              
284 3589         11376 my $code = $e->terminate;
285 3589 100       8703 $self->terminate($code, $e) if defined $code;
286              
287 3563         16335 return $e;
288             }
289              
290             sub terminate {
291 3     3 0 6 my $self = shift;
292 3         6 my ($code) = @_;
293 3         31 exit($code);
294             }
295              
296             sub cull {
297 813     813 1 1287 my $self = shift;
298              
299 813   100     2518 my $ipc = $self->{+IPC} || return;
300 791 50 33     4773 return if $self->{+PID} != $$ || $self->{+TID} != get_tid();
301              
302             # No need to do IPC checks on culled events
303 791         3372 $self->process($_) for $ipc->cull($self->{+HID});
304             }
305              
306             sub finalize {
307 348     348 0 5207 my $self = shift;
308 348         674 my ($dbg, $do_plan) = @_;
309              
310 348         1158 $self->cull();
311 348         1282 my $state = $self->{+STATE};
312              
313 348         1621 my $plan = $state->plan;
314 348         1253 my $count = $state->count;
315 348         2013 my $failed = $state->failed;
316              
317             # return if NOTHING was done.
318 348 100 100     2368 return unless $do_plan || defined($plan) || $count || $failed;
      100        
      100        
319              
320 336 100       1196 unless ($state->ended) {
321 334 100       2153 if ($self->{+_FOLLOW_UPS}) {
322 33         76 $_->($dbg, $self) for reverse @{$self->{+_FOLLOW_UPS}};
  33         247  
323             }
324              
325             # These need to be refreshed now
326 333         1173 $plan = $state->plan;
327 333         1117 $count = $state->count;
328 333         1602 $failed = $state->failed;
329              
330 333 100 100     3914 if (($plan && $plan eq 'NO PLAN') || ($do_plan && !$plan)) {
      100        
      66        
331 316         2675 $self->send(
332             Test::Stream::Event::Plan->new(
333             debug => $dbg,
334             max => $count,
335             )
336             );
337 316         1600 $plan = $state->plan;
338             }
339             }
340              
341 335         1394 $state->finish($dbg->frame);
342             }
343              
344             sub DESTROY {
345 411     411   1218 my $self = shift;
346 411   100     1729 my $ipc = $self->{+IPC} || return;
347 379 100       1412 return unless $$ == $self->{+PID};
348 378 50       1034 return unless get_tid() == $self->{+TID};
349              
350 378         1306 local $?;
351 378         1787 $ipc->drop_hub($self->{+HID});
352             }
353              
354             1;
355              
356             __END__