Commit | Line | Data |
---|---|---|
518760d9 CG |
1 | package Test::Stream; |
2 | use strict; | |
3 | use warnings; | |
4 | ||
136323e4 | 5 | our $VERSION = '1.301001_076'; |
518760d9 CG |
6 | $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval) |
7 | ||
4e88444f | 8 | use Test::Stream::Context qw/context/; |
518760d9 CG |
9 | use Test::Stream::Threads; |
10 | use Test::Stream::IOSets; | |
11 | use Test::Stream::Util qw/try/; | |
12 | use Test::Stream::Carp qw/croak confess carp/; | |
13 | use Test::Stream::Meta qw/MODERN ENCODING init_tester/; | |
14 | ||
15 | use Test::Stream::ArrayBase( | |
16 | accessors => [qw{ | |
17 | no_ending no_diag no_header | |
18 | pid tid | |
19 | state | |
20 | subtests subtest_todo subtest_exception | |
21 | subtest_tap_instant | |
22 | subtest_tap_delayed | |
23 | mungers | |
24 | listeners | |
25 | follow_ups | |
26 | bailed_out | |
27 | exit_on_disruption | |
28 | use_tap use_legacy _use_fork | |
29 | use_numbers | |
30 | io_sets | |
31 | event_id | |
32 | in_subthread | |
33 | }], | |
34 | ); | |
35 | ||
36 | sub STATE_COUNT() { 0 } | |
37 | sub STATE_FAILED() { 1 } | |
38 | sub STATE_PLAN() { 2 } | |
39 | sub STATE_PASSING() { 3 } | |
40 | sub STATE_LEGACY() { 4 } | |
41 | sub STATE_ENDED() { 5 } | |
42 | ||
43 | sub OUT_STD() { 0 } | |
44 | sub OUT_ERR() { 1 } | |
45 | sub OUT_TODO() { 2 } | |
46 | ||
47 | use Test::Stream::Exporter; | |
48 | exports qw/ | |
49 | OUT_STD OUT_ERR OUT_TODO | |
50 | STATE_COUNT STATE_FAILED STATE_PLAN STATE_PASSING STATE_LEGACY STATE_ENDED | |
51 | /; | |
4e88444f | 52 | default_exports qw/ cull tap_encoding context /; |
518760d9 CG |
53 | Test::Stream::Exporter->cleanup; |
54 | ||
55 | sub tap_encoding { | |
56 | my ($encoding) = @_; | |
57 | ||
58 | require Encode; | |
59 | ||
60 | croak "encoding '$encoding' is not valid, or not available" | |
61 | unless $encoding eq 'legacy' || Encode::find_encoding($encoding); | |
62 | ||
63 | require Test::Stream::Context; | |
64 | my $ctx = Test::Stream::Context::context(); | |
65 | $ctx->stream->io_sets->init_encoding($encoding); | |
66 | ||
67 | my $meta = init_tester($ctx->package); | |
68 | $meta->[ENCODING] = $encoding; | |
69 | } | |
70 | ||
71 | sub cull { | |
518760d9 CG |
72 | my $ctx = Test::Stream::Context::context(); |
73 | $ctx->stream->fork_cull(); | |
74 | } | |
75 | ||
76 | sub before_import { | |
77 | my $class = shift; | |
78 | my ($importer, $list) = @_; | |
79 | ||
80 | if (@$list && $list->[0] eq '-internal') { | |
81 | shift @$list; | |
82 | return; | |
83 | } | |
84 | ||
85 | my $meta = init_tester($importer); | |
86 | $meta->[MODERN] = 1; | |
87 | ||
88 | my $other = []; | |
89 | my $idx = 0; | |
90 | my $stream = $class->shared; | |
91 | ||
92 | while ($idx <= $#{$list}) { | |
93 | my $item = $list->[$idx++]; | |
94 | next unless $item; | |
95 | ||
96 | if ($item eq 'subtest_tap') { | |
97 | my $val = $list->[$idx++]; | |
98 | if (!$val || $val eq 'none') { | |
99 | $stream->set_subtest_tap_instant(0); | |
100 | $stream->set_subtest_tap_delayed(0); | |
101 | } | |
102 | elsif ($val eq 'instant') { | |
103 | $stream->set_subtest_tap_instant(1); | |
104 | $stream->set_subtest_tap_delayed(0); | |
105 | } | |
106 | elsif ($val eq 'delayed') { | |
107 | $stream->set_subtest_tap_instant(0); | |
108 | $stream->set_subtest_tap_delayed(1); | |
109 | } | |
110 | elsif ($val eq 'both') { | |
111 | $stream->set_subtest_tap_instant(1); | |
112 | $stream->set_subtest_tap_delayed(1); | |
113 | } | |
114 | else { | |
115 | croak "'$val' is not a valid option for '$item'"; | |
116 | } | |
117 | } | |
118 | elsif ($item eq 'utf8') { | |
119 | $stream->io_sets->init_encoding('utf8'); | |
120 | $meta->[ENCODING] = 'utf8'; | |
121 | } | |
122 | elsif ($item eq 'encoding') { | |
123 | my $encoding = $list->[$idx++]; | |
124 | ||
125 | croak "encoding '$encoding' is not valid, or not available" | |
126 | unless Encode::find_encoding($encoding); | |
127 | ||
128 | $stream->io_sets->init_encoding($encoding); | |
129 | $meta->[ENCODING] = $encoding; | |
130 | } | |
131 | elsif ($item eq 'enable_fork') { | |
132 | $stream->use_fork; | |
133 | } | |
134 | else { | |
135 | push @$other => $item; | |
136 | } | |
137 | } | |
138 | ||
139 | @$list = @$other; | |
140 | ||
141 | return; | |
142 | } | |
143 | ||
144 | sub plan { $_[0]->[STATE]->[-1]->[STATE_PLAN] } | |
145 | sub count { $_[0]->[STATE]->[-1]->[STATE_COUNT] } | |
146 | sub failed { $_[0]->[STATE]->[-1]->[STATE_FAILED] } | |
147 | sub ended { $_[0]->[STATE]->[-1]->[STATE_ENDED] } | |
148 | sub legacy { $_[0]->[STATE]->[-1]->[STATE_LEGACY] } | |
149 | ||
150 | sub is_passing { | |
151 | my $self = shift; | |
152 | ||
153 | if (@_) { | |
154 | ($self->[STATE]->[-1]->[STATE_PASSING]) = @_; | |
155 | } | |
156 | ||
157 | my $current = $self->[STATE]->[-1]->[STATE_PASSING]; | |
158 | ||
159 | my $plan = $self->[STATE]->[-1]->[STATE_PLAN]; | |
160 | return $current if $self->[STATE]->[-1]->[STATE_ENDED]; | |
161 | return $current unless $plan; | |
162 | return $current unless $plan->max; | |
163 | return $current if $plan->directive && $plan->directive eq 'NO PLAN'; | |
164 | return $current unless $self->[STATE]->[-1]->[STATE_COUNT] > $plan->max; | |
165 | ||
166 | return $self->[STATE]->[-1]->[STATE_PASSING] = 0; | |
167 | } | |
168 | ||
169 | sub init { | |
170 | my $self = shift; | |
171 | ||
172 | $self->[PID] = $$; | |
173 | $self->[TID] = get_tid(); | |
174 | $self->[STATE] = [[0, 0, undef, 1]]; | |
175 | $self->[USE_TAP] = 1; | |
176 | $self->[USE_NUMBERS] = 1; | |
177 | $self->[IO_SETS] = Test::Stream::IOSets->new; | |
178 | $self->[EVENT_ID] = 1; | |
179 | $self->[NO_ENDING] = 1; | |
180 | $self->[SUBTESTS] = []; | |
181 | ||
182 | $self->[SUBTEST_TAP_INSTANT] = 1; | |
183 | $self->[SUBTEST_TAP_DELAYED] = 0; | |
184 | ||
185 | $self->use_fork if USE_THREADS; | |
186 | ||
187 | $self->[EXIT_ON_DISRUPTION] = 1; | |
188 | } | |
189 | ||
190 | { | |
191 | my ($root, @stack, $magic); | |
192 | ||
193 | END { | |
194 | $root->fork_cull if $root && $root->_use_fork && $$ == $root->[PID]; | |
195 | $magic->do_magic($root) if $magic && $root && !$root->[NO_ENDING] | |
196 | } | |
197 | ||
198 | sub _stack { @stack } | |
199 | ||
200 | sub shared { | |
201 | my ($class) = @_; | |
202 | return $stack[-1] if @stack; | |
203 | ||
204 | @stack = ($root = $class->new(0)); | |
205 | $root->[NO_ENDING] = 0; | |
206 | ||
207 | require Test::Stream::Context; | |
208 | require Test::Stream::Event::Finish; | |
209 | require Test::Stream::ExitMagic; | |
210 | require Test::Stream::ExitMagic::Context; | |
211 | ||
212 | $magic = Test::Stream::ExitMagic->new; | |
213 | ||
214 | return $root; | |
215 | } | |
216 | ||
217 | sub clear { | |
218 | $root->[NO_ENDING] = 1; | |
219 | $root = undef; | |
220 | $magic = undef; | |
221 | @stack = (); | |
222 | } | |
223 | ||
224 | sub intercept_start { | |
225 | my $class = shift; | |
226 | my ($new) = @_; | |
227 | ||
228 | my $old = $stack[-1]; | |
229 | ||
230 | unless($new) { | |
231 | $new = $class->new(); | |
232 | ||
233 | $new->set_exit_on_disruption(0); | |
234 | $new->set_use_tap(0); | |
235 | $new->set_use_legacy(0); | |
236 | } | |
237 | ||
238 | push @stack => $new; | |
239 | ||
240 | return ($new, $old); | |
241 | } | |
242 | ||
243 | sub intercept_stop { | |
244 | my $class = shift; | |
245 | my ($current) = @_; | |
246 | croak "Stream stack inconsistency" unless $current == $stack[-1]; | |
247 | pop @stack; | |
248 | } | |
249 | } | |
250 | ||
251 | sub intercept { | |
252 | my $class = shift; | |
253 | my ($code) = @_; | |
254 | ||
255 | croak "The first argument to intercept must be a coderef" | |
256 | unless $code && ref $code && ref $code eq 'CODE'; | |
257 | ||
258 | my ($new, $old) = $class->intercept_start(); | |
259 | my ($ok, $error) = try { $code->($new, $old) }; | |
260 | $class->intercept_stop($new); | |
261 | ||
262 | die $error unless $ok; | |
263 | return $ok; | |
264 | } | |
265 | ||
266 | sub listen { | |
267 | my $self = shift; | |
268 | for my $sub (@_) { | |
269 | next unless $sub; | |
270 | ||
271 | croak "listen only takes coderefs for arguments, got '$sub'" | |
272 | unless ref $sub && ref $sub eq 'CODE'; | |
273 | ||
274 | push @{$self->[LISTENERS]} => $sub; | |
275 | } | |
276 | } | |
277 | ||
278 | sub munge { | |
279 | my $self = shift; | |
280 | for my $sub (@_) { | |
281 | next unless $sub; | |
282 | ||
283 | croak "munge only takes coderefs for arguments, got '$sub'" | |
284 | unless ref $sub && ref $sub eq 'CODE'; | |
285 | ||
286 | push @{$self->[MUNGERS]} => $sub; | |
287 | } | |
288 | } | |
289 | ||
290 | sub follow_up { | |
291 | my $self = shift; | |
292 | for my $sub (@_) { | |
293 | next unless $sub; | |
294 | ||
295 | croak "follow_up only takes coderefs for arguments, got '$sub'" | |
296 | unless ref $sub && ref $sub eq 'CODE'; | |
297 | ||
298 | push @{$self->[FOLLOW_UPS]} => $sub; | |
299 | } | |
300 | } | |
301 | ||
302 | sub use_fork { | |
303 | require File::Temp; | |
304 | require Storable; | |
305 | ||
306 | $_[0]->[_USE_FORK] ||= File::Temp::tempdir(CLEANUP => 0); | |
307 | confess "Could not get a temp dir" unless $_[0]->[_USE_FORK]; | |
308 | if ($^O eq 'VMS') { | |
309 | require VMS::Filespec; | |
310 | $_[0]->[_USE_FORK] = VMS::Filespec::unixify($_[0]->[_USE_FORK]); | |
311 | } | |
312 | return 1; | |
313 | } | |
314 | ||
315 | sub fork_out { | |
316 | my $self = shift; | |
317 | ||
318 | my $tempdir = $self->[_USE_FORK]; | |
319 | confess "Fork support has not been turned on!" unless $tempdir; | |
320 | ||
321 | my $tid = get_tid(); | |
322 | ||
323 | for my $event (@_) { | |
324 | next unless $event; | |
325 | next if $event->isa('Test::Stream::Event::Finish'); | |
326 | ||
327 | # First write the file, then rename it so that it is not read before it is ready. | |
328 | my $name = $tempdir . "/$$-$tid-" . ($self->[EVENT_ID]++); | |
329 | my ($ret, $err) = try { Storable::store($event, $name) }; | |
330 | # Temporary to debug an error on one cpan-testers box | |
331 | unless ($ret) { | |
332 | require Data::Dumper; | |
333 | confess(Data::Dumper::Dumper({ error => $err, event => $event})); | |
334 | } | |
335 | rename($name, "$name.ready") || confess "Could not rename file '$name' -> '$name.ready'"; | |
336 | } | |
337 | } | |
338 | ||
339 | sub fork_cull { | |
340 | my $self = shift; | |
341 | ||
342 | confess "fork_cull() can only be called from the parent process!" | |
343 | if $$ != $self->[PID]; | |
344 | ||
345 | confess "fork_cull() can only be called from the parent thread!" | |
346 | if get_tid() != $self->[TID]; | |
347 | ||
348 | my $tempdir = $self->[_USE_FORK]; | |
349 | confess "Fork support has not been turned on!" unless $tempdir; | |
350 | ||
351 | opendir(my $dh, $tempdir) || croak "could not open temp dir ($tempdir)!"; | |
352 | ||
353 | my @files = sort readdir($dh); | |
354 | for my $file (@files) { | |
355 | next if $file =~ m/^\.+$/; | |
356 | next unless $file =~ m/\.ready$/; | |
357 | ||
358 | # Untaint the path. | |
359 | my $full = "$tempdir/$file"; | |
360 | ($full) = ($full =~ m/^(.*)$/gs); | |
361 | ||
362 | my $obj = Storable::retrieve($full); | |
363 | confess "Empty event object found '$full'" unless $obj; | |
364 | ||
365 | if ($ENV{TEST_KEEP_TMP_DIR}) { | |
366 | rename($full, "$full.complete") | |
367 | || confess "Could not rename file '$full', '$full.complete'"; | |
368 | } | |
369 | else { | |
370 | unlink($full) || die "Could not unlink file: $file"; | |
371 | } | |
372 | ||
373 | my $cache = $self->_update_state($self->[STATE]->[0], $obj); | |
374 | $self->_process_event($obj, $cache); | |
375 | $self->_finalize_event($obj, $cache); | |
376 | } | |
377 | ||
378 | closedir($dh); | |
379 | } | |
380 | ||
381 | sub done_testing { | |
382 | my $self = shift; | |
383 | my ($ctx, $num) = @_; | |
384 | my $state = $self->[STATE]->[-1]; | |
385 | ||
386 | if (my $old = $state->[STATE_ENDED]) { | |
387 | my ($p1, $f1, $l1) = $old->call; | |
388 | $ctx->ok(0, "done_testing() was already called at $f1 line $l1"); | |
389 | return; | |
390 | } | |
391 | ||
392 | if ($self->[FOLLOW_UPS]) { | |
393 | $_->($ctx) for @{$self->[FOLLOW_UPS]}; | |
394 | } | |
395 | ||
396 | $state->[STATE_ENDED] = $ctx->snapshot; | |
397 | ||
398 | my $ran = $state->[STATE_COUNT]; | |
399 | my $plan = $state->[STATE_PLAN] ? $state->[STATE_PLAN]->max : 0; | |
400 | ||
401 | if (defined($num) && $plan && $num != $plan) { | |
402 | $ctx->ok(0, "planned to run $plan but done_testing() expects $num"); | |
403 | return; | |
404 | } | |
405 | ||
406 | $ctx->plan($num || $plan || $ran) unless $state->[STATE_PLAN]; | |
407 | ||
408 | if ($plan && $plan != $ran) { | |
409 | $state->[STATE_PASSING] = 0; | |
410 | return; | |
411 | } | |
412 | ||
413 | if ($num && $num != $ran) { | |
414 | $state->[STATE_PASSING] = 0; | |
415 | return; | |
416 | } | |
417 | ||
418 | unless ($ran) { | |
419 | $state->[STATE_PASSING] = 0; | |
420 | return; | |
421 | } | |
422 | } | |
423 | ||
424 | sub send { | |
425 | my ($self, $e) = @_; | |
426 | ||
427 | # Subtest state management | |
428 | if ($e->isa('Test::Stream::Event::Child')) { | |
429 | if ($e->action eq 'push') { | |
430 | $e->context->note("Subtest: " . $e->name) if $self->[SUBTEST_TAP_INSTANT] && !$e->no_note; | |
431 | ||
432 | push @{$self->[STATE]} => [0, 0, undef, 1]; | |
433 | push @{$self->[SUBTESTS]} => []; | |
434 | push @{$self->[SUBTEST_TODO]} => $e->context->in_todo; | |
435 | push @{$self->[SUBTEST_EXCEPTION]} => undef; | |
436 | ||
437 | return $e; | |
438 | } | |
439 | else { | |
440 | pop @{$self->[SUBTEST_TODO]}; | |
441 | my $events = pop @{$self->[SUBTESTS]} || confess "Unbalanced subtest stack (events)!"; | |
442 | my $state = pop @{$self->[STATE]} || confess "Unbalanced subtest stack (state)!"; | |
443 | confess "Child pop left the stream without a state!" unless @{$self->[STATE]}; | |
444 | ||
445 | $e = Test::Stream::Event::Subtest->new_from_pairs( | |
446 | context => $e->context, | |
447 | created => $e->created, | |
448 | events => $events, | |
449 | state => $state, | |
450 | name => $e->name, | |
451 | exception => pop @{$self->[SUBTEST_EXCEPTION]}, | |
452 | ); | |
453 | } | |
454 | } | |
455 | ||
456 | my $cache = $self->_update_state($self->[STATE]->[-1], $e); | |
457 | ||
458 | # Subtests get dibbs on events | |
459 | if (@{$self->[SUBTESTS]}) { | |
460 | $e->context->set_diag_todo(1) if $self->[SUBTEST_TODO]->[-1]; | |
461 | $e->set_in_subtest(scalar @{$self->[SUBTESTS]}); | |
462 | push @{$self->[SUBTESTS]->[-1]} => $e; | |
463 | ||
464 | $self->_render_tap($cache) if $self->[SUBTEST_TAP_INSTANT] && !$cache->{no_out}; | |
465 | } | |
466 | elsif($self->[_USE_FORK] && ($$ != $self->[PID] || get_tid() != $self->[TID])) { | |
467 | $self->fork_out($e); | |
468 | } | |
469 | else { | |
470 | $self->_process_event($e, $cache); | |
471 | } | |
472 | ||
473 | $self->_finalize_event($e, $cache); | |
474 | ||
475 | return $e; | |
476 | } | |
477 | ||
478 | sub _update_state { | |
479 | my ($self, $state, $e) = @_; | |
480 | my $cache = {tap_event => $e, state => $state}; | |
481 | ||
482 | if ($e->isa('Test::Stream::Event::Ok')) { | |
483 | $cache->{do_tap} = 1; | |
484 | $state->[STATE_COUNT]++; | |
485 | if (!$e->bool) { | |
486 | $state->[STATE_FAILED]++; | |
487 | $state->[STATE_PASSING] = 0; | |
488 | } | |
489 | } | |
490 | elsif (!$self->[NO_HEADER] && $e->isa('Test::Stream::Event::Finish')) { | |
491 | if ($self->[FOLLOW_UPS]) { | |
492 | $_->($e->context) for @{$self->[FOLLOW_UPS]}; | |
493 | } | |
494 | ||
495 | $state->[STATE_ENDED] = $e->context->snapshot; | |
496 | ||
497 | my $plan = $state->[STATE_PLAN]; | |
498 | if ($plan && $e->tests_run && $plan->directive eq 'NO PLAN') { | |
499 | $plan->set_max($state->[STATE_COUNT]); | |
500 | $plan->set_directive(undef); | |
501 | $cache->{tap_event} = $plan; | |
502 | $cache->{do_tap} = 1; | |
503 | } | |
504 | else { | |
505 | $cache->{do_tap} = 0; | |
506 | $cache->{no_out} = 1; | |
507 | } | |
508 | } | |
509 | elsif ($self->[NO_DIAG] && $e->isa('Test::Stream::Event::Diag')) { | |
510 | $cache->{no_out} = 1; | |
511 | } | |
512 | elsif ($e->isa('Test::Stream::Event::Plan')) { | |
513 | $cache->{is_plan} = 1; | |
514 | ||
515 | if($self->[NO_HEADER]) { | |
516 | $cache->{no_out} = 1; | |
517 | } | |
518 | elsif(my $existing = $state->[STATE_PLAN]) { | |
519 | my $directive = $existing ? $existing->directive : ''; | |
520 | ||
521 | if ($existing && (!$directive || $directive eq 'NO PLAN')) { | |
522 | my ($p1, $f1, $l1) = $existing->context->call; | |
523 | my ($p2, $f2, $l2) = $e->context->call; | |
524 | die "Tried to plan twice!\n $f1 line $l1\n $f2 line $l2\n"; | |
525 | } | |
526 | } | |
527 | ||
528 | my $directive = $e->directive; | |
529 | $cache->{no_out} = 1 if $directive && $directive eq 'NO PLAN'; | |
530 | } | |
531 | ||
532 | push @{$state->[STATE_LEGACY]} => $e if $self->[USE_LEGACY]; | |
533 | ||
534 | $cache->{number} = $state->[STATE_COUNT]; | |
535 | ||
536 | return $cache; | |
537 | } | |
538 | ||
539 | sub _process_event { | |
540 | my ($self, $e, $cache) = @_; | |
541 | ||
542 | if ($self->[MUNGERS]) { | |
543 | $_->($self, $e) for @{$self->[MUNGERS]}; | |
544 | } | |
545 | ||
546 | $self->_render_tap($cache) unless $cache->{no_out}; | |
547 | ||
548 | if ($self->[LISTENERS]) { | |
549 | $_->($self, $e) for @{$self->[LISTENERS]}; | |
550 | } | |
551 | } | |
552 | ||
553 | sub _render_tap { | |
554 | my ($self, $cache) = @_; | |
555 | ||
556 | return if $^C; | |
557 | return unless $self->[USE_TAP]; | |
558 | my $e = $cache->{tap_event}; | |
559 | return unless $cache->{do_tap} || $e->can('to_tap'); | |
560 | ||
561 | my $num = $self->use_numbers ? $cache->{number} : undef; | |
562 | confess "XXX" unless $e->can('to_tap'); | |
563 | my @sets = $e->to_tap($num, $self->[SUBTEST_TAP_DELAYED]); | |
564 | ||
565 | my $in_subtest = $e->in_subtest || 0; | |
566 | my $indent = ' ' x $in_subtest; | |
567 | ||
568 | for my $set (@sets) { | |
569 | my ($hid, $msg) = @$set; | |
570 | next unless $msg; | |
571 | my $enc = $e->encoding || confess "Could not find encoding!"; | |
572 | my $io = $self->[IO_SETS]->{$enc}->[$hid] || confess "Could not find IO $hid for $enc"; | |
573 | ||
574 | local($\, $", $,) = (undef, ' ', ''); | |
575 | $msg =~ s/^/$indent/mg if $in_subtest; | |
576 | print $io $msg; | |
577 | } | |
578 | } | |
579 | ||
580 | sub _finalize_event { | |
581 | my ($self, $e, $cache) = @_; | |
582 | ||
583 | if ($cache->{is_plan}) { | |
584 | $cache->{state}->[STATE_PLAN] = $e; | |
585 | return unless $e->directive; | |
586 | return unless $e->directive eq 'SKIP'; | |
587 | ||
588 | $self->[SUBTEST_EXCEPTION]->[-1] = $e if $e->in_subtest; | |
589 | ||
590 | die $e if $e->in_subtest || !$self->[EXIT_ON_DISRUPTION]; | |
591 | exit 0; | |
592 | } | |
593 | elsif (!$cache->{do_tap} && $e->isa('Test::Stream::Event::Bail')) { | |
594 | $self->[BAILED_OUT] = $e; | |
595 | $self->[NO_ENDING] = 1; | |
596 | ||
597 | $self->[SUBTEST_EXCEPTION]->[-1] = $e if $e->in_subtest; | |
598 | ||
599 | die $e if $e->in_subtest || !$self->[EXIT_ON_DISRUPTION]; | |
600 | exit 255; | |
601 | } | |
602 | } | |
603 | ||
604 | sub _reset { | |
605 | my $self = shift; | |
606 | ||
607 | return unless $self->pid != $$ || $self->tid != get_tid(); | |
608 | ||
609 | $self->[PID] = $$; | |
610 | $self->[TID] = get_tid(); | |
611 | if (USE_THREADS || $self->[_USE_FORK]) { | |
612 | $self->[_USE_FORK] = undef; | |
613 | $self->use_fork; | |
614 | } | |
615 | $self->[STATE] = [[0, 0, undef, 1]]; | |
616 | } | |
617 | ||
618 | sub CLONE { | |
619 | for my $stream (_stack()) { | |
620 | next unless defined $stream->pid; | |
621 | next unless defined $stream->tid; | |
622 | ||
623 | next if $$ == $stream->pid && get_tid() == $stream->tid; | |
624 | ||
625 | $stream->[IN_SUBTHREAD] = 1; | |
626 | } | |
627 | } | |
628 | ||
629 | sub DESTROY { | |
630 | my $self = shift; | |
631 | ||
632 | return if $self->in_subthread; | |
633 | ||
634 | my $dir = $self->[_USE_FORK] || return; | |
635 | ||
636 | return unless defined $self->pid; | |
637 | return unless defined $self->tid; | |
638 | ||
639 | return unless $$ == $self->pid; | |
640 | return unless get_tid() == $self->tid; | |
641 | ||
642 | if ($ENV{TEST_KEEP_TMP_DIR}) { | |
643 | print STDERR "# Not removing temp dir: $dir\n"; | |
644 | return; | |
645 | } | |
646 | ||
647 | opendir(my $dh, $dir) || confess "Could not open temp dir! ($dir)"; | |
648 | while(my $file = readdir($dh)) { | |
649 | next if $file =~ m/^\.+$/; | |
650 | die "Unculled event! You ran tests in a child process, but never pulled them in!\n" | |
651 | if $file !~ m/\.complete$/; | |
652 | unlink("$dir/$file") || confess "Could not unlink file: '$dir/$file'"; | |
653 | } | |
654 | closedir($dh); | |
655 | rmdir($dir) || warn "Could not remove temp dir ($dir)"; | |
656 | } | |
657 | ||
658 | sub STORABLE_freeze { | |
659 | my ($self, $cloning) = @_; | |
660 | return if $cloning; | |
661 | return ($self); | |
662 | } | |
663 | ||
664 | sub STORABLE_thaw { | |
665 | my ($self, $cloning, @vals) = @_; | |
666 | return if $cloning; | |
667 | return Test::Stream->shared; | |
668 | } | |
669 | ||
670 | ||
671 | 1; | |
672 | ||
673 | __END__ | |
674 | ||
675 | =head1 NAME | |
676 | ||
677 | Test::Stream - A modern infrastructure for testing. | |
678 | ||
679 | =head1 SYNOPSYS | |
680 | ||
681 | # Enables modern enhancements such as forking support and TAP encoding. | |
682 | # Also turns off expensive legacy support. | |
683 | use Test::Stream; | |
684 | use Test::More; | |
685 | ||
686 | # ... Tests ... | |
687 | ||
688 | done_testing; | |
689 | ||
690 | =head1 FEATURES | |
691 | ||
692 | When you load Test::Stream inside your test file you prevent Test::More from | |
693 | turning on some expensive legacy support. You will also get warnings if your | |
694 | code, or any other code you load uses deprecated or discouraged practices. | |
695 | ||
696 | =head1 IMPORT ARGUMENTS | |
697 | ||
698 | Any import argument not recognised will be treated as an export, if it is not a | |
699 | valid export an exception will be thrown. | |
700 | ||
701 | =over 4 | |
702 | ||
703 | =item '-internal' | |
704 | ||
705 | This argument, I<when given first>, will prevent the import process from | |
706 | turning on enhanced features. This is mainly for internal use (thus the name) | |
707 | in order to access/load Test::Stream. | |
708 | ||
709 | =item subtest_tap => 'none' | |
710 | ||
711 | Do not show events within subtests, just the subtest result itself. | |
712 | ||
713 | =item subtest_tap => 'instant' | |
714 | ||
715 | Show events as they happen (this is how legacy Test::More worked). This is the | |
716 | default. | |
717 | ||
718 | =item subtest_tap => 'delayed' | |
719 | ||
720 | Show events within subtest AFTER the subtest event itself is complete. | |
721 | ||
722 | =item subtest_tap => 'both' | |
723 | ||
724 | Show events as they happen, then also display them after. | |
725 | ||
726 | =item 'enable_fork' | |
727 | ||
728 | Turns on support for code that forks. This is not activated by default because | |
729 | it adds ~30ms to the Test::More compile-time, which can really add up in large | |
730 | test suites. Turn it on only when needed. | |
731 | ||
732 | =item 'utf8' | |
733 | ||
734 | Set the TAP encoding to utf8 | |
735 | ||
736 | =item encoding => '...' | |
737 | ||
738 | Set the TAP encoding. | |
739 | ||
740 | =back | |
741 | ||
742 | =head1 EXPORTS | |
743 | ||
744 | =head2 DEFAULT EXPORTS | |
745 | ||
746 | =over 4 | |
747 | ||
748 | =item tap_encoding( $ENCODING ) | |
749 | ||
750 | Set the tap encoding from this point on. | |
751 | ||
752 | =item cull | |
753 | ||
754 | Bring in results from child processes/threads. This is automatically done | |
755 | whenever a context is obtained, but you may wish to do it on demand. | |
756 | ||
757 | =back | |
758 | ||
759 | =head2 CONSTANTS | |
760 | ||
761 | none of these are exported by default you must request them | |
762 | ||
763 | =over | |
764 | ||
765 | =item OUT_STD | |
766 | ||
767 | =item OUT_ERR | |
768 | ||
769 | =item OUT_TODO | |
770 | ||
771 | These are indexes of specific IO handles inside an IO set (each encoding has an | |
772 | IO set). | |
773 | ||
774 | =item STATE_COUNT | |
775 | ||
776 | =item STATE_FAILED | |
777 | ||
778 | =item STATE_PLAN | |
779 | ||
780 | =item STATE_PASSING | |
781 | ||
782 | =item STATE_LEGACY | |
783 | ||
784 | =item STATE_ENDED | |
785 | ||
786 | These are indexes into the STATE array present in the stream. | |
787 | ||
788 | =back | |
789 | ||
790 | =head1 THE STREAM STACK AND METHODS | |
791 | ||
792 | At any point there can be any number of streams. Most streams will be present | |
793 | in the stream stack. The stack is managed via a collection of class methods. | |
794 | You can always access the "current" or "central" stream using | |
795 | Test::Stream->shared. If you want your events to go where they are supposed to | |
796 | then you should always send them to the shared stream. | |
797 | ||
798 | It is important to note that any toogle, control, listener, munger, etc. | |
799 | applied to a stream will effect only that stream. Independant streams, streams | |
800 | down the stack, and streams added later will not get any settings from other | |
801 | stacks. Keep this in mind if you take it upon yourself to modify the stream | |
802 | stack. | |
803 | ||
804 | =head2 TOGGLES AND CONTROLS | |
805 | ||
806 | =over 4 | |
807 | ||
808 | =item $stream->use_fork | |
809 | ||
810 | Turn on forking support (it cannot be turned off). | |
811 | ||
812 | =item $stream->set_subtest_tap_instant($bool) | |
813 | ||
814 | =item $bool = $stream->subtest_tap_instant | |
815 | ||
816 | Render subtest events as they happen. | |
817 | ||
818 | =item $stream->set_subtest_tap_delayed($bool) | |
819 | ||
820 | =item $bool = $stream->subtest_tap_delayed | |
821 | ||
822 | Render subtest events when printing the result of the subtest | |
823 | ||
824 | =item $stream->set_exit_on_disruption($bool) | |
825 | ||
826 | =item $bool = $stream->exit_on_disruption | |
827 | ||
828 | When true, skip_all and bailout will call exit. When false the bailout and | |
829 | skip_all events will be thrown as exceptions. | |
830 | ||
831 | =item $stream->set_use_tap($bool) | |
832 | ||
833 | =item $bool = $stream->use_tap | |
834 | ||
835 | Turn TAP rendering on or off. | |
836 | ||
837 | =item $stream->set_use_legacy($bool) | |
838 | ||
839 | =item $bool = $stream->use_legacy | |
840 | ||
841 | Turn legacy result storing on and off. | |
842 | ||
843 | =item $stream->set_use_numbers($bool) | |
844 | ||
845 | =item $bool = $stream->use_numbers | |
846 | ||
847 | Turn test numbers on and off. | |
848 | ||
849 | =back | |
850 | ||
851 | =head2 SENDING EVENTS | |
852 | ||
853 | Test::Stream->shared->send($event) | |
854 | ||
855 | The C<send()> method is used to issue an event to the stream. This method will | |
856 | handle thread/fork sych, mungers, listeners, TAP output, etc. | |
857 | ||
858 | =head2 ALTERING EVENTS | |
859 | ||
860 | Test::Stream->shared->munge(sub { | |
861 | my ($stream, $event) = @_; | |
862 | ||
863 | ... Modify the event object ... | |
864 | ||
865 | # return is ignored. | |
866 | }); | |
867 | ||
868 | Mungers can never be removed once added. The return from a munger is ignored. | |
869 | Any changes you wish to make to the object must be done directly by altering | |
870 | it in place. The munger is called before the event is rendered as TAP, and | |
871 | AFTER the event has made any necessary state changes. | |
872 | ||
873 | =head2 LISTENING FOR EVENTS | |
874 | ||
875 | Test::Stream->shared->listen(sub { | |
876 | my ($stream, $event) = @_; | |
877 | ||
878 | ... do whatever you want with the event ... | |
879 | ||
880 | # return is ignored | |
881 | }); | |
882 | ||
883 | Listeners can never be removed once added. The return from a listener is | |
884 | ignored. Changing an event in a listener is not something you should ever do, | |
885 | though no protections are in place to prevent it (this may change!). The | |
886 | listeners are called AFTER the event has been rendered as TAP. | |
887 | ||
888 | =head2 POST-TEST BEHAVIORS | |
889 | ||
890 | Test::Stream->shared->follow_up(sub { | |
891 | my ($context) = @_; | |
892 | ||
893 | ... do whatever you need to ... | |
894 | ||
895 | # Return is ignored | |
896 | }); | |
897 | ||
898 | follow_up subs are called only once, when the stream recieves a finish event. There are 2 ways a finish event can occur: | |
899 | ||
900 | =over 4 | |
901 | ||
902 | =item done_testing | |
903 | ||
904 | A finish event is generated when you call done_testing. The finish event occurs | |
905 | before the plan is output. | |
906 | ||
907 | =item EXIT MAGIC | |
908 | ||
909 | A finish event is generated when the Test::Stream END block is called, just | |
910 | before cleanup. This event will not happen if it was already geenerated by a | |
911 | call to done_testing. | |
912 | ||
913 | =back | |
914 | ||
915 | =head2 OTHER METHODS | |
916 | ||
917 | =over | |
918 | ||
919 | =item $stream->state | |
920 | ||
921 | Get the current state of the stream. The state is an array where specific | |
922 | indexes have specific meanings. These indexes are managed via constants. | |
923 | ||
924 | =item $stream->plan | |
925 | ||
926 | Get the plan event, if a plan has been issued. | |
927 | ||
928 | =item $stream->count | |
929 | ||
930 | Get the test count so far. | |
931 | ||
932 | =item $stream->failed | |
933 | ||
934 | Get the number of failed tests so far. | |
935 | ||
936 | =item $stream->ended | |
937 | ||
938 | Get the context in which the tests ended, if they have ended. | |
939 | ||
940 | =item $stream->legacy | |
941 | ||
942 | Used internally to store events for legacy support. | |
943 | ||
944 | =item $stream->is_passing | |
945 | ||
946 | Check if the test is passing its plan. | |
947 | ||
948 | =item $stream->done_testing($context, $max) | |
949 | ||
950 | Tell the stream we are done testing. | |
951 | ||
952 | =item $stream->fork_cull | |
953 | ||
954 | Gather events from other threads/processes. | |
955 | ||
956 | =back | |
957 | ||
958 | =head2 STACK METHODS AND INTERCEPTING EVENTS | |
959 | ||
960 | =over 4 | |
961 | ||
962 | =item $stream = Test::Stream->shared | |
963 | ||
964 | Get the current shared stream. The shared stream is the stream at the top of | |
965 | the stack. | |
966 | ||
967 | =item Test::Stream->clear | |
968 | ||
969 | Completely remove the stream stack. It is very unlikely you will ever want to | |
970 | do this. | |
971 | ||
972 | =item ($new, $old) = Test::Stream->intercept_start($new) | |
973 | ||
974 | =item ($new, $old) = Test::Stream->intercept_start | |
975 | ||
976 | Push a new stream to the top of the stack. If you do not provide a stack a new | |
977 | one will be created for you. If you have one created for you it will have the | |
978 | following differences from a default stack: | |
979 | ||
980 | $new->set_exit_on_disruption(0); | |
981 | $new->set_use_tap(0); | |
982 | $new->set_use_legacy(0); | |
983 | ||
984 | =item Test::Stream->intercept_stop($top) | |
985 | ||
986 | Pop the stack, you must pass in the instance you expect to be popped, there | |
987 | will be an exception if they do not match. | |
988 | ||
989 | =item Test::Stream->intercept(sub { ... }) | |
990 | ||
991 | Test::Stream->intercept(sub { | |
992 | my ($new, $old) = @_; | |
993 | ||
994 | ... | |
995 | }); | |
996 | ||
997 | Temporarily push a new stream to the top of the stack. The codeblock you pass | |
998 | in will be run. Once your codelbock returns the stack will be popped and | |
999 | restored to the previous state. | |
1000 | ||
1001 | =back | |
1002 | ||
1003 | =encoding utf8 | |
1004 | ||
1005 | =head1 SOURCE | |
1006 | ||
1007 | The source code repository for Test::More can be found at | |
1008 | F<http://github.com/Test-More/test-more/>. | |
1009 | ||
1010 | =head1 MAINTAINER | |
1011 | ||
1012 | =over 4 | |
1013 | ||
1014 | =item Chad Granum E<lt>exodist@cpan.orgE<gt> | |
1015 | ||
1016 | =back | |
1017 | ||
1018 | =head1 AUTHORS | |
1019 | ||
1020 | The following people have all contributed to the Test-More dist (sorted using | |
1021 | VIM's sort function). | |
1022 | ||
1023 | =over 4 | |
1024 | ||
1025 | =item Chad Granum E<lt>exodist@cpan.orgE<gt> | |
1026 | ||
1027 | =item Fergal Daly E<lt>fergal@esatclear.ie>E<gt> | |
1028 | ||
1029 | =item Mark Fowler E<lt>mark@twoshortplanks.comE<gt> | |
1030 | ||
1031 | =item Michael G Schwern E<lt>schwern@pobox.comE<gt> | |
1032 | ||
1033 | =item 唐鳳 | |
1034 | ||
1035 | =back | |
1036 | ||
1037 | =head1 COPYRIGHT | |
1038 | ||
1039 | There has been a lot of code migration between modules, | |
1040 | here are all the original copyrights together: | |
1041 | ||
1042 | =over 4 | |
1043 | ||
1044 | =item Test::Stream | |
1045 | ||
1046 | =item Test::Stream::Tester | |
1047 | ||
1048 | Copyright 2014 Chad Granum E<lt>exodist7@gmail.comE<gt>. | |
1049 | ||
1050 | This program is free software; you can redistribute it and/or | |
1051 | modify it under the same terms as Perl itself. | |
1052 | ||
1053 | See F<http://www.perl.com/perl/misc/Artistic.html> | |
1054 | ||
1055 | =item Test::Simple | |
1056 | ||
1057 | =item Test::More | |
1058 | ||
1059 | =item Test::Builder | |
1060 | ||
1061 | Originally authored by Michael G Schwern E<lt>schwern@pobox.comE<gt> with much | |
1062 | inspiration from Joshua Pritikin's Test module and lots of help from Barrie | |
1063 | Slaymaker, Tony Bowden, blackstar.co.uk, chromatic, Fergal Daly and the perl-qa | |
1064 | gang. | |
1065 | ||
1066 | Idea by Tony Bowden and Paul Johnson, code by Michael G Schwern | |
1067 | E<lt>schwern@pobox.comE<gt>, wardrobe by Calvin Klein. | |
1068 | ||
1069 | Copyright 2001-2008 by Michael G Schwern E<lt>schwern@pobox.comE<gt>. | |
1070 | ||
1071 | This program is free software; you can redistribute it and/or | |
1072 | modify it under the same terms as Perl itself. | |
1073 | ||
1074 | See F<http://www.perl.com/perl/misc/Artistic.html> | |
1075 | ||
1076 | =item Test::use::ok | |
1077 | ||
1078 | To the extent possible under law, 唐鳳 has waived all copyright and related | |
1079 | or neighboring rights to L<Test-use-ok>. | |
1080 | ||
1081 | This work is published from Taiwan. | |
1082 | ||
1083 | L<http://creativecommons.org/publicdomain/zero/1.0> | |
1084 | ||
1085 | =item Test::Tester | |
1086 | ||
1087 | This module is copyright 2005 Fergal Daly <fergal@esatclear.ie>, some parts | |
1088 | are based on other people's work. | |
1089 | ||
1090 | Under the same license as Perl itself | |
1091 | ||
1092 | See http://www.perl.com/perl/misc/Artistic.html | |
1093 | ||
1094 | =item Test::Builder::Tester | |
1095 | ||
1096 | Copyright Mark Fowler E<lt>mark@twoshortplanks.comE<gt> 2002, 2004. | |
1097 | ||
1098 | This program is free software; you can redistribute it | |
1099 | and/or modify it under the same terms as Perl itself. | |
1100 | ||
1101 | =back |