File Coverage

inc/Test/Builder.pm
Criterion Covered Total %
statement 243 880 27.6
branch 55 392 14.0
condition 18 252 7.1
subroutine 47 109 43.1
pod 47 52 90.3
total 410 1685 24.3


line stmt bran cond sub pod time code
1             #line 1
2             package Test::Builder;
3 1     1   10  
  1         3  
4 1     1   3 use 5.006;
  1         1  
  1         20  
5 1     1   4 use strict;
  1         1  
  1         48  
6             use warnings;
7              
8             our $VERSION = '1.302073';
9              
10 1 50   1   25 BEGIN {
11 0         0 if( $] < 5.008 ) {
12             require Test::Builder::IO::Scalar;
13             }
14             }
15 1     1   4  
  1         1  
  1         118  
16             use Scalar::Util qw/blessed reftype weaken/;
17 1     1   318  
  1         2  
  1         51  
18 1     1   352 use Test2::Util qw/USE_THREADS try get_tid/;
  1         3  
  1         109  
19             use Test2::API qw/context release/;
20             # Make Test::Builder thread-safe for ithreads.
21 1 50 33 1   4 BEGIN {
22             warn "Test::Builder was loaded after Test2 initialization, this is not recommended."
23             if Test2::API::test2_init_done() || Test2::API::test2_load_done();
24 1         14  
25             if (USE_THREADS) {
26             require Test2::IPC;
27             require Test2::IPC::Driver::Files;
28             Test2::IPC::Driver::Files->import;
29             Test2::API::test2_ipc_enable_polling();
30             Test2::API::test2_no_wait(1);
31             Test2::API::test2_ipc_enable_shm();
32             }
33             }
34 1     1   5  
  1         1  
  1         19  
35 1     1   3 use Test2::Event::Subtest;
  1         1  
  1         16  
36             use Test2::Hub::Subtest;
37 1     1   311  
  1         2  
  1         4  
38 1     1   314 use Test::Builder::Formatter;
  1         2  
  1         82  
39             use Test::Builder::TodoDiag;
40              
41             our $Level = 1;
42             our $Test = $ENV{TB_NO_EARLY_INIT} ? undef : Test::Builder->new;
43              
44 1     1   1 sub _add_ts_hooks {
45 1         4 my $self = shift;
46             my $hub = $self->{Stack}->top;
47              
48             # Take a reference to the hash key, we do this to avoid closing over $self
49             # which is the singleton. We use a reference because the value could change
50 1         2 # in rare cases.
51             my $epkgr = \$self->{Exported_To};
52              
53             #$hub->add_context_aquire(sub {$_[0]->{level} += $Level - 1});
54              
55 124     124   177 $hub->pre_filter(sub {
56             my ($active_hub, $e) = @_;
57 124         176  
58 124 50       277 my $epkg = $$epkgr;
59             my $cpkg = $e->{trace} ? $e->{trace}->{frame}->[0] : undef;
60 1     1   5  
  1         1  
  1         34  
61 1     1   4 no strict 'refs';
  1         2  
  1         2681  
62 124         130 no warnings 'once';
63 124 50       213 my $todo;
  124         371  
64 124 50 33     350 $todo = ${"$cpkg\::TODO"} if $cpkg;
  124         188  
65             $todo = ${"$epkg\::TODO"} if $epkg && !$todo;
66 124 50       291  
67             return $e unless $todo;
68              
69 0 0       0 # Turn a diag into a todo diag
70             return Test::Builder::TodoDiag->new(%$e) if ref($e) eq 'Test2::Event::Diag';
71              
72 0 0       0 # Set todo on ok's
73 0         0 if ($e->isa('Test2::Event::Ok')) {
74 0         0 $e->set_todo($todo);
75             $e->set_effective_pass(1);
76 0 0       0  
77 0   0     0 if (my $result = $e->get_meta(__PACKAGE__)) {
78 0   0     0 $result->{reason} ||= $todo;
79 0         0 $result->{type} ||= 'todo';
80             $result->{ok} = 1;
81             }
82             }
83 0         0  
84 1         6 return $e;
85             }, inherit => 1);
86             }
87              
88 126     126 1 226 sub new {
89 126 100       329 my($class) = shift;
90 1         4 unless($Test) {
91 1         4 my $ctx = context();
92 1         3 $Test = $class->create(singleton => 1);
93             $ctx->release;
94              
95             # Non-TB tools normally expect 0 added to the level. $Level is normally 1. So
96             # we only want the level to change if $Level != 1.
97 1     126   12 # TB->ctx compensates for this later.
  126         333  
98             Test2::API::test2_add_callback_context_aquire(sub { $_[0]->{level} += $Level - 1 });
99 1     1   4  
  1         6  
100             Test2::API::test2_add_callback_exit(sub { $Test->_ending(@_) });
101 1         3  
102             Test2::API::test2_ipc()->set_no_fatal(1) if USE_THREADS;
103 126         265 }
104             return $Test;
105             }
106              
107 1     1 1 2 sub create {
108 1         2 my $class = shift;
109             my %params = @_;
110 1         2  
111 1 50       3 my $self = bless {}, $class;
112 1         9 if ($params{singleton}) {
113             $self->{Stack} = Test2::API::test2_stack();
114             }
115 0         0 else {
116             $self->{Stack} = Test2::API::Stack->new;
117 0         0 $self->{Stack}->new_hub(
118             formatter => Test::Builder::Formatter->new,
119             ipc => Test2::API::test2_ipc(),
120             );
121 1         4 }
122 1         3 $self->reset(%params);
123             $self->_add_ts_hooks;
124 1         1  
125             return $self;
126             }
127              
128 131     131 0 167 sub ctx {
129             my $self = shift;
130             context(
131             # 1 for our frame, another for the -1 off of $Level in our hook at the top.
132             level => 2,
133             fudge => 1,
134             stack => $self->{Stack},
135 131         597 hub => $self->{Hub},
136             wrapped => 1,
137             @_
138             );
139             }
140              
141 0     0 0 0 sub parent {
142 0         0 my $self = shift;
143 0   0     0 my $ctx = $self->ctx;
144 0         0 my $chub = $self->{Hub} || $ctx->hub;
145             $ctx->release;
146 0         0  
147 0         0 my $meta = $chub->meta(__PACKAGE__, {});
148             my $parent = $meta->{parent};
149 0 0       0  
150             return undef unless $parent;
151              
152             return bless {
153             Original_Pid => $$,
154 0         0 Stack => $self->{Stack},
155             Hub => $parent,
156             }, blessed($self);
157             }
158              
159 0     0 0 0 sub child {
160             my( $self, $name ) = @_;
161 0   0     0  
162 0         0 $name ||= "Child of " . $self->name;
163             my $ctx = $self->ctx;
164 0         0  
165 0         0 my $parent = $ctx->hub;
166             my $pmeta = $parent->meta(__PACKAGE__, {});
167 0 0       0 $self->croak("You already have a child named ($pmeta->{child}) running")
168             if $pmeta->{child};
169 0         0  
170             $pmeta->{child} = $name;
171              
172 0         0 # Clear $TODO for the child.
173             my $orig_TODO = $self->find_TODO(undef, 1, undef);
174 0         0  
175             my $subevents = [];
176 0         0  
177             my $hub = $ctx->stack->new_hub(
178             class => 'Test2::Hub::Subtest',
179             );
180              
181 0     0   0 $hub->pre_filter(sub {
182             my ($active_hub, $e) = @_;
183              
184 0 0       0 # Turn a diag into a todo diag
185             return Test::Builder::TodoDiag->new(%$e) if ref($e) eq 'Test2::Event::Diag';
186 0         0  
187 0 0       0 return $e;
188             }, inherit => 1) if $orig_TODO;
189 0     0   0  
  0         0  
190             $hub->listen(sub { push @$subevents => $_[1] });
191 0 0       0  
192             $hub->set_nested( $parent->isa('Test2::Hub::Subtest') ? $parent->nested + 1 : 1 );
193 0         0  
194 0         0 my $meta = $hub->meta(__PACKAGE__, {});
195 0         0 $meta->{Name} = $name;
196 0         0 $meta->{TODO} = $orig_TODO;
197 0         0 $meta->{TODO_PKG} = $ctx->trace->package;
198 0         0 $meta->{parent} = $parent;
199 0         0 $meta->{Test_Results} = [];
200 0         0 $meta->{subevents} = $subevents;
201 0 0       0 $meta->{subtest_id} = $hub->id;
202             $meta->{subtest_buffered} = $parent->format ? 0 : 1;
203 0         0  
204             $self->_add_ts_hooks;
205 0         0  
206 0         0 $ctx->release;
207             return bless { Original_Pid => $$, Stack => $self->{Stack}, Hub => $hub }, blessed($self);
208             }
209              
210 0     0 0 0 sub finalize {
211 0         0 my $self = shift;
212 0 0       0 my $ok = 1;
213             ($ok) = @_ if @_;
214 0         0  
215 0   0     0 my $st_ctx = $self->ctx;
216             my $chub = $self->{Hub} || return $st_ctx->release;
217 0         0  
218 0 0       0 my $meta = $chub->meta(__PACKAGE__, {});
219 0         0 if ($meta->{child}) {
220             $self->croak("Can't call finalize() with child ($meta->{child}) active");
221             }
222 0         0  
223             local $? = 0; # don't fail if $subtests happened to set $? nonzero
224 0         0  
225             $self->{Stack}->pop($chub);
226 0         0  
227             $self->find_TODO($meta->{TODO_PKG}, 1, $meta->{TODO});
228 0         0  
229 0         0 my $parent = $self->parent;
230 0         0 my $ctx = $parent->ctx;
231 0         0 my $trace = $ctx->trace;
232             delete $ctx->hub->meta(__PACKAGE__, {})->{child};
233 0 0 0     0  
      0        
      0        
234             $chub->finalize($trace, 1)
235             if $ok
236             && $chub->count
237             && !$chub->no_ending
238             && !$chub->ended;
239 0   0     0  
240 0         0 my $plan = $chub->plan || 0;
241 0         0 my $count = $chub->count;
242 0         0 my $failed = $chub->failed;
243             my $passed = $chub->is_passing;
244 0 0       0  
245 0 0 0     0 my $num_extra = $plan =~ m/\D/ ? 0 : $count - $plan;
246 0 0       0 if ($count && $num_extra != 0) {
247 0         0 my $s = $plan == 1 ? '' : 's';
248             $st_ctx->diag(<<"FAIL");
249             Looks like you planned $plan test$s but ran $count.
250             FAIL
251             }
252 0 0       0  
253 0 0       0 if ($failed) {
254             my $s = $failed == 1 ? '' : 's';
255 0 0       0  
256             my $qualifier = $num_extra == 0 ? '' : ' run';
257 0         0  
258             $st_ctx->diag(<<"FAIL");
259             Looks like you failed $failed test$s of $count$qualifier.
260             FAIL
261             }
262 0 0 0     0  
      0        
      0        
263 0         0 if (!$passed && !$failed && $count && !$num_extra) {
264             $st_ctx->diag(<<"FAIL");
265             All assertions inside the subtest passed, but errors were encountered.
266             FAIL
267             }
268 0         0  
269             $st_ctx->release;
270 0 0       0  
271 0         0 unless ($chub->bailed_out) {
272 0 0 0     0 my $plan = $chub->plan;
    0          
273 0         0 if ( $plan && $plan eq 'SKIP' ) {
274             $parent->skip($chub->skip_reason, $meta->{Name});
275             }
276 0         0 elsif ( !$chub->count ) {
277             $parent->ok( 0, sprintf q[No tests run for subtest "%s"], $meta->{Name} );
278             }
279 0         0 else {
280 0         0 $parent->{subevents} = $meta->{subevents};
281 0         0 $parent->{subtest_id} = $meta->{subtest_id};
282 0         0 $parent->{subtest_buffered} = $meta->{subtest_buffered};
283             $parent->ok( $chub->is_passing, $meta->{Name} );
284             }
285             }
286 0         0  
287 0         0 $ctx->release;
288             return $chub->is_passing;
289             }
290              
291 0     0 1 0 sub subtest {
292 0         0 my $self = shift;
293 0         0 my ($name, $code, @args) = @_;
294 0 0 0     0 my $ctx = $self->ctx;
295             $ctx->throw("subtest()'s second argument must be a code ref")
296             unless $code && reftype($code) eq 'CODE';
297 0   0     0  
298             $name ||= "Child of " . $self->name;
299 0         0  
300             $ctx->note("Subtest: $name");
301 0         0  
302             my $child = $self->child($name);
303 0         0  
304 0         0 my $start_pid = $$;
305 0         0 my $st_ctx;
306             my ($ok, $err, $finished, $child_error);
307 0         0 T2_SUBTEST_WRAPPER: {
  0         0  
308 0         0 my $ctx = $self->ctx;
309 0         0 $st_ctx = $ctx->snapshot;
310 0         0 $ctx->release;
  0         0  
  0         0  
  0         0  
311 0         0 $ok = eval { local $Level = 1; $code->(@args); 1 };
312             ($err, $child_error) = ($@, $?);
313              
314 0 0 0     0 # They might have done 'BEGIN { skip_all => "whatever" }'
      0        
      0        
315 0         0 if (!$ok && $err =~ m/Label not found for "last T2_SUBTEST_WRAPPER"/ || (blessed($err) && blessed($err) eq 'Test::Builder::Exception')) {
316 0         0 $ok = undef;
317             $err = undef;
318             }
319 0         0 else {
320             $finished = 1;
321             }
322             }
323 0 0 0     0  
324 0 0       0 if ($start_pid != $$ && !$INC{'Test/Sync/IPC.pm'}) {
325 0         0 warn $ok ? "Forked inside subtest, but subtest never finished!\n" : $err;
326             exit 255;
327             }
328 0         0  
329             my $trace = $ctx->trace;
330 0 0       0  
331 0 0       0 if (!$finished) {
332 0         0 if(my $bailed = $st_ctx->hub->bailed_out) {
333 0         0 my $chub = $child->{Hub};
334 0         0 $self->{Stack}->pop($chub);
335             $ctx->bail($bailed->reason);
336 0         0 }
337 0         0 my $code = $st_ctx->hub->exit_code;
338 0 0       0 $ok = !$code;
339             $err = "Subtest ended with exit code $code" if $code;
340             }
341 0         0  
342 0         0 my $st_hub = $st_ctx->hub;
343 0         0 my $plan = $st_hub->plan;
344             my $count = $st_hub->count;
345 0 0 0     0  
      0        
346 0 0       0 if (!$count && (!defined($plan) || "$plan" ne 'SKIP')) {
347 0         0 $st_ctx->plan(0) unless defined $plan;
348             $st_ctx->diag('No tests run!');
349             }
350 0         0  
351             $child->finalize($st_ctx->trace);
352 0         0  
353             $ctx->release;
354 0 0       0  
355             die $err unless $ok;
356 0 0       0  
357             $? = $child_error if defined $child_error;
358 0         0  
359             return $st_hub->is_passing;
360             }
361              
362 0     0 1 0 sub name {
363 0         0 my $self = shift;
364 0         0 my $ctx = $self->ctx;
365             release $ctx, $ctx->hub->meta(__PACKAGE__, {})->{Name};
366             }
367              
368 1     1 1 3 sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
369             my ($self, %params) = @_;
370 1         2  
371             Test2::API::test2_set_is_end(0);
372              
373             # We leave this a global because it has to be localized and localizing
374 1         1 # hash keys is just asking for pain. Also, it was documented.
375             $Level = 1;
376 1         2  
377             $self->{Original_Pid} = $$;
378 1         2  
379 1 50       12 my $ctx = $self->ctx;
380 0         0 unless ($params{singleton}) {
381 0         0 $ctx->hub->reset_state();
382 0         0 $ctx->hub->set_pid($$);
383             $ctx->hub->set_tid(get_tid);
384             }
385 1         5  
386             my $meta = $ctx->hub->meta(__PACKAGE__, {});
387             %$meta = (
388             Name => $0,
389             Ending => 0,
390             Done_Testing => undef,
391             Skip_All => 0,
392             Test_Results => [],
393 1         5 parent => $meta->{parent},
394             );
395 1         2  
396             $self->{Exported_To} = undef;
397 1   33     9  
398 1         3 $self->{Orig_Handles} ||= do {
399 1         1 my $format = $ctx->hub->format;
400 1 50 33     16 my $out;
401 1         6 if ($format && $format->isa('Test2::Formatter::TAP')) {
402             $out = $format->handles;
403 1 50       4 }
404             $out ? [@$out] : [];
405             };
406 1         2  
407 1         4 $self->use_numbers(1);
408 1         2 $self->no_header(0);
409 1         3 $self->no_ending(0);
410             $self->reset_outputs;
411 1         2  
412             $ctx->release;
413 1         1  
414             return;
415             }
416              
417              
418             my %plan_cmds = (
419             no_plan => \&no_plan,
420             skip_all => \&skip_all,
421             tests => \&_plan_tests,
422             );
423              
424 1     1 1 2 sub plan {
425             my( $self, $cmd, $arg ) = @_;
426 1 50       3  
427             return unless $cmd;
428 1         14  
429 1         3 my $ctx = $self->ctx;
430             my $hub = $ctx->hub;
431 1 50       4  
432             $ctx->throw("You tried to plan twice") if $hub->plan;
433 1         3  
434             local $Level = $Level + 1;
435 1 50       2  
436 1         3 if( my $method = $plan_cmds{$cmd} ) {
437 1         3 local $Level = $Level + 1;
438             $self->$method($arg);
439             }
440 0         0 else {
  0         0  
441 0         0 my @args = grep { defined } ( $cmd, $arg );
442             $ctx->throw("plan() doesn't understand @args");
443             }
444 1         9  
445             release $ctx, 1;
446             }
447              
448              
449 1     1   2 sub _plan_tests {
450             my($self, $arg) = @_;
451 1         3  
452             my $ctx = $self->ctx;
453 1 50       3  
    0          
454 1         2 if($arg) {
455 1         3 local $Level = $Level + 1;
456             $self->expected_tests($arg);
457             }
458 0         0 elsif( !defined $arg ) {
459             $ctx->throw("Got an undefined number of tests");
460             }
461 0         0 else {
462             $ctx->throw("You said to run 0 tests");
463             }
464 1         3  
465             $ctx->release;
466             }
467              
468              
469 1     1 1 2 sub expected_tests {
470 1         2 my $self = shift;
471             my($max) = @_;
472 1         2  
473             my $ctx = $self->ctx;
474 1 50       3  
475 1 50       7 if(@_) {
476             $self->croak("Number of tests must be a positive integer. You gave it '$max'")
477             unless $max =~ /^\+?\d+$/;
478 1         3  
479             $ctx->plan($max);
480             }
481 1         3  
482             my $hub = $ctx->hub;
483 1         2  
484             $ctx->release;
485 1         4  
486 1 50       3 my $plan = $hub->plan;
487 1 50       4 return 0 unless $plan;
488 1         3 return 0 if $plan =~ m/\D/;
489             return $plan;
490             }
491              
492              
493 0     0 1 0 sub no_plan {
494             my($self, $arg) = @_;
495 0         0  
496             my $ctx = $self->ctx;
497 0 0       0  
498 0         0 if (defined $ctx->hub->plan) {
499 0         0 warn "Plan already set, no_plan() is a no-op, this will change to a hard failure in the future.";
500 0         0 $ctx->release;
501             return;
502             }
503 0 0       0  
504             $ctx->alert("no_plan takes no arguments") if $arg;
505 0         0  
506             $ctx->hub->plan('NO PLAN');
507 0         0  
508             release $ctx, 1;
509             }
510              
511              
512 0     0 1 0 sub done_testing {
513             my($self, $num_tests) = @_;
514 0         0  
515             my $ctx = $self->ctx;
516 0         0  
517             my $meta = $ctx->hub->meta(__PACKAGE__, {});
518 0 0       0  
519 0         0 if ($meta->{Done_Testing}) {
  0         0  
520 0         0 my ($file, $line) = @{$meta->{Done_Testing}}[1,2];
521 0         0 local $ctx->hub->{ended}; # OMG This is awful.
522 0         0 $self->ok(0, "done_testing() was already called at $file line $line");
523 0         0 $ctx->release;
524             return;
525 0         0 }
526             $meta->{Done_Testing} = [$ctx->trace->call];
527 0         0  
528 0         0 my $plan = $ctx->hub->plan;
529             my $count = $ctx->hub->count;
530              
531 0 0 0     0 # If done_testing() specified the number of tests, shut off no_plan
    0 0        
532 0 0 0     0 if( defined $num_tests ) {
533             $ctx->plan($num_tests) if !$plan || $plan eq 'NO PLAN';
534             }
535 0         0 elsif ($count && defined $num_tests && $count != $num_tests) {
  0         0  
536             $self->ok(0, "planned to run @{[ $self->expected_tests ]} but done_testing() expects $num_tests");
537             }
538 0         0 else {
539             $num_tests = $self->current_test;
540             }
541 0 0 0     0  
542 0         0 if( $self->expected_tests && $num_tests != $self->expected_tests ) {
  0         0  
543             $self->ok(0, "planned to run @{[ $self->expected_tests ]} ".
544             "but done_testing() expects $num_tests");
545             }
546 0 0 0     0  
547             $ctx->plan($num_tests) if $ctx->hub->plan && $ctx->hub->plan eq 'NO PLAN';
548 0         0  
549             $ctx->hub->finalize($ctx->trace, 1);
550 0         0  
551             release $ctx, 1;
552             }
553              
554              
555 0     0 1 0 sub has_plan {
556             my $self = shift;
557 0         0  
558 0         0 my $ctx = $self->ctx;
559 0         0 my $plan = $ctx->hub->plan;
560             $ctx->release;
561 0 0 0     0  
562 0 0 0     0 return( $plan ) if $plan && $plan !~ m/\D/;
563 0         0 return('no_plan') if $plan && $plan eq 'NO PLAN';
564             return(undef);
565             }
566              
567              
568 0     0 1 0 sub skip_all {
569             my( $self, $reason ) = @_;
570 0         0  
571             my $ctx = $self->ctx;
572 0   0     0  
573             $ctx->hub->meta(__PACKAGE__, {})->{Skip_All} = $reason || 1;
574              
575 0 0       0 # Work around old perl bug
576 0         0 if ($] < 5.020000) {
577 0         0 my $begin = 0;
578 0         0 my $level = 0;
579 0 0 0     0 while (my @call = caller($level++)) {
580 0 0       0 last unless @call && $call[0];
581 0         0 next unless $call[3] =~ m/::BEGIN$/;
582 0         0 $begin++;
583             last;
584             }
585 0 0 0     0 # HACK!
586             die 'Label not found for "last T2_SUBTEST_WRAPPER"' if $begin && $ctx->hub->meta(__PACKAGE__, {})->{parent};
587             }
588 0         0  
589             $ctx->plan(0, SKIP => $reason);
590             }
591              
592              
593 2     2 1 2 sub exported_to {
594             my( $self, $pack ) = @_;
595 2 100       4  
596 1         2 if( defined $pack ) {
597             $self->{Exported_To} = $pack;
598 2         4 }
599             return $self->{Exported_To};
600             }
601              
602              
603 123     123 1 218 sub ok {
604             my( $self, $test, $name ) = @_;
605 123         257  
606             my $ctx = $self->ctx;
607              
608             # $test might contain an object which we don't want to accidentally
609 123 50       302 # store, so we turn it into a boolean.
610             $test = $test ? 1 : 0;
611              
612 1     1   6 # In case $name is a string overloaded object, force it to stringify.
  1         2  
  1         107  
613 123 100       234 no warnings qw/uninitialized numeric/;
614             $name = "$name" if defined $name;
615              
616             # Profiling showed that the regex here was a huge time waster, doing the
617 123 50 33     303 # numeric addition first cuts our profile time from ~300ms to ~50ms
618             $self->diag(<<" ERR") if 0 + $name && $name =~ /^[\d\s]+$/;
619             You named your test '$name'. You shouldn't use numbers for your test names.
620             Very confusing.
621 1     1   6 ERR
  1         2  
  1         529  
622             use warnings qw/uninitialized numeric/;
623 123         201  
624 123         182 my $trace = $ctx->{trace};
625             my $hub = $ctx->{hub};
626 123 100       474  
627             my $result = {
628             ok => $test,
629             actual_ok => $test,
630             reason => '',
631             type => '',
632             (name => defined($name) ? $name : ''),
633             };
634 123         312  
635             $hub->{_meta}->{+__PACKAGE__}->{Test_Results}[ $hub->{count} ] = $result;
636 123         159  
637             my $orig_name = $name;
638 123         131  
639 123         148 my @attrs;
640 123         134 my $subevents = delete $self->{subevents};
641 123         178 my $subtest_id = delete $self->{subtest_id};
642 123         151 my $subtest_buffered = delete $self->{subtest_buffered};
643 123 50       205 my $epkg = 'Test2::Event::Ok';
644 0         0 if ($subevents) {
645 0         0 $epkg = 'Test2::Event::Subtest';
646             push @attrs => (subevents => $subevents, subtest_id => $subtest_id, buffered => $subtest_buffered);
647             }
648 123         930  
649             my $e = bless {
650             trace => bless( {%$trace}, 'Test2::Util::Trace'),
651             pass => $test,
652             name => $name,
653             _meta => {'Test::Builder' => $result},
654             effective_pass => $test,
655             @attrs,
656 123         488 }, $epkg;
657             $hub->send($e);
658 123 50       199  
659             $self->_ok_debug($trace, $orig_name) unless($test);
660 123         494  
661 123         725 $ctx->release;
662             return $test;
663             }
664              
665 0     0   0 sub _ok_debug {
666 0         0 my $self = shift;
667             my ($trace, $orig_name) = @_;
668 0         0  
669             my $is_todo = defined($self->todo);
670 0 0       0  
671             my $msg = $is_todo ? "Failed (TODO)" : "Failed";
672 0         0  
673 0 0 0     0 my $dfh = $self->_diag_fh;
674             print $dfh "\n" if $ENV{HARNESS_ACTIVE} && $dfh;
675 0         0  
676 0 0       0 my (undef, $file, $line) = $trace->call;
677 0         0 if (defined $orig_name) {
678 0         0 $self->diag(qq[ $msg test '$orig_name'\n]);
679             $self->diag(qq[ at $file line $line.\n]);
680             }
681 0         0 else {
682             $self->diag(qq[ $msg test at $file line $line.\n]);
683             }
684             }
685              
686 0     0   0 sub _diag_fh {
687 0         0 my $self = shift;
688 0 0       0 local $Level = $Level + 1;
689             return $self->in_todo ? $self->todo_output : $self->failure_output;
690             }
691              
692 0     0   0 sub _unoverload {
693             my ($self, $type, $thing) = @_;
694 0 0       0  
695 0 0 0 0   0 return unless ref $$thing;
  0         0  
696             return unless blessed($$thing) || scalar $self->_try(sub{ $$thing->isa('UNIVERSAL') });
697 0         0 {
  0         0  
698 0         0 local ($!, $@);
699             require overload;
700 0   0     0 }
701 0         0 my $string_meth = overload::Method( $$thing, $type ) || return;
702             $$thing = $$thing->$string_meth();
703             }
704              
705 0     0   0 sub _unoverload_str {
706             my $self = shift;
707 0         0  
708             $self->_unoverload( q[""], $_ ) for @_;
709             }
710              
711 0     0   0 sub _unoverload_num {
712             my $self = shift;
713 0         0  
714             $self->_unoverload( '0+', $_ ) for @_;
715 0         0  
716 0 0       0 for my $val (@_) {
717 0         0 next unless $self->_is_dualvar($$val);
718             $$val = $$val + 0;
719             }
720             }
721              
722             # This is a hack to detect a dualvar such as $!
723 0     0   0 sub _is_dualvar {
724             my( $self, $val ) = @_;
725              
726 0 0       0 # Objects are not dualvars.
727             return 0 if ref $val;
728 1     1   6  
  1         1  
  1         862  
729 0         0 no warnings 'numeric';
730 0   0     0 my $numval = $val + 0;
731             return ($numval != 0 and $numval ne $val ? 1 : 0);
732             }
733              
734              
735 0     0 1 0 sub is_eq {
736             my( $self, $got, $expect, $name ) = @_;
737 0         0  
738             my $ctx = $self->ctx;
739 0         0  
740             local $Level = $Level + 1;
741 0 0 0     0  
742             if( !defined $got || !defined $expect ) {
743 0   0     0 # undef only matches undef and nothing else
744             my $test = !defined $got && !defined $expect;
745 0         0  
746 0 0       0 $self->ok( $test, $name );
747 0         0 $self->_is_diag( $got, 'eq', $expect ) unless $test;
748 0         0 $ctx->release;
749             return $test;
750             }
751 0         0  
752             release $ctx, $self->cmp_ok( $got, 'eq', $expect, $name );
753             }
754              
755              
756 0     0 1 0 sub is_num {
757 0         0 my( $self, $got, $expect, $name ) = @_;
758 0         0 my $ctx = $self->ctx;
759             local $Level = $Level + 1;
760 0 0 0     0  
761             if( !defined $got || !defined $expect ) {
762 0   0     0 # undef only matches undef and nothing else
763             my $test = !defined $got && !defined $expect;
764 0         0  
765 0 0       0 $self->ok( $test, $name );
766 0         0 $self->_is_diag( $got, '==', $expect ) unless $test;
767 0         0 $ctx->release;
768             return $test;
769             }
770 0         0  
771             release $ctx, $self->cmp_ok( $got, '==', $expect, $name );
772             }
773              
774              
775 0     0   0 sub _diag_fmt {
776             my( $self, $type, $val ) = @_;
777 0 0       0  
778 0 0 0     0 if( defined $$val ) {
779             if( $type eq 'eq' or $type eq 'ne' ) {
780 0         0 # quote and force string context
781             $$val = "'$$val'";
782             }
783             else {
784 0         0 # force numeric context
785             $self->_unoverload_num($val);
786             }
787             }
788 0         0 else {
789             $$val = 'undef';
790             }
791 0         0  
792             return;
793             }
794              
795              
796 0     0   0 sub _is_diag {
797             my( $self, $got, $type, $expect ) = @_;
798 0         0  
799             $self->_diag_fmt( $type, $_ ) for \$got, \$expect;
800 0         0  
801 0         0 local $Level = $Level + 1;
802             return $self->diag(<<"DIAGNOSTIC");
803             got: $got
804             expected: $expect
805             DIAGNOSTIC
806              
807             }
808              
809 0     0   0 sub _isnt_diag {
810             my( $self, $got, $type ) = @_;
811 0         0  
812             $self->_diag_fmt( $type, \$got );
813 0         0  
814 0         0 local $Level = $Level + 1;
815             return $self->diag(<<"DIAGNOSTIC");
816             got: $got
817             expected: anything else
818             DIAGNOSTIC
819             }
820              
821              
822 0     0 1 0 sub isnt_eq {
823 0         0 my( $self, $got, $dont_expect, $name ) = @_;
824 0         0 my $ctx = $self->ctx;
825             local $Level = $Level + 1;
826 0 0 0     0  
827             if( !defined $got || !defined $dont_expect ) {
828 0   0     0 # undef only matches undef and nothing else
829             my $test = defined $got || defined $dont_expect;
830 0         0  
831 0 0       0 $self->ok( $test, $name );
832 0         0 $self->_isnt_diag( $got, 'ne' ) unless $test;
833 0         0 $ctx->release;
834             return $test;
835             }
836 0         0  
837             release $ctx, $self->cmp_ok( $got, 'ne', $dont_expect, $name );
838             }
839              
840 0     0 1 0 sub isnt_num {
841 0         0 my( $self, $got, $dont_expect, $name ) = @_;
842 0         0 my $ctx = $self->ctx;
843             local $Level = $Level + 1;
844 0 0 0     0  
845             if( !defined $got || !defined $dont_expect ) {
846 0   0     0 # undef only matches undef and nothing else
847             my $test = defined $got || defined $dont_expect;
848 0         0  
849 0 0       0 $self->ok( $test, $name );
850 0         0 $self->_isnt_diag( $got, '!=' ) unless $test;
851 0         0 $ctx->release;
852             return $test;
853             }
854 0         0  
855             release $ctx, $self->cmp_ok( $got, '!=', $dont_expect, $name );
856             }
857              
858              
859 0     0 1 0 sub like {
860 0         0 my( $self, $thing, $regex, $name ) = @_;
861             my $ctx = $self->ctx;
862 0         0  
863             local $Level = $Level + 1;
864 0         0  
865             release $ctx, $self->_regex_ok( $thing, $regex, '=~', $name );
866             }
867              
868 0     0 1 0 sub unlike {
869 0         0 my( $self, $thing, $regex, $name ) = @_;
870             my $ctx = $self->ctx;
871 0         0  
872             local $Level = $Level + 1;
873 0         0  
874             release $ctx, $self->_regex_ok( $thing, $regex, '!~', $name );
875             }
876              
877              
878             my %numeric_cmps = map { ( $_, 1 ) } ( "<", "<=", ">", ">=", "==", "!=", "<=>" );
879              
880             # Bad, these are not comparison operators. Should we include more?
881             my %cmp_ok_bl = map { ( $_, 1 ) } ( "=", "+=", ".=", "x=", "^=", "|=", "||=", "&&=", "...");
882              
883 0     0 1 0 sub cmp_ok {
884 0         0 my( $self, $got, $type, $expect, $name ) = @_;
885             my $ctx = $self->ctx;
886 0 0       0  
887 0         0 if ($cmp_ok_bl{$type}) {
888             $ctx->throw("$type is not a valid comparison operator in cmp_ok()");
889             }
890 0         0  
891 0         0 my ($test, $succ);
892             my $error;
893             {
894             ## no critic (BuiltinFunctions::ProhibitStringyEval)
895 0         0  
  0         0  
896             local( $@, $!, $SIG{__DIE__} ); # isolate eval
897 0         0  
898             my($pack, $file, $line) = $ctx->trace->call();
899              
900 0         0 # This is so that warnings come out at the caller's level
901             $succ = eval qq[
902             #line $line "(eval in cmp_ok) $file"
903             \$test = (\$got $type \$expect);
904             1;
905 0         0 ];
906             $error = $@;
907 0         0 }
908 0         0 local $Level = $Level + 1;
909             my $ok = $self->ok( $test, $name );
910              
911             # Treat overloaded objects as numbers if we're asked to do a
912             # numeric comparison.
913 0 0       0 my $unoverload
914             = $numeric_cmps{$type}
915             ? '_unoverload_num'
916             : '_unoverload_str';
917 0 0       0  
918             $self->diag(<<"END") unless $succ;
919             An error occurred while using $type:
920             ------------------------------------
921             $error
922             ------------------------------------
923             END
924 0 0       0  
925 0         0 unless($ok) {
926             $self->$unoverload( \$got, \$expect );
927 0 0       0  
    0          
928 0         0 if( $type =~ /^(eq|==)$/ ) {
929             $self->_is_diag( $got, $type, $expect );
930             }
931 1     1   6 elsif( $type =~ /^(ne|!=)$/ ) {
  1         3  
  1         51  
932 0   0     0 no warnings;
933             my $eq = ($got eq $expect || $got == $expect)
934             && (
935             (defined($got) xor defined($expect))
936             || (length($got) != length($expect))
937 1     1   5 );
  1         2  
  1         252  
938             use warnings;
939 0 0       0  
940 0         0 if ($eq) {
941             $self->_cmp_diag( $got, $type, $expect );
942             }
943 0         0 else {
944             $self->_isnt_diag( $got, $type );
945             }
946             }
947 0         0 else {
948             $self->_cmp_diag( $got, $type, $expect );
949             }
950 0         0 }
951             return release $ctx, $ok;
952             }
953              
954 0     0   0 sub _cmp_diag {
955             my( $self, $got, $type, $expect ) = @_;
956 0 0       0  
957 0 0       0 $got = defined $got ? "'$got'" : 'undef';
958             $expect = defined $expect ? "'$expect'" : 'undef';
959 0         0  
960 0         0 local $Level = $Level + 1;
961             return $self->diag(<<"DIAGNOSTIC");
962             $got
963             $type
964             $expect
965             DIAGNOSTIC
966             }
967              
968 0     0   0 sub _caller_context {
969             my $self = shift;
970 0         0  
971             my( $pack, $file, $line ) = $self->caller(1);
972 0         0  
973 0 0 0     0 my $code = '';
974             $code .= "#line $line $file\n" if defined $file and defined $line;
975 0         0  
976             return $code;
977             }
978              
979              
980 0     0 1 0 sub BAIL_OUT {
981             my( $self, $reason ) = @_;
982 0         0  
983             my $ctx = $self->ctx;
984 0         0  
985             $self->{Bailed_Out} = 1;
986 0         0  
987             $ctx->bail($reason);
988             }
989              
990              
991 1     1   5 {
  1         2  
  1         515  
992             no warnings 'once';
993             *BAILOUT = \&BAIL_OUT;
994             }
995              
996 0     0 1 0 sub skip {
997 0   0     0 my( $self, $why, $name ) = @_;
998 0 0       0 $why ||= '';
999 0         0 $name = '' unless defined $name;
1000             $self->_unoverload_str( \$why );
1001 0         0  
1002             my $ctx = $self->ctx;
1003 0         0  
1004             $ctx->hub->meta(__PACKAGE__, {})->{Test_Results}[ $ctx->hub->count ] = {
1005             'ok' => 1,
1006             actual_ok => 1,
1007             name => $name,
1008             type => 'skip',
1009             reason => $why,
1010             };
1011 0         0  
1012 0         0 $name =~ s|#|\\#|g; # # in a name can confuse Test::Harness.
1013 0         0 $name =~ s{\n}{\n# }sg;
1014             $why =~ s{\n}{\n# }sg;
1015 0         0  
1016 0         0 my $tctx = $ctx->snapshot;
1017             $tctx->skip('', $why);
1018 0         0  
1019             return release $ctx, 1;
1020             }
1021              
1022              
1023 0     0 1 0 sub todo_skip {
1024 0   0     0 my( $self, $why ) = @_;
1025             $why ||= '';
1026 0         0  
1027             my $ctx = $self->ctx;
1028 0         0  
1029             $ctx->hub->meta(__PACKAGE__, {})->{Test_Results}[ $ctx->hub->count ] = {
1030             'ok' => 1,
1031             actual_ok => 0,
1032             name => '',
1033             type => 'todo_skip',
1034             reason => $why,
1035             };
1036 0         0  
1037 0         0 $why =~ s{\n}{\n# }sg;
1038 0         0 my $tctx = $ctx->snapshot;
1039             $tctx->send_event( 'Skip', todo => $why, todo_diag => 1, reason => $why, pass => 0);
1040 0         0  
1041             return release $ctx, 1;
1042             }
1043              
1044              
1045 0     0 1 0 sub maybe_regex {
1046 0         0 my( $self, $regex ) = @_;
1047             my $usable_regex = undef;
1048 0 0       0  
1049             return $usable_regex unless defined $regex;
1050 0         0  
1051             my( $re, $opts );
1052              
1053 0 0 0     0 # Check for qr/foo/
    0          
1054 0         0 if( _is_qr($regex) ) {
1055             $usable_regex = $regex;
1056             }
1057             # Check for '/foo/' or 'm,foo,'
1058             elsif(( $re, $opts ) = $regex =~ m{^ /(.*)/ (\w*) $ }sx or
1059             ( undef, $re, $opts ) = $regex =~ m,^ m([^\w\s]) (.+) \1 (\w*) $,sx
1060             )
1061 0 0       0 {
1062             $usable_regex = length $opts ? "(?$opts)$re" : $re;
1063             }
1064 0         0  
1065             return $usable_regex;
1066             }
1067              
1068 0     0   0 sub _is_qr {
1069             my $regex = shift;
1070              
1071             # is_regexp() checks for regexes in a robust manner, say if they're
1072 0 0       0 # blessed.
1073 0         0 return re::is_regexp($regex) if defined &re::is_regexp;
1074             return ref $regex eq 'Regexp';
1075             }
1076              
1077 0     0   0 sub _regex_ok {
1078             my( $self, $thing, $regex, $cmp, $name ) = @_;
1079 0         0  
1080 0         0 my $ok = 0;
1081 0 0       0 my $usable_regex = $self->maybe_regex($regex);
1082 0         0 unless( defined $usable_regex ) {
1083 0         0 local $Level = $Level + 1;
1084 0         0 $ok = $self->ok( 0, $name );
1085 0         0 $self->diag(" '$regex' doesn't look much like a regex to me.");
1086             return $ok;
1087             }
1088              
1089 0         0 {
  0         0  
1090 0         0 my $test;
1091             my $context = $self->_caller_context;
1092              
1093             {
1094             ## no critic (BuiltinFunctions::ProhibitStringyEval)
1095 0         0  
  0         0  
1096             local( $@, $!, $SIG{__DIE__} ); # isolate eval
1097              
1098 1     1   7 # No point in issuing an uninit warning, they'll see it in the diagnostics
  1         2  
  1         416  
1099             no warnings 'uninitialized';
1100 0         0  
1101             $test = eval $context . q{$test = $thing =~ /$usable_regex/ ? 1 : 0};
1102             }
1103 0 0       0  
1104             $test = !$test if $cmp eq '!~';
1105 0         0  
1106 0         0 local $Level = $Level + 1;
1107             $ok = $self->ok( $test, $name );
1108             }
1109 0 0       0  
1110 0 0       0 unless($ok) {
1111 0 0       0 $thing = defined $thing ? "'$thing'" : 'undef';
1112             my $match = $cmp eq '=~' ? "doesn't match" : "matches";
1113 0         0  
1114 0         0 local $Level = $Level + 1;
1115             $self->diag( sprintf <<'DIAGNOSTIC', $thing, $match, $regex );
1116             %s
1117             %13s '%s'
1118             DIAGNOSTIC
1119              
1120             }
1121 0         0  
1122             return $ok;
1123             }
1124              
1125              
1126 0     0 1 0 sub is_fh {
1127 0         0 my $self = shift;
1128 0 0       0 my $maybe_fh = shift;
1129             return 0 unless defined $maybe_fh;
1130 0 0       0  
1131 0 0       0 return 1 if ref $maybe_fh eq 'GLOB'; # its a glob ref
1132             return 1 if ref \$maybe_fh eq 'GLOB'; # its a glob
1133              
1134 0   0     0 return eval { $maybe_fh->isa("IO::Handle") } ||
1135             eval { tied($maybe_fh)->can('TIEHANDLE') };
1136             }
1137              
1138              
1139 0     0 1 0 sub level {
1140             my( $self, $level ) = @_;
1141 0 0       0  
1142 0         0 if( defined $level ) {
1143             $Level = $level;
1144 0         0 }
1145             return $Level;
1146             }
1147              
1148              
1149 1     1 1 3 sub use_numbers {
1150             my( $self, $use_nums ) = @_;
1151 1         1  
1152 1         5 my $ctx = $self->ctx;
1153 1 50 33     10 my $format = $ctx->hub->format;
      33        
1154 0 0       0 unless ($format && $format->can('no_numbers') && $format->can('set_no_numbers')) {
1155 0         0 warn "The current formatter does not support 'use_numbers'" if $format;
1156             return release $ctx, 0;
1157             }
1158 1 50       10  
1159             $format->set_no_numbers(!$use_nums) if defined $use_nums;
1160 1 50       2  
1161             return release $ctx, $format->no_numbers ? 0 : 1;
1162             }
1163              
1164 1     1   3 BEGIN {
1165 2         5 for my $method (qw(no_header no_diag)) {
1166             my $set = "set_$method";
1167 1     1   1 my $code = sub {
1168             my( $self, $no ) = @_;
1169 1         2  
1170 1         3 my $ctx = $self->ctx;
1171 1 50 33     6 my $format = $ctx->hub->format;
1172 0 0       0 unless ($format && $format->can($set)) {
1173 0         0 warn "The current formatter does not support '$method'" if $format;
1174             $ctx->release;
1175 0         0 return
1176             }
1177 1 50       11  
1178             $format->$set($no) if defined $no;
1179 1 50       2  
1180 2         5 return release $ctx, $format->$method ? 1 : 0;
1181             };
1182 1     1   6  
  1         2  
  1         31  
1183 2         1218 no strict 'refs'; ## no critic
1184             *$method = $code;
1185             }
1186             }
1187              
1188 1     1 1 2 sub no_ending {
1189             my( $self, $no ) = @_;
1190 1         2  
1191             my $ctx = $self->ctx;
1192 1 50       5  
1193             $ctx->hub->set_no_ending($no) if defined $no;
1194 1         2  
1195             return release $ctx, $ctx->hub->no_ending;
1196             }
1197              
1198 0     0 1 0 sub diag {
1199 0 0       0 my $self = shift;
1200             return unless @_;
1201 0         0  
1202 0 0       0 my $ctx = $self->ctx;
  0         0  
1203 0         0 $ctx->diag(join '' => map {defined($_) ? $_ : 'undef'} @_);
1204 0         0 $ctx->release;
1205             return 0;
1206             }
1207              
1208              
1209 0     0 1 0 sub note {
1210 0 0       0 my $self = shift;
1211             return unless @_;
1212 0         0  
1213 0 0       0 my $ctx = $self->ctx;
  0         0  
1214 0         0 $ctx->note(join '' => map {defined($_) ? $_ : 'undef'} @_);
1215 0         0 $ctx->release;
1216             return 0;
1217             }
1218              
1219              
1220 0     0 1 0 sub explain {
1221             my $self = shift;
1222 0         0  
1223 0         0 local ($@, $!);
1224             require Data::Dumper;
1225              
1226 0         0 return map {
1227 0 0       0 ref $_
1228 0         0 ? do {
1229 0         0 my $dumper = Data::Dumper->new( [$_] );
1230 0 0       0 $dumper->Indent(1)->Terse(1);
1231 0         0 $dumper->Sortkeys(1) if $dumper->can("Sortkeys");
1232             $dumper->Dump;
1233             }
1234             : $_
1235             } @_;
1236             }
1237              
1238              
1239 0     0 1 0 sub output {
1240             my( $self, $fh ) = @_;
1241 0         0  
1242 0         0 my $ctx = $self->ctx;
1243 0         0 my $format = $ctx->hub->format;
1244 0 0 0     0 $ctx->release;
1245             return unless $format && $format->isa('Test2::Formatter::TAP');
1246 0 0       0  
1247             $format->handles->[Test2::Formatter::TAP::OUT_STD()] = $self->_new_fh($fh)
1248             if defined $fh;
1249 0         0  
1250             return $format->handles->[Test2::Formatter::TAP::OUT_STD()];
1251             }
1252              
1253 0     0 1 0 sub failure_output {
1254             my( $self, $fh ) = @_;
1255 0         0  
1256 0         0 my $ctx = $self->ctx;
1257 0         0 my $format = $ctx->hub->format;
1258 0 0 0     0 $ctx->release;
1259             return unless $format && $format->isa('Test2::Formatter::TAP');
1260 0 0       0  
1261             $format->handles->[Test2::Formatter::TAP::OUT_ERR()] = $self->_new_fh($fh)
1262             if defined $fh;
1263 0         0  
1264             return $format->handles->[Test2::Formatter::TAP::OUT_ERR()];
1265             }
1266              
1267 0     0 1 0 sub todo_output {
1268             my( $self, $fh ) = @_;
1269 0         0  
1270 0         0 my $ctx = $self->ctx;
1271 0         0 my $format = $ctx->hub->format;
1272 0 0 0     0 $ctx->release;
1273             return unless $format && $format->isa('Test::Builder::Formatter');
1274 0 0       0  
1275             $format->handles->[Test::Builder::Formatter::OUT_TODO()] = $self->_new_fh($fh)
1276             if defined $fh;
1277 0         0  
1278             return $format->handles->[Test::Builder::Formatter::OUT_TODO()];
1279             }
1280              
1281 0     0   0 sub _new_fh {
1282 0         0 my $self = shift;
1283             my($file_or_fh) = shift;
1284 0         0  
1285 0 0       0 my $fh;
    0          
1286 0         0 if( $self->is_fh($file_or_fh) ) {
1287             $fh = $file_or_fh;
1288             }
1289             elsif( ref $file_or_fh eq 'SCALAR' ) {
1290 0 0       0 # Scalar refs as filehandles was added in 5.8.
1291 0 0       0 if( $] >= 5.008 ) {
1292             open $fh, ">>", $file_or_fh
1293             or $self->croak("Can't open scalar ref $file_or_fh: $!");
1294             }
1295             # Emulate scalar ref filehandles with a tie.
1296 0 0       0 else {
1297             $fh = Test::Builder::IO::Scalar->new($file_or_fh)
1298             or $self->croak("Can't tie scalar ref $file_or_fh");
1299             }
1300             }
1301 0 0       0 else {
1302             open $fh, ">", $file_or_fh
1303 0         0 or $self->croak("Can't open test output log $file_or_fh: $!");
1304             _autoflush($fh);
1305             }
1306 0         0  
1307             return $fh;
1308             }
1309              
1310 0     0   0 sub _autoflush {
1311 0         0 my($fh) = shift;
1312 0         0 my $old_fh = select $fh;
1313 0         0 $| = 1;
1314             select $old_fh;
1315 0         0  
1316             return;
1317             }
1318              
1319              
1320 1     1 1 1 sub reset_outputs {
1321             my $self = shift;
1322 1         1  
1323 1         2 my $ctx = $self->ctx;
1324 1         3 my $format = $ctx->hub->format;
1325 1 50 33     5 $ctx->release;
1326 1 50       2 return unless $format && $format->isa('Test2::Formatter::TAP');
  1         14  
1327             $format->set_handles([@{$self->{Orig_Handles}}]) if $self->{Orig_Handles};
1328 1         2  
1329             return;
1330             }
1331              
1332              
1333 0     0 1 0 sub carp {
1334 0         0 my $self = shift;
1335 0         0 my $ctx = $self->ctx;
1336 0         0 $ctx->alert(join "", @_);
1337             $ctx->release;
1338             }
1339              
1340 0     0 1 0 sub croak {
1341 0         0 my $self = shift;
1342 0         0 my $ctx = $self->ctx;
1343 0         0 $ctx->throw(join "", @_);
1344             $ctx->release;
1345             }
1346              
1347              
1348 0     0 1 0 sub current_test {
1349             my( $self, $num ) = @_;
1350 0         0  
1351 0         0 my $ctx = $self->ctx;
1352             my $hub = $ctx->hub;
1353 0 0       0  
1354 0         0 if( defined $num ) {
1355             $hub->set_count($num);
1356              
1357 0         0 # If the test counter is being pushed forward fill in the details.
1358 0 0       0 my $test_results = $ctx->hub->meta(__PACKAGE__, {})->{Test_Results};
    0          
1359 0 0       0 if( $num > @$test_results ) {
1360 0         0 my $start = @$test_results ? @$test_results : 0;
1361 0         0 for( $start .. $num - 1 ) {
1362             $test_results->[$_] = {
1363             'ok' => 1,
1364             actual_ok => undef,
1365             reason => 'incrementing test number',
1366             type => 'unknown',
1367             name => undef
1368             };
1369             }
1370             }
1371             # If backward, wipe history. Its their funeral.
1372 0         0 elsif( $num < @$test_results ) {
  0         0  
1373             $#{$test_results} = $num - 1;
1374             }
1375 0         0 }
1376             return release $ctx, $hub->count;
1377             }
1378              
1379              
1380 0     0 1 0 sub is_passing {
1381             my $self = shift;
1382 0         0  
1383 0         0 my $ctx = $self->ctx;
1384             my $hub = $ctx->hub;
1385 0 0       0  
1386 0         0 if( @_ ) {
1387 0 0       0 my ($bool) = @_;
1388 0         0 $hub->set_failed(0) if $bool;
1389             $hub->is_passing($bool);
1390             }
1391 0         0  
1392             return release $ctx, $hub->is_passing;
1393             }
1394              
1395              
1396 0     0 1 0 sub summary {
1397             my($self) = shift;
1398 0         0  
1399 0         0 my $ctx = $self->ctx;
1400 0         0 my $data = $ctx->hub->meta(__PACKAGE__, {})->{Test_Results};
1401 0         0 $ctx->release;
  0         0  
1402             return map { $_->{'ok'} } @$data;
1403             }
1404              
1405              
1406 0     0 1 0 sub details {
1407 0         0 my $self = shift;
1408 0         0 my $ctx = $self->ctx;
1409 0         0 my $data = $ctx->hub->meta(__PACKAGE__, {})->{Test_Results};
1410 0         0 $ctx->release;
1411             return @$data;
1412             }
1413              
1414              
1415 0     0 1 0 sub find_TODO {
1416             my( $self, $pack, $set, $new_value ) = @_;
1417 0         0  
1418             my $ctx = $self->ctx;
1419 0   0     0  
      0        
1420 0         0 $pack ||= $ctx->trace->package || $self->exported_to;
1421             $ctx->release;
1422 0 0       0  
1423             return unless $pack;
1424 1     1   7  
  1         1  
  1         30  
1425 1     1   4 no strict 'refs'; ## no critic
  1         2  
  1         117  
1426 0         0 no warnings 'once';
  0         0  
1427 0 0       0 my $old_value = ${ $pack . '::TODO' };
  0         0  
1428 0         0 $set and ${ $pack . '::TODO' } = $new_value;
1429             return $old_value;
1430             }
1431              
1432 0     0 1 0 sub todo {
1433             my( $self, $pack ) = @_;
1434 0         0  
1435 0         0 local $Level = $Level + 1;
1436 0         0 my $ctx = $self->ctx;
1437             $ctx->release;
1438 0         0  
1439 0 0 0     0 my $meta = $ctx->hub->meta(__PACKAGE__, {todo => []})->{todo};
1440             return $meta->[-1]->[1] if $meta && @$meta;
1441 0   0     0  
1442             $pack ||= $ctx->trace->package;
1443 0 0       0  
1444             return unless $pack;
1445 1     1   5  
  1         2  
  1         20  
1446 1     1   4 no strict 'refs'; ## no critic
  1         1  
  1         107  
1447 0         0 no warnings 'once';
  0         0  
1448             return ${ $pack . '::TODO' };
1449             }
1450              
1451 0     0 1 0 sub in_todo {
1452             my $self = shift;
1453 0         0  
1454 0         0 local $Level = $Level + 1;
1455 0         0 my $ctx = $self->ctx;
1456             $ctx->release;
1457 0         0  
1458 0 0 0     0 my $meta = $ctx->hub->meta(__PACKAGE__, {todo => []})->{todo};
1459             return 1 if $meta && @$meta;
1460 0   0     0  
1461             my $pack = $ctx->trace->package || return 0;
1462 1     1   5  
  1         2  
  1         28  
1463 1     1   4 no strict 'refs'; ## no critic
  1         2  
  1         966  
1464 0         0 no warnings 'once';
  0         0  
1465             my $todo = ${ $pack . '::TODO' };
1466 0 0       0  
1467 0 0       0 return 0 unless defined $todo;
1468 0         0 return 0 if "$todo" eq '';
1469             return 1;
1470             }
1471              
1472 0     0 1 0 sub todo_start {
1473 0 0       0 my $self = shift;
1474             my $message = @_ ? shift : '';
1475 0         0  
1476             my $ctx = $self->ctx;
1477 0         0  
1478             my $hub = $ctx->hub;
1479 0     0   0 my $filter = $hub->pre_filter(sub {
1480             my ($active_hub, $e) = @_;
1481              
1482 0 0       0 # Turn a diag into a todo diag
1483             return Test::Builder::TodoDiag->new(%$e) if ref($e) eq 'Test2::Event::Diag';
1484              
1485 0 0 0     0 # Set todo on ok's
1486 0         0 if ($hub == $active_hub && $e->isa('Test2::Event::Ok')) {
1487 0         0 $e->set_todo($message);
1488             $e->set_effective_pass(1);
1489 0 0       0  
1490 0   0     0 if (my $result = $e->get_meta(__PACKAGE__)) {
1491 0   0     0 $result->{reason} ||= $message;
1492 0         0 $result->{type} ||= 'todo';
1493             $result->{ok} = 1;
1494             }
1495             }
1496 0         0  
1497 0         0 return $e;
1498             }, inherit => 1);
1499 0         0  
  0         0  
1500             push @{$ctx->hub->meta(__PACKAGE__, {todo => []})->{todo}} => [$filter, $message];
1501 0         0  
1502             $ctx->release;
1503 0         0  
1504             return;
1505             }
1506              
1507 0     0 1 0 sub todo_end {
1508             my $self = shift;
1509 0         0  
1510             my $ctx = $self->ctx;
1511 0         0  
  0         0  
1512             my $set = pop @{$ctx->hub->meta(__PACKAGE__, {todo => []})->{todo}};
1513 0 0       0  
1514             $ctx->throw('todo_end() called without todo_start()') unless $set;
1515 0         0  
1516             $ctx->hub->pre_unfilter($set->[0]);
1517 0         0  
1518             $ctx->release;
1519 0         0  
1520             return;
1521             }
1522              
1523              
1524 0     0 1 0 sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
1525             my( $self ) = @_;
1526 0         0  
1527             my $ctx = $self->ctx;
1528 0         0  
1529 0         0 my $trace = $ctx->trace;
1530 0 0       0 $ctx->release;
1531             return wantarray ? $trace->call : $trace->package;
1532             }
1533              
1534              
1535 0     0   0 sub _try {
1536             my( $self, $code, %opts ) = @_;
1537 0         0  
1538             my $error;
1539             my $return;
1540 0         0 {
  0         0  
1541 0         0 local $!; # eval can mess up $!
1542 0         0 local $@; # don't set $@ in the test
1543 0         0 local $SIG{__DIE__}; # don't trip an outside DIE handler.
  0         0  
1544 0         0 $return = eval { $code->() };
1545             $error = $@;
1546             }
1547 0 0 0     0  
1548             die $error if $error and $opts{die_on_fail};
1549 0 0       0  
1550             return wantarray ? ( $return, $error ) : $return;
1551             }
1552              
1553 1     1   2 sub _ending {
1554 1         2 my $self = shift;
1555             my ($ctx, $real_exit_code, $new) = @_;
1556 1 50       4  
1557 0         0 unless ($ctx) {
1558 0         0 my $octx = $self->ctx;
1559 0         0 $ctx = $octx->snapshot;
1560             $octx->release;
1561             }
1562 1 50       4  
1563 1 50       3 return if $ctx->hub->no_ending;
1564             return if $ctx->hub->meta(__PACKAGE__, {})->{Ending}++;
1565              
1566             # Don't bother with an ending if this is a forked copy. Only the parent
1567 1 50       4 # should do the ending.
1568             return unless $self->{Original_Pid} == $$;
1569 1         3  
1570 1 50       3 my $hub = $ctx->hub;
1571             return if $hub->bailed_out;
1572 1         4  
1573 1         5 my $plan = $hub->plan;
1574 1         4 my $count = $hub->count;
1575 1         3 my $failed = $hub->failed;
1576 1 0 33     6 my $passed = $hub->is_passing;
      33        
1577             return unless $plan || $count || $failed;
1578              
1579 1 50 33     3 # Ran tests but never declared a plan or hit done_testing
1580 0         0 if( !$hub->plan and $hub->count ) {
1581             $self->diag("Tests were run but no plan was declared and done_testing() was not seen.");
1582 0 0       0  
1583 0         0 if($real_exit_code) {
1584             $self->diag(<<"FAIL");
1585             Looks like your test exited with $real_exit_code just after $count.
1586 0   0     0 FAIL
1587 0         0 $$new ||= $real_exit_code;
1588             return;
1589             }
1590              
1591 0 0       0 # But if the tests ran, handle exit code.
1592 0 0       0 if($failed > 0) {
1593 0   0     0 my $exit_code = $failed <= 254 ? $failed : 254;
1594 0         0 $$new ||= $exit_code;
1595             return;
1596             }
1597 0   0     0  
1598 0         0 $$new ||= 254;
1599             return;
1600             }
1601 1 50 33     4  
1602 0         0 if ($real_exit_code && !$count) {
1603 0   0     0 $self->diag("Looks like your test exited with $real_exit_code before it could output anything.");
1604 0         0 $$new ||= $real_exit_code;
1605             return;
1606             }
1607 1 50 33     7  
1608             return if $plan && "$plan" eq 'SKIP';
1609 1 50       3  
1610 0         0 if (!$count) {
1611 0   0     0 $self->diag('No tests run!');
1612 0         0 $$new ||= 255;
1613             return;
1614             }
1615 1 50       4  
1616 0         0 if ($real_exit_code) {
1617             $self->diag(<<"FAIL");
1618             Looks like your test exited with $real_exit_code just after $count.
1619 0   0     0 FAIL
1620 0         0 $$new ||= $real_exit_code;
1621             return;
1622             }
1623 1 50       3  
1624 0         0 if ($plan eq 'NO PLAN') {
1625 0         0 $ctx->plan( $count );
1626             $plan = $hub->plan;
1627             }
1628              
1629 1         2 # Figure out if we passed or failed and print helpful messages.
1630             my $num_extra = $count - $plan;
1631 1 50       4  
1632 0 0       0 if ($num_extra != 0) {
1633 0         0 my $s = $plan == 1 ? '' : 's';
1634             $self->diag(<<"FAIL");
1635             Looks like you planned $plan test$s but ran $count.
1636             FAIL
1637             }
1638 1 50       3  
1639 0 0       0 if ($failed) {
1640             my $s = $failed == 1 ? '' : 's';
1641 0 0       0  
1642             my $qualifier = $num_extra == 0 ? '' : ' run';
1643 0         0  
1644             $self->diag(<<"FAIL");
1645             Looks like you failed $failed test$s of $count$qualifier.
1646             FAIL
1647             }
1648 1 0 33     5  
      33        
      33        
1649 0         0 if (!$passed && !$failed && $count && !$num_extra) {
1650             $ctx->diag(<<"FAIL");
1651             All assertions passed, but errors were encountered.
1652             FAIL
1653             }
1654 1         1  
1655 1 50       7 my $exit_code = 0;
    50          
    50          
1656 0 0       0 if ($failed) {
1657             $exit_code = $failed <= 254 ? $failed : 254;
1658             }
1659 0         0 elsif ($num_extra != 0) {
1660             $exit_code = 255;
1661             }
1662 0         0 elsif (!$passed) {
1663             $exit_code = 255;
1664             }
1665 1   33     6  
1666 1         3 $$new ||= $exit_code;
1667             return;
1668             }
1669              
1670             # Some things used this even though it was private... I am looking at you
1671             # Test::Builder::Prefix...
1672 0     0     sub _print_comment {
1673             my( $self, $fh, @msgs ) = @_;
1674 0 0          
1675 0 0         return if $self->no_diag;
1676             return unless @msgs;
1677              
1678 0 0         # Prevent printing headers when compiling (i.e. -c)
1679             return if $^C;
1680              
1681             # Smash args together like print does.
1682 0 0         # Convert undef to 'undef' so its readable.
  0            
1683             my $msg = join '', map { defined($_) ? $_ : 'undef' } @msgs;
1684              
1685 0           # Escape the beginning, _print will take care of the rest.
1686             $msg =~ s/^/# /;
1687 0            
1688 0           local( $\, $", $, ) = ( undef, ' ', '' );
1689             print $fh $msg;
1690 0            
1691             return 0;
1692             }
1693              
1694             # This is used by Test::SharedFork to turn on IPC after the fact. Not
1695             # documenting because I do not want it used. The method name is borrowed from
1696             # Test::Builder 2
1697             # Once Test2 stuff goes stable this method will be removed and Test::SharedFork
1698             # will be made smarter.
1699 0     0 0   sub coordinate_forks {
1700             my $self = shift;
1701              
1702 0           {
  0            
1703 0           local ($@, $!);
1704             require Test2::IPC;
1705 0           }
1706 0           Test2::IPC->import;
1707 0           Test2::API::test2_ipc_enable_polling();
1708 0           my $ipc = Test2::IPC::apply_ipc($self->{Stack});
1709 0           $ipc->set_no_fatal(1);
1710 0           Test2::API::test2_no_wait(1);
1711             Test2::API::test2_ipc_enable_shm();
1712             }
1713              
1714             1;
1715              
1716             __END__