File Coverage

inc/Test/Builder.pm
Criterion Covered Total %
statement 341 947 36.0
branch 80 440 18.1
condition 24 253 9.4
subroutine 70 124 56.4
pod 48 53 90.5
total 563 1817 30.9


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