File Coverage

inc/Test/Builder.pm
Criterion Covered Total %
statement 455 880 51.7
branch 106 392 27.0
condition 53 252 21.0
subroutine 68 109 62.3
pod 47 52 90.3
total 729 1685 43.2


line stmt bran cond sub pod time code
1             #line 1
2             package Test::Builder;
3 6     6   97  
  6         22  
4 6     6   43 use 5.006;
  6         10  
  6         123  
5 6     6   32 use strict;
  6         16  
  6         384  
6             use warnings;
7              
8             our $VERSION = '1.302073';
9              
10 6 50   6   208 BEGIN {
11 0         0 if( $] < 5.008 ) {
12             require Test::Builder::IO::Scalar;
13             }
14             }
15 6     6   44  
  6         12  
  6         550  
16             use Scalar::Util qw/blessed reftype weaken/;
17 6     6   2560  
  6         15  
  6         431  
18 6     6   2817 use Test2::Util qw/USE_THREADS try get_tid/;
  6         21  
  6         866  
19             use Test2::API qw/context release/;
20             # Make Test::Builder thread-safe for ithreads.
21 6 50 33 6   31 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 6         131  
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 6     6   41  
  6         11  
  6         156  
35 6     6   35 use Test2::Event::Subtest;
  6         12  
  6         176  
36             use Test2::Hub::Subtest;
37 6     6   2569  
  6         17  
  6         42  
38 6     6   2562 use Test::Builder::Formatter;
  6         16  
  6         701  
39             use Test::Builder::TodoDiag;
40              
41             our $Level = 1;
42             our $Test = $ENV{TB_NO_EARLY_INIT} ? undef : Test::Builder->new;
43              
44 15     15   32 sub _add_ts_hooks {
45 15         63 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 15         43 # in rare cases.
51             my $epkgr = \$self->{Exported_To};
52              
53             #$hub->add_context_aquire(sub {$_[0]->{level} += $Level - 1});
54              
55 111     111   236 $hub->pre_filter(sub {
56             my ($active_hub, $e) = @_;
57 111         209  
58 111 50       382 my $epkg = $$epkgr;
59             my $cpkg = $e->{trace} ? $e->{trace}->{frame}->[0] : undef;
60 6     6   45  
  6         11  
  6         219  
61 6     6   53 no strict 'refs';
  6         14  
  6         20639  
62 111         176 no warnings 'once';
63 111 50       216 my $todo;
  111         331  
64 111 100 66     373 $todo = ${"$cpkg\::TODO"} if $cpkg;
  96         197  
65             $todo = ${"$epkg\::TODO"} if $epkg && !$todo;
66 111 50       354  
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 15         174 return $e;
85             }, inherit => 1);
86             }
87              
88 89     89 1 249 sub new {
89 89 100       295 my($class) = shift;
90 6         213 unless($Test) {
91 6         39 my $ctx = context();
92 6         39 $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 6     195   47 # TB->ctx compensates for this later.
  195         595  
98             Test2::API::test2_add_callback_context_aquire(sub { $_[0]->{level} += $Level - 1 });
99 6     6   40  
  6         42  
100             Test2::API::test2_add_callback_exit(sub { $Test->_ending(@_) });
101 6         23  
102             Test2::API::test2_ipc()->set_no_fatal(1) if USE_THREADS;
103 89         232 }
104             return $Test;
105             }
106              
107 6     6 1 16 sub create {
108 6         19 my $class = shift;
109             my %params = @_;
110 6         15  
111 6 50       27 my $self = bless {}, $class;
112 6         76 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 6         34 }
122 6         23 $self->reset(%params);
123             $self->_add_ts_hooks;
124 6         14  
125             return $self;
126             }
127              
128 225     225 0 430 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 225         982 hub => $self->{Hub},
136             wrapped => 1,
137             @_
138             );
139             }
140              
141 9     9 0 22 sub parent {
142 9         24 my $self = shift;
143 9   33     46 my $ctx = $self->ctx;
144 9         37 my $chub = $self->{Hub} || $ctx->hub;
145             $ctx->release;
146 9         89  
147 9         41 my $meta = $chub->meta(__PACKAGE__, {});
148             my $parent = $meta->{parent};
149 9 50       30  
150             return undef unless $parent;
151              
152             return bless {
153             Original_Pid => $$,
154 9         93 Stack => $self->{Stack},
155             Hub => $parent,
156             }, blessed($self);
157             }
158              
159 9     9 0 30 sub child {
160             my( $self, $name ) = @_;
161 9   33     27  
162 9         26 $name ||= "Child of " . $self->name;
163             my $ctx = $self->ctx;
164 9         51  
165 9         56 my $parent = $ctx->hub;
166             my $pmeta = $parent->meta(__PACKAGE__, {});
167 9 50       36 $self->croak("You already have a child named ($pmeta->{child}) running")
168             if $pmeta->{child};
169 9         30  
170             $pmeta->{child} = $name;
171              
172 9         46 # Clear $TODO for the child.
173             my $orig_TODO = $self->find_TODO(undef, 1, undef);
174 9         37  
175             my $subevents = [];
176 9         42  
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 9 50       31 return $e;
188             }, inherit => 1) if $orig_TODO;
189 9     34   96  
  34         115  
190             $hub->listen(sub { push @$subevents => $_[1] });
191 9 50       102  
192             $hub->set_nested( $parent->isa('Test2::Hub::Subtest') ? $parent->nested + 1 : 1 );
193 9         54  
194 9         29 my $meta = $hub->meta(__PACKAGE__, {});
195 9         21 $meta->{Name} = $name;
196 9         34 $meta->{TODO} = $orig_TODO;
197 9         28 $meta->{TODO_PKG} = $ctx->trace->package;
198 9         25 $meta->{parent} = $parent;
199 9         46 $meta->{Test_Results} = [];
200 9         36 $meta->{subevents} = $subevents;
201 9 50       36 $meta->{subtest_id} = $hub->id;
202             $meta->{subtest_buffered} = $parent->format ? 0 : 1;
203 9         43  
204             $self->_add_ts_hooks;
205 9         42  
206 9         98 $ctx->release;
207             return bless { Original_Pid => $$, Stack => $self->{Stack}, Hub => $hub }, blessed($self);
208             }
209              
210 9     9 0 37 sub finalize {
211 9         21 my $self = shift;
212 9 50       36 my $ok = 1;
213             ($ok) = @_ if @_;
214 9         25  
215 9   50     40 my $st_ctx = $self->ctx;
216             my $chub = $self->{Hub} || return $st_ctx->release;
217 9         36  
218 9 50       66 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 9         45  
223             local $? = 0; # don't fail if $subtests happened to set $? nonzero
224 9         77  
225             $self->{Stack}->pop($chub);
226 9         56  
227             $self->find_TODO($meta->{TODO_PKG}, 1, $meta->{TODO});
228 9         46  
229 9         32 my $parent = $self->parent;
230 9         39 my $ctx = $parent->ctx;
231 9         30 my $trace = $ctx->trace;
232             delete $ctx->hub->meta(__PACKAGE__, {})->{child};
233 9 50 33     108  
      33        
      33        
234             $chub->finalize($trace, 1)
235             if $ok
236             && $chub->count
237             && !$chub->no_ending
238             && !$chub->ended;
239 9   50     28  
240 9         30 my $plan = $chub->plan || 0;
241 9         83 my $count = $chub->count;
242 9         25 my $failed = $chub->failed;
243             my $passed = $chub->is_passing;
244 9 50       73  
245 9 50 33     52 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 9 50       43  
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 9 0 33     45  
      33        
      33        
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 9         47  
269             $st_ctx->release;
270 9 50       33  
271 9         25 unless ($chub->bailed_out) {
272 9 50 33     85 my $plan = $chub->plan;
    50          
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 9         25 else {
280 9         23 $parent->{subevents} = $meta->{subevents};
281 9         23 $parent->{subtest_id} = $meta->{subtest_id};
282 9         45 $parent->{subtest_buffered} = $meta->{subtest_buffered};
283             $parent->ok( $chub->is_passing, $meta->{Name} );
284             }
285             }
286 9         38  
287 9         38 $ctx->release;
288             return $chub->is_passing;
289             }
290              
291 9     9 1 43 sub subtest {
292 9         31 my $self = shift;
293 9         33 my ($name, $code, @args) = @_;
294 9 50 33     96 my $ctx = $self->ctx;
295             $ctx->throw("subtest()'s second argument must be a code ref")
296             unless $code && reftype($code) eq 'CODE';
297 9   33     37  
298             $name ||= "Child of " . $self->name;
299 9         66  
300             $ctx->note("Subtest: $name");
301 9         60  
302             my $child = $self->child($name);
303 9         24  
304 9         14 my $start_pid = $$;
305 9         21 my $st_ctx;
306             my ($ok, $err, $finished, $child_error);
307 9         17 T2_SUBTEST_WRAPPER: {
  9         26  
308 9         49 my $ctx = $self->ctx;
309 9         39 $st_ctx = $ctx->snapshot;
310 9         20 $ctx->release;
  9         30  
  9         38  
  9         1035  
311 9         34 $ok = eval { local $Level = 1; $code->(@args); 1 };
312             ($err, $child_error) = ($@, $?);
313              
314 9 50 33     87 # They might have done 'BEGIN { skip_all => "whatever" }'
      33        
      33        
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 9         32 else {
320             $finished = 1;
321             }
322             }
323 9 50 33     83  
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 9         37  
329             my $trace = $ctx->trace;
330 9 50       31  
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 9         29  
342 9         29 my $st_hub = $st_ctx->hub;
343 9         32 my $plan = $st_hub->plan;
344             my $count = $st_hub->count;
345 9 0 0     34  
      33        
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 9         47  
351             $child->finalize($st_ctx->trace);
352 9         34  
353             $ctx->release;
354 9 50       31  
355             die $err unless $ok;
356 9 50       32  
357             $? = $child_error if defined $child_error;
358 9         28  
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 6     6 1 18 sub reset { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
369             my ($self, %params) = @_;
370 6         34  
371             Test2::API::test2_set_is_end(0);
372              
373             # We leave this a global because it has to be localized and localizing
374 6         12 # hash keys is just asking for pain. Also, it was documented.
375             $Level = 1;
376 6         26  
377             $self->{Original_Pid} = $$;
378 6         49  
379 6 50       28 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 6         33  
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 6         46 parent => $meta->{parent},
394             );
395 6         16  
396             $self->{Exported_To} = undef;
397 6   33     30  
398 6         40 $self->{Orig_Handles} ||= do {
399 6         24 my $format = $ctx->hub->format;
400 6 50 33     95 my $out;
401 6         39 if ($format && $format->isa('Test2::Formatter::TAP')) {
402             $out = $format->handles;
403 6 50       47 }
404             $out ? [@$out] : [];
405             };
406 6         34  
407 6         48 $self->use_numbers(1);
408 6         25 $self->no_header(0);
409 6         23 $self->no_ending(0);
410             $self->reset_outputs;
411 6         21  
412             $ctx->release;
413 6         17  
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 6     6 1 20 sub plan {
425             my( $self, $cmd, $arg ) = @_;
426 6 100       22  
427             return unless $cmd;
428 1         3  
429 1         5 my $ctx = $self->ctx;
430             my $hub = $ctx->hub;
431 1 50       5  
432             $ctx->throw("You tried to plan twice") if $hub->plan;
433 1         2  
434             local $Level = $Level + 1;
435 1 50       4  
436 1         1 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         4  
445             release $ctx, 1;
446             }
447              
448              
449 0     0   0 sub _plan_tests {
450             my($self, $arg) = @_;
451 0         0  
452             my $ctx = $self->ctx;
453 0 0       0  
    0          
454 0         0 if($arg) {
455 0         0 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 0         0  
465             $ctx->release;
466             }
467              
468              
469 14     14 1 31 sub expected_tests {
470 14         209 my $self = shift;
471             my($max) = @_;
472 14         37  
473             my $ctx = $self->ctx;
474 14 50       56  
475 0 0       0 if(@_) {
476             $self->croak("Number of tests must be a positive integer. You gave it '$max'")
477             unless $max =~ /^\+?\d+$/;
478 0         0  
479             $ctx->plan($max);
480             }
481 14         46  
482             my $hub = $ctx->hub;
483 14         59  
484             $ctx->release;
485 14         200  
486 14 50       68 my $plan = $hub->plan;
487 0 0       0 return 0 unless $plan;
488 0         0 return 0 if $plan =~ m/\D/;
489             return $plan;
490             }
491              
492              
493 1     1 1 3 sub no_plan {
494             my($self, $arg) = @_;
495 1         2  
496             my $ctx = $self->ctx;
497 1 50       4  
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 1 50       4  
504             $ctx->alert("no_plan takes no arguments") if $arg;
505 1         3  
506             $ctx->hub->plan('NO PLAN');
507 1         4  
508             release $ctx, 1;
509             }
510              
511              
512 14     14 1 49 sub done_testing {
513             my($self, $num_tests) = @_;
514 14         40  
515             my $ctx = $self->ctx;
516 14         67  
517             my $meta = $ctx->hub->meta(__PACKAGE__, {});
518 14 50       55  
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 14         82 }
526             $meta->{Done_Testing} = [$ctx->trace->call];
527 14         49  
528 14         41 my $plan = $ctx->hub->plan;
529             my $count = $ctx->hub->count;
530              
531 14 50 33     113 # If done_testing() specified the number of tests, shut off no_plan
    50 33        
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 14         51 else {
539             $num_tests = $self->current_test;
540             }
541 14 50 33     64  
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 14 50 33     48  
547             $ctx->plan($num_tests) if $ctx->hub->plan && $ctx->hub->plan eq 'NO PLAN';
548 14         65  
549             $ctx->hub->finalize($ctx->trace, 1);
550 14         50  
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 10     10 1 21 sub exported_to {
594             my( $self, $pack ) = @_;
595 10 100       32  
596 5         13 if( defined $pack ) {
597             $self->{Exported_To} = $pack;
598 10         25 }
599             return $self->{Exported_To};
600             }
601              
602              
603 53     53 1 147 sub ok {
604             my( $self, $test, $name ) = @_;
605 53         162  
606             my $ctx = $self->ctx;
607              
608             # $test might contain an object which we don't want to accidentally
609 53 50       190 # store, so we turn it into a boolean.
610             $test = $test ? 1 : 0;
611              
612 6     6   56 # In case $name is a string overloaded object, force it to stringify.
  6         13  
  6         831  
613 53 100       178 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 53 50 33     305 # 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 6     6   46 ERR
  6         12  
  6         4340  
622             use warnings qw/uninitialized numeric/;
623 53         108  
624 53         110 my $trace = $ctx->{trace};
625             my $hub = $ctx->{hub};
626 53 100       307  
627             my $result = {
628             ok => $test,
629             actual_ok => $test,
630             reason => '',
631             type => '',
632             (name => defined($name) ? $name : ''),
633             };
634 53         221  
635             $hub->{_meta}->{+__PACKAGE__}->{Test_Results}[ $hub->{count} ] = $result;
636 53         89  
637             my $orig_name = $name;
638 53         90  
639 53         97 my @attrs;
640 53         95 my $subevents = delete $self->{subevents};
641 53         1473 my $subtest_id = delete $self->{subtest_id};
642 53         88 my $subtest_buffered = delete $self->{subtest_buffered};
643 53 100       125 my $epkg = 'Test2::Event::Ok';
644 9         19 if ($subevents) {
645 9         31 $epkg = 'Test2::Event::Subtest';
646             push @attrs => (subevents => $subevents, subtest_id => $subtest_id, buffered => $subtest_buffered);
647             }
648 53         556  
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 53         272 }, $epkg;
657             $hub->send($e);
658 53 50       138  
659             $self->_ok_debug($trace, $orig_name) unless($test);
660 53         245  
661 53         342 $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 20     20   43 sub _unoverload {
693             my ($self, $type, $thing) = @_;
694 20 50       59  
695 20 50 50 20   125 return unless ref $$thing;
  20         192  
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 10     10   20 sub _unoverload_str {
706             my $self = shift;
707 10         39  
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 6     6   48  
  6         13  
  6         7020  
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 12     12 1 41 sub is_eq {
736             my( $self, $got, $expect, $name ) = @_;
737 12         33  
738             my $ctx = $self->ctx;
739 12         35  
740             local $Level = $Level + 1;
741 12 100 66     64  
742             if( !defined $got || !defined $expect ) {
743 2   33     8 # undef only matches undef and nothing else
744             my $test = !defined $got && !defined $expect;
745 2         8  
746 2 50       7 $self->ok( $test, $name );
747 2         7 $self->_is_diag( $got, 'eq', $expect ) unless $test;
748 2         7 $ctx->release;
749             return $test;
750             }
751 10         61  
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 1     1 1 5 sub isnt_eq {
823 1         2 my( $self, $got, $dont_expect, $name ) = @_;
824 1         5 my $ctx = $self->ctx;
825             local $Level = $Level + 1;
826 1 50 33     7  
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 1         66  
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 1     1 1 4 sub like {
860 1         14 my( $self, $thing, $regex, $name ) = @_;
861             my $ctx = $self->ctx;
862 1         5  
863             local $Level = $Level + 1;
864 1         5  
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 11     11 1 42 sub cmp_ok {
884 11         28 my( $self, $got, $type, $expect, $name ) = @_;
885             my $ctx = $self->ctx;
886 11 50       55  
887 0         0 if ($cmp_ok_bl{$type}) {
888             $ctx->throw("$type is not a valid comparison operator in cmp_ok()");
889             }
890 11         37  
891 11         0 my ($test, $succ);
892             my $error;
893             {
894             ## no critic (BuiltinFunctions::ProhibitStringyEval)
895 11         20  
  11         67  
896             local( $@, $!, $SIG{__DIE__} ); # isolate eval
897 11         54  
898             my($pack, $file, $line) = $ctx->trace->call();
899              
900 11         882 # 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 11         201 ];
906             $error = $@;
907 11         35 }
908 11         48 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 11 50       53 my $unoverload
914             = $numeric_cmps{$type}
915             ? '_unoverload_num'
916             : '_unoverload_str';
917 11 50       35  
918             $self->diag(<<"END") unless $succ;
919             An error occurred while using $type:
920             ------------------------------------
921             $error
922             ------------------------------------
923             END
924 11 50       34  
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 6     6   49 elsif( $type =~ /^(ne|!=)$/ ) {
  6         13  
  6         432  
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 6     6   41 );
  6         13  
  6         2115  
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 11         46 }
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 1     1   4 sub _caller_context {
969             my $self = shift;
970 1         4  
971             my( $pack, $file, $line ) = $self->caller(1);
972 1         3  
973 1 50 33     23 my $code = '';
974             $code .= "#line $line $file\n" if defined $file and defined $line;
975 1         10  
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 6     6   47 {
  6         13  
  6         4371  
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 1     1 1 3 sub maybe_regex {
1046 1         3 my( $self, $regex ) = @_;
1047             my $usable_regex = undef;
1048 1 50       4  
1049             return $usable_regex unless defined $regex;
1050 1         3  
1051             my( $re, $opts );
1052              
1053 1 50 0     4 # Check for qr/foo/
    0          
1054 1         3 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 1         3  
1065             return $usable_regex;
1066             }
1067              
1068 1     1   3 sub _is_qr {
1069             my $regex = shift;
1070              
1071             # is_regexp() checks for regexes in a robust manner, say if they're
1072 1 50       7 # blessed.
1073 0         0 return re::is_regexp($regex) if defined &re::is_regexp;
1074             return ref $regex eq 'Regexp';
1075             }
1076              
1077 1     1   5 sub _regex_ok {
1078             my( $self, $thing, $regex, $cmp, $name ) = @_;
1079 1         3  
1080 1         5 my $ok = 0;
1081 1 50       4 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 1         13 {
  1         2  
1090 1         5 my $test;
1091             my $context = $self->_caller_context;
1092              
1093             {
1094             ## no critic (BuiltinFunctions::ProhibitStringyEval)
1095 1         5  
  1         6  
1096             local( $@, $!, $SIG{__DIE__} ); # isolate eval
1097              
1098 6     6   49 # No point in issuing an uninit warning, they'll see it in the diagnostics
  6         20  
  6         3437  
1099             no warnings 'uninitialized';
1100 1         70  
1101             $test = eval $context . q{$test = $thing =~ /$usable_regex/ ? 1 : 0};
1102             }
1103 1 50       25  
1104             $test = !$test if $cmp eq '!~';
1105 1         5  
1106 1         4 local $Level = $Level + 1;
1107             $ok = $self->ok( $test, $name );
1108             }
1109 1 50       5  
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 1         4  
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 6     6 1 18 sub use_numbers {
1150             my( $self, $use_nums ) = @_;
1151 6         16  
1152 6         32 my $ctx = $self->ctx;
1153 6 50 33     116 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 6 50       41  
1159             $format->set_no_numbers(!$use_nums) if defined $use_nums;
1160 6 50       18  
1161             return release $ctx, $format->no_numbers ? 0 : 1;
1162             }
1163              
1164 6     6   20 BEGIN {
1165 12         33 for my $method (qw(no_header no_diag)) {
1166             my $set = "set_$method";
1167 6     6   27 my $code = sub {
1168             my( $self, $no ) = @_;
1169 6         26  
1170 6         44 my $ctx = $self->ctx;
1171 6 50 33     55 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 6 50       49  
1178             $format->$set($no) if defined $no;
1179 6 50       20  
1180 12         51 return release $ctx, $format->$method ? 1 : 0;
1181             };
1182 6     6   50  
  6         14  
  6         203  
1183 12         8789 no strict 'refs'; ## no critic
1184             *$method = $code;
1185             }
1186             }
1187              
1188 6     6 1 14 sub no_ending {
1189             my( $self, $no ) = @_;
1190 6         21  
1191             my $ctx = $self->ctx;
1192 6 50       51  
1193             $ctx->hub->set_no_ending($no) if defined $no;
1194 6         42  
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 6     6 1 14 sub reset_outputs {
1321             my $self = shift;
1322 6         66  
1323 6         35 my $ctx = $self->ctx;
1324 6         29 my $format = $ctx->hub->format;
1325 6 50 33     61 $ctx->release;
1326 6 50       25 return unless $format && $format->isa('Test2::Formatter::TAP');
  6         79  
1327             $format->set_handles([@{$self->{Orig_Handles}}]) if $self->{Orig_Handles};
1328 6         21  
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 14     14 1 83 sub current_test {
1349             my( $self, $num ) = @_;
1350 14         40  
1351 14         71 my $ctx = $self->ctx;
1352             my $hub = $ctx->hub;
1353 14 50       48  
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 14         44 }
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 18     18 1 53 sub find_TODO {
1416             my( $self, $pack, $set, $new_value ) = @_;
1417 18         55  
1418             my $ctx = $self->ctx;
1419 18   33     98  
      66        
1420 18         76 $pack ||= $ctx->trace->package || $self->exported_to;
1421             $ctx->release;
1422 18 50       54  
1423             return unless $pack;
1424 6     6   50  
  6         14  
  6         271  
1425 6     6   40 no strict 'refs'; ## no critic
  6         13  
  6         944  
1426 18         33 no warnings 'once';
  18         72  
1427 18 50       61 my $old_value = ${ $pack . '::TODO' };
  18         42  
1428 18         70 $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 6     6   42  
  6         20  
  6         223  
1446 6     6   36 no strict 'refs'; ## no critic
  6         10  
  6         932  
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 6     6   43  
  6         13  
  6         196  
1463 6     6   32 no strict 'refs'; ## no critic
  6         11  
  6         7749  
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 1     1 1 3 sub caller { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
1525             my( $self ) = @_;
1526 1         3  
1527             my $ctx = $self->ctx;
1528 1         5  
1529 1         4 my $trace = $ctx->trace;
1530 1 50       17 $ctx->release;
1531             return wantarray ? $trace->call : $trace->package;
1532             }
1533              
1534              
1535 23     23   54 sub _try {
1536             my( $self, $code, %opts ) = @_;
1537 23         37  
1538             my $error;
1539             my $return;
1540 23         36 {
  23         110  
1541 23         34 local $!; # eval can mess up $!
1542 23         76 local $@; # don't set $@ in the test
1543 23         46 local $SIG{__DIE__}; # don't trip an outside DIE handler.
  23         52  
1544 23         131 $return = eval { $code->() };
1545             $error = $@;
1546             }
1547 23 50 66     96  
1548             die $error if $error and $opts{die_on_fail};
1549 23 100       140  
1550             return wantarray ? ( $return, $error ) : $return;
1551             }
1552              
1553 6     6   16 sub _ending {
1554 6         24 my $self = shift;
1555             my ($ctx, $real_exit_code, $new) = @_;
1556 6 50       23  
1557 0         0 unless ($ctx) {
1558 0         0 my $octx = $self->ctx;
1559 0         0 $ctx = $octx->snapshot;
1560             $octx->release;
1561             }
1562 6 50       24  
1563 6 50       23 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 6 50       48 # should do the ending.
1568             return unless $self->{Original_Pid} == $$;
1569 6         22  
1570 6 50       41 my $hub = $ctx->hub;
1571             return if $hub->bailed_out;
1572 6         22  
1573 6         24 my $plan = $hub->plan;
1574 6         23 my $count = $hub->count;
1575 6         23 my $failed = $hub->failed;
1576 6 0 33     30 my $passed = $hub->is_passing;
      33        
1577             return unless $plan || $count || $failed;
1578              
1579 6 50 33     30 # 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 6 50 33     41  
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 6 50 33     64  
1608             return if $plan && "$plan" eq 'SKIP';
1609 6 50       25  
1610 0         0 if (!$count) {
1611 0   0     0 $self->diag('No tests run!');
1612 0         0 $$new ||= 255;
1613             return;
1614             }
1615 6 50       23  
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 6 50       34  
1624 0         0 if ($plan eq 'NO PLAN') {
1625 0         0 $ctx->plan( $count );
1626             $plan = $hub->plan;
1627             }
1628              
1629 6         18 # Figure out if we passed or failed and print helpful messages.
1630             my $num_extra = $count - $plan;
1631 6 50       23  
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 6 50       21  
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 6 0 33     53  
      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 6         18  
1655 6 50       43 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 6   33     38  
1666 6         26 $$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__