File Coverage

blib/lib/Test2/API.pm
Criterion Covered Total %
statement 345 388 88.9
branch 114 150 76.0
condition 72 125 57.6
subroutine 95 106 89.6
pod 50 62 80.6
total 676 831 81.3


line stmt bran cond sub pod time code
1             package Test2::API;
2 246     246   10224 use strict;
  246         529  
  246         7616  
3 246     246   1191 use warnings;
  246         449  
  246         7273  
4              
5 246     246   6727 use Test2::Util qw/USE_THREADS/;
  246         426  
  246         15053  
6              
7             BEGIN {
8 246   50 246   4117 $ENV{TEST_ACTIVE} ||= 1;
9 246         64271 $ENV{TEST2_ACTIVE} = 1;
10             }
11              
12             our $VERSION = '1.302180';
13              
14              
15             my $INST;
16             my $ENDING = 0;
17 217     217 0 597 sub test2_unset_is_end { $ENDING = 0 }
18 3     3 1 16 sub test2_get_is_end { $ENDING }
19              
20             sub test2_set_is_end {
21 749     749 1 1705 my $before = $ENDING;
22 749 50       3219 ($ENDING) = @_ ? @_ : (1);
23              
24             # Only send the event in a transition from false to true
25 749 100       4946 return if $before;
26 247 50       1241 return unless $ENDING;
27              
28 247 50       1116 return unless $INST;
29 247 50       2215 my $stack = $INST->stack or return;
30 247 100       2073 my $root = $stack->root or return;
31              
32 246 100       1793 return unless $root->count;
33              
34 218 100       1916 return unless $$ == $INST->pid;
35 211 50       1843 return unless get_tid() == $INST->tid;
36              
37 211         2295 my $trace = Test2::EventFacet::Trace->new(
38             frame => [__PACKAGE__, __FILE__, __LINE__, __PACKAGE__ . '::test2_set_is_end'],
39             );
40 211         1324 my $ctx = Test2::API::Context->new(
41             trace => $trace,
42             hub => $root,
43             );
44              
45 211         2275 $ctx->send_ev2(control => { phase => 'END', details => 'Transition to END phase' });
46              
47 211         1105 1;
48             }
49              
50 246     246   113157 use Test2::API::Instance(\$INST);
  246         764  
  246         1350  
51              
52             # Set the exit status
53             END {
54 246     246   1805 test2_set_is_end(); # See gh #16
55 246         1804 $INST->set_exit();
56             }
57              
58             sub CLONE {
59 0     0   0 my $init = test2_init_done();
60 0         0 my $load = test2_load_done();
61              
62 0 0 0     0 return if $init && $load;
63              
64 0         0 require Carp;
65 0         0 Carp::croak "Test2 must be fully loaded before you start a new thread!\n";
66             }
67              
68             # See gh #16
69             {
70 246     246   1967 no warnings;
  246         561  
  246         21002  
71 237 50   237   18276 INIT { eval 'END { test2_set_is_end() }; 1' or die $@ }
  170     170   4382  
72             }
73              
74             BEGIN {
75 246     246   1800 no warnings 'once';
  246         609  
  246         26916  
76 246 50 33 246   1960 if($] ge '5.014' || $ENV{T2_CHECK_DEPTH} || $Test2::API::DO_DEPTH_CHECK) {
      0        
77 246         5231 *DO_DEPTH_CHECK = sub() { 1 };
78             }
79             else {
80 0         0 *DO_DEPTH_CHECK = sub() { 0 };
81             }
82             }
83              
84 246     246   1702 use Test2::EventFacet::Trace();
  246         573  
  246         4979  
85 246     246   116552 use Test2::Util::Trace(); # Legacy
  246         619  
  246         5415  
86              
87 246     246   98906 use Test2::Hub::Subtest();
  246         634  
  246         4951  
88 246     246   100018 use Test2::Hub::Interceptor();
  246         637  
  246         4992  
89 246     246   1621 use Test2::Hub::Interceptor::Terminator();
  246         583  
  246         3432  
90              
91 246     246   100218 use Test2::Event::Ok();
  246         689  
  246         6092  
92 246     246   102937 use Test2::Event::Diag();
  246         635  
  246         5238  
93 246     246   98941 use Test2::Event::Note();
  246         678  
  246         4918  
94 246     246   99071 use Test2::Event::Plan();
  246         662  
  246         5200  
95 246     246   97534 use Test2::Event::Bail();
  246         666  
  246         5529  
96 246     246   98495 use Test2::Event::Exception();
  246         658  
  246         4994  
97 246     246   98585 use Test2::Event::Waiting();
  246         655  
  246         4895  
98 246     246   97558 use Test2::Event::Skip();
  246         723  
  246         4833  
99 246     246   99974 use Test2::Event::Subtest();
  246         670  
  246         6441  
100              
101 246     246   1655 use Carp qw/carp croak confess/;
  246         498  
  246         14401  
102 246     246   1513 use Scalar::Util qw/blessed weaken/;
  246         508  
  246         11721  
103 246     246   1406 use Test2::Util qw/get_tid clone_io pkg_to_file gen_uid/;
  246         488  
  246         31970  
104              
105             our @EXPORT_OK = qw{
106             context release
107             context_do
108             no_context
109             intercept intercept_deep
110             run_subtest
111              
112             test2_init_done
113             test2_load_done
114             test2_load
115             test2_start_preload
116             test2_stop_preload
117             test2_in_preload
118             test2_is_testing_done
119              
120             test2_set_is_end
121             test2_unset_is_end
122             test2_get_is_end
123              
124             test2_pid
125             test2_tid
126             test2_stack
127             test2_no_wait
128             test2_ipc_wait_enable
129             test2_ipc_wait_disable
130             test2_ipc_wait_enabled
131              
132             test2_add_uuid_via
133              
134             test2_add_callback_testing_done
135              
136             test2_add_callback_context_aquire
137             test2_add_callback_context_acquire
138             test2_add_callback_context_init
139             test2_add_callback_context_release
140             test2_add_callback_exit
141             test2_add_callback_post_load
142             test2_add_callback_pre_subtest
143             test2_list_context_aquire_callbacks
144             test2_list_context_acquire_callbacks
145             test2_list_context_init_callbacks
146             test2_list_context_release_callbacks
147             test2_list_exit_callbacks
148             test2_list_post_load_callbacks
149             test2_list_pre_subtest_callbacks
150              
151             test2_ipc
152             test2_has_ipc
153             test2_ipc_disable
154             test2_ipc_disabled
155             test2_ipc_drivers
156             test2_ipc_add_driver
157             test2_ipc_polling
158             test2_ipc_disable_polling
159             test2_ipc_enable_polling
160             test2_ipc_get_pending
161             test2_ipc_set_pending
162             test2_ipc_get_timeout
163             test2_ipc_set_timeout
164              
165             test2_formatter
166             test2_formatters
167             test2_formatter_add
168             test2_formatter_set
169              
170             test2_stdout
171             test2_stderr
172             test2_reset_io
173             };
174 246     246   1831 BEGIN { require Exporter; our @ISA = qw(Exporter) }
  246         1026907  
175              
176             my $STACK = $INST->stack;
177             my $CONTEXTS = $INST->contexts;
178             my $INIT_CBS = $INST->context_init_callbacks;
179             my $ACQUIRE_CBS = $INST->context_acquire_callbacks;
180              
181             my $STDOUT = clone_io(\*STDOUT);
182             my $STDERR = clone_io(\*STDERR);
183 353   33 353 1 2402 sub test2_stdout { $STDOUT ||= clone_io(\*STDOUT) }
184 353   33 353 1 2071 sub test2_stderr { $STDERR ||= clone_io(\*STDERR) }
185              
186             sub test2_post_preload_reset {
187 0     0 0 0 test2_reset_io();
188 0         0 $INST->post_preload_reset;
189             }
190              
191             sub test2_reset_io {
192 0     0 1 0 $STDOUT = clone_io(\*STDOUT);
193 0         0 $STDERR = clone_io(\*STDERR);
194             }
195              
196 189     189 1 1138 sub test2_init_done { $INST->finalized }
197 163     163 1 762 sub test2_load_done { $INST->loaded }
198              
199 403     403 0 1892 sub test2_load { $INST->load }
200 1     1 0 12 sub test2_start_preload { $ENV{T2_IN_PRELOAD} = 1; $INST->start_preload }
  1         4  
201 1     1 0 13 sub test2_stop_preload { $ENV{T2_IN_PRELOAD} = 0; $INST->stop_preload }
  1         6  
202 1270     1270 0 5035 sub test2_in_preload { $INST->preload }
203              
204 1     1 0 5 sub test2_pid { $INST->pid }
205 1     1 0 5 sub test2_tid { $INST->tid }
206 359     359 1 1777 sub test2_stack { $INST->stack }
207 2     2 1 26 sub test2_ipc_wait_enable { $INST->set_no_wait(0) }
208 1     1 1 4 sub test2_ipc_wait_disable { $INST->set_no_wait(1) }
209 3     3 1 8 sub test2_ipc_wait_enabled { !$INST->no_wait }
210              
211             sub test2_is_testing_done {
212             # No instance? VERY DONE!
213 2 50   2 1 11 return 1 unless $INST;
214              
215             # No stack? tests must be done, it is created pretty early
216 2 50       7 my $stack = $INST->stack or return 1;
217              
218             # Nothing on the stack, no root hub yet, likely have not started testing
219 2 50       5 return 0 unless @$stack;
220              
221             # Stack has a slot for the root hub (see above) but it is undefined, likely
222             # garbage collected, test is done
223 2 50       7 my $root_hub = $stack->[0] or return 1;
224              
225             # If the root hub is ended than testing is done.
226 2 100       7 return 1 if $root_hub->ended;
227              
228             # Looks like we are still testing!
229 1         5 return 0;
230             }
231              
232             sub test2_no_wait {
233 5 100   5 1 19 $INST->set_no_wait(@_) if @_;
234 5         13 $INST->no_wait;
235             }
236              
237             sub test2_add_callback_testing_done {
238 0     0 1 0 my $cb = shift;
239              
240             test2_add_callback_post_load(sub {
241 0     0   0 my $stack = test2_stack();
242 0         0 $stack->top; # Insure we have a hub
243 0         0 my ($hub) = Test2::API::test2_stack->all;
244              
245 0         0 $hub->set_active(1);
246              
247 0         0 $hub->follow_up($cb);
248 0         0 });
249              
250 0         0 return;
251             }
252              
253 3     3 1 26 sub test2_add_callback_context_acquire { $INST->add_context_acquire_callback(@_) }
254 162     162 0 891 sub test2_add_callback_context_aquire { $INST->add_context_acquire_callback(@_) }
255 3     3 1 20 sub test2_add_callback_context_init { $INST->add_context_init_callback(@_) }
256 3     3 1 19 sub test2_add_callback_context_release { $INST->add_context_release_callback(@_) }
257 165     165 1 883 sub test2_add_callback_exit { $INST->add_exit_callback(@_) }
258 165     165 1 950 sub test2_add_callback_post_load { $INST->add_post_load_callback(@_) }
259 2     2 1 33 sub test2_add_callback_pre_subtest { $INST->add_pre_subtest_callback(@_) }
260 0     0 0 0 sub test2_list_context_aquire_callbacks { @{$INST->context_acquire_callbacks} }
  0         0  
261 2     2 1 7 sub test2_list_context_acquire_callbacks { @{$INST->context_acquire_callbacks} }
  2         7  
262 2     2 1 9 sub test2_list_context_init_callbacks { @{$INST->context_init_callbacks} }
  2         54  
263 2     2 1 12 sub test2_list_context_release_callbacks { @{$INST->context_release_callbacks} }
  2         7  
264 2     2 1 10 sub test2_list_exit_callbacks { @{$INST->exit_callbacks} }
  2         9  
265 2     2 1 11 sub test2_list_post_load_callbacks { @{$INST->post_load_callbacks} }
  2         6  
266 261     261 1 415 sub test2_list_pre_subtest_callbacks { @{$INST->pre_subtest_callbacks} }
  261         957  
267              
268             sub test2_add_uuid_via {
269 1 50   1 1 18 $INST->set_add_uuid_via(@_) if @_;
270 1         4 $INST->add_uuid_via();
271             }
272              
273 430     430 1 2304 sub test2_ipc { $INST->ipc }
274 188     188 1 1006 sub test2_has_ipc { $INST->has_ipc }
275 2     2 1 187 sub test2_ipc_disable { $INST->ipc_disable }
276 3     3 0 27 sub test2_ipc_disabled { $INST->ipc_disabled }
277 5     5 1 44 sub test2_ipc_add_driver { $INST->add_ipc_driver(@_) }
278 6     6 1 32 sub test2_ipc_drivers { @{$INST->ipc_drivers} }
  6         29  
279 3     3 1 8 sub test2_ipc_polling { $INST->ipc_polling }
280 1     1 1 5 sub test2_ipc_enable_polling { $INST->enable_ipc_polling }
281 1     1 1 6 sub test2_ipc_disable_polling { $INST->disable_ipc_polling }
282 0     0 1 0 sub test2_ipc_get_pending { $INST->get_ipc_pending }
283 35     35 1 346 sub test2_ipc_set_pending { $INST->set_ipc_pending(@_) }
284 2     2 1 10 sub test2_ipc_set_timeout { $INST->set_ipc_timeout(@_) }
285 4     4 1 20 sub test2_ipc_get_timeout { $INST->ipc_timeout() }
286 0     0 1 0 sub test2_ipc_enable_shm { 0 }
287              
288             sub test2_formatter {
289 267 100 66 267 1 1910 if ($ENV{T2_FORMATTER} && $ENV{T2_FORMATTER} =~ m/^(\+)?(.*)$/) {
290 18 50       117 my $formatter = $1 ? $2 : "Test2::Formatter::$2";
291 18         121 my $file = pkg_to_file($formatter);
292 18         89 require $file;
293 18         306 return $formatter;
294             }
295              
296 249         1447 return $INST->formatter;
297             }
298              
299 0     0 1 0 sub test2_formatters { @{$INST->formatters} }
  0         0  
300 162     162 1 1113 sub test2_formatter_add { $INST->add_formatter(@_) }
301             sub test2_formatter_set {
302 2     2 1 18 my ($formatter) = @_;
303 2 100       95 croak "No formatter specified" unless $formatter;
304 1 50       4 croak "Global Formatter already set" if $INST->formatter_set;
305 0         0 $INST->set_formatter($formatter);
306             }
307              
308             # Private, for use in Test2::API::Context
309 246     246   1073 sub _contexts_ref { $INST->contexts }
310 1     1   9 sub _context_acquire_callbacks_ref { $INST->context_acquire_callbacks }
311 1     1   10 sub _context_init_callbacks_ref { $INST->context_init_callbacks }
312 247     247   1522 sub _context_release_callbacks_ref { $INST->context_release_callbacks }
313 491     491   2025 sub _add_uuid_via_ref { \($INST->{Test2::API::Instance::ADD_UUID_VIA()}) }
314              
315             # Private, for use in Test2::IPC
316 0     0   0 sub _set_ipc { $INST->set_ipc(@_) }
317              
318             sub context_do(&;@) {
319 5     5 1 55 my $code = shift;
320 5         13 my @args = @_;
321              
322 5         15 my $ctx = context(level => 1);
323              
324 5         12 my $want = wantarray;
325              
326 5         6 my @out;
327 5         10 my $ok = eval {
328 5 100       34 $want ? @out = $code->($ctx, @args) :
    100          
329             defined($want) ? $out[0] = $code->($ctx, @args) :
330             $code->($ctx, @args) ;
331 3         23 1;
332             };
333 5         23 my $err = $@;
334              
335 5         20 $ctx->release;
336              
337 5 100       21 die $err unless $ok;
338              
339 3 100       10 return @out if $want;
340 2 100       9 return $out[0] if defined $want;
341 1         4 return;
342             }
343              
344             sub no_context(&;$) {
345 3     3 1 7 my ($code, $hid) = @_;
346 3   66     13 $hid ||= $STACK->top->hid;
347              
348 3         7 my $ctx = $CONTEXTS->{$hid};
349 3         6 delete $CONTEXTS->{$hid};
350 3         5 my $ok = eval { $code->(); 1 };
  3         9  
  3         10  
351 3         7 my $err = $@;
352              
353 3         8 $CONTEXTS->{$hid} = $ctx;
354 3         10 weaken($CONTEXTS->{$hid});
355              
356 3 50       7 die $err unless $ok;
357              
358 3         6 return;
359             };
360              
361             my $UUID_VIA = _add_uuid_via_ref();
362             sub context {
363             # We need to grab these before anything else to ensure they are not
364             # changed.
365 13358     13358 1 81744 my ($errno, $eval_error, $child_error, $extended_error) = (0 + $!, $@, $?, $^E);
366              
367 13358         67714 my %params = (level => 0, wrapped => 0, @_);
368              
369             # If something is getting a context then the sync system needs to be
370             # considered loaded...
371 13358 100       38735 $INST->load unless $INST->{loaded};
372              
373 13358 100       29183 croak "context() called, but return value is ignored"
374             unless defined wantarray;
375              
376 13357   66     35274 my $stack = $params{stack} || $STACK;
377 13357   66     56445 my $hub = $params{hub} || (@$stack ? $stack->[-1] : $stack->top);
378              
379             # Catch an edge case where we try to get context after the root hub has
380             # been garbage collected resulting in a stack that has a single undef
381             # hub
382 13357 50 33     41457 if (!$hub && !exists($params{hub}) && @$stack) {
      33        
383 0         0 my $msg = Carp::longmess("Attempt to get Test2 context after testing has completed (did you attempt a testing event after done_testing?)");
384              
385             # The error message is usually masked by the global destruction, so we have to print to STDER
386 0         0 print STDERR $msg;
387              
388             # Make sure this is a failure, we are probably already in END, so set $? to change the exit code
389 0         0 $? = 1;
390              
391             # Now we actually die to interrupt the program flow and avoid undefined his warnings
392 0         0 die $msg;
393             }
394              
395 13357         23374 my $hid = $hub->{hid};
396 13357         22057 my $current = $CONTEXTS->{$hid};
397              
398 13357         47984 $_->(\%params) for @$ACQUIRE_CBS;
399 13357 100       27947 map $_->(\%params), @{$hub->{_context_acquire}} if $hub->{_context_acquire};
  88         174  
400              
401             # This is for https://github.com/Test-More/test-more/issues/16
402             # and https://rt.perl.org/Public/Bug/Display.html?id=127774
403 13357   50     41828 my $phase = ${^GLOBAL_PHASE} || 'NA';
404 13357   66     59244 my $end_phase = $ENDING || $phase eq 'END' || $phase eq 'DESTRUCT';
405              
406 13357         22410 my $level = 1 + $params{level};
407 13357 100       106486 my ($pkg, $file, $line, $sub, @other) = $end_phase ? caller(0) : caller($level);
408 13357 100 66     38404 unless ($pkg || $end_phase) {
409 515 100       1376 confess "Could not find context at depth $level" unless $params{fudge};
410 514   66     6200 ($pkg, $file, $line, $sub, @other) = caller(--$level) while ($level >= 0 && !$pkg);
411             }
412              
413 13356         19370 my $depth = $level;
414 13356   100     135872 $depth++ while DO_DEPTH_CHECK && !$end_phase && (!$current || $depth <= $current->{_depth} + $params{wrapped}) && caller($depth + 1);
      100        
      100        
415 13356         22219 $depth -= $params{wrapped};
416 13356   100     50604 my $depth_ok = !DO_DEPTH_CHECK || $end_phase || !$current || $current->{_depth} < $depth;
417              
418 13356 100 100     35340 if ($current && $params{on_release} && $depth_ok) {
      66        
419 1   50     3 $current->{_on_release} ||= [];
420 1         2 push @{$current->{_on_release}} => $params{on_release};
  1         4  
421             }
422              
423             # I know this is ugly....
424 13356 100 50     110807 ($!, $@, $?, $^E) = ($errno, $eval_error, $child_error, $extended_error) and return bless(
      100        
425             {
426             %$current,
427             _is_canon => undef,
428             errno => $errno,
429             eval_error => $eval_error,
430             child_error => $child_error,
431             _is_spawn => [$pkg, $file, $line, $sub],
432             },
433             'Test2::API::Context'
434             ) if $current && $depth_ok;
435              
436             # Handle error condition of bad level
437 8333 100       15084 if ($current) {
438 3 100       5 unless (${$current->{_aborted}}) {
  3         11  
439             _canon_error($current, [$pkg, $file, $line, $sub, $depth])
440 2 50       9 unless $current->{_is_canon};
441              
442 2 50       13 _depth_error($current, [$pkg, $file, $line, $sub, $depth])
443             unless $depth_ok;
444             }
445              
446 3 50       41 $current->release if $current->{_is_canon};
447              
448 3         11 delete $CONTEXTS->{$hid};
449             }
450              
451             # Directly bless the object here, calling new is a noticeable performance
452             # hit with how often this needs to be called.
453             my $trace = bless(
454             {
455             frame => [$pkg, $file, $line, $sub],
456             pid => $$,
457             tid => get_tid(),
458             cid => gen_uid(),
459             hid => $hid,
460             nested => $hub->{nested},
461             buffered => $hub->{buffered},
462              
463             full_caller => [$pkg, $file, $line, $sub, @other],
464              
465             $$UUID_VIA ? (
466             huuid => $hub->{uuid},
467 8333 100       38694 uuid => ${$UUID_VIA}->('context'),
  43         107  
468             ) : (),
469             },
470             'Test2::EventFacet::Trace'
471             );
472              
473             # Directly bless the object here, calling new is a noticeable performance
474             # hit with how often this needs to be called.
475 8333         18144 my $aborted = 0;
476             $current = bless(
477             {
478             _aborted => \$aborted,
479             stack => $stack,
480             hub => $hub,
481             trace => $trace,
482             _is_canon => 1,
483             _depth => $depth,
484             errno => $errno,
485             eval_error => $eval_error,
486             child_error => $child_error,
487 8333 100       59112 $params{on_release} ? (_on_release => [$params{on_release}]) : (),
488             },
489             'Test2::API::Context'
490             );
491              
492 8333         26759 $CONTEXTS->{$hid} = $current;
493 8333         32445 weaken($CONTEXTS->{$hid});
494              
495 8333         18511 $_->($current) for @$INIT_CBS;
496 8333 100       18727 map $_->($current), @{$hub->{_context_init}} if $hub->{_context_init};
  49         96  
497              
498 8333 100       16360 $params{on_init}->($current) if $params{on_init};
499              
500 8333         36298 ($!, $@, $?, $^E) = ($errno, $eval_error, $child_error, $extended_error);
501              
502 8333         40704 return $current;
503             }
504              
505             sub _depth_error {
506 2     2   11 _existing_error(@_, <<" EOT");
507             context() was called to retrieve an existing context, however the existing
508             context was created in a stack frame at the same, or deeper level. This usually
509             means that a tool failed to release the context when it was finished.
510             EOT
511             }
512              
513             sub _canon_error {
514 0     0   0 _existing_error(@_, <<" EOT");
515             context() was called to retrieve an existing context, however the existing
516             context has an invalid internal state (!_canon_count). This should not normally
517             happen unless something is mucking about with internals...
518             EOT
519             }
520              
521             sub _existing_error {
522 2     2   7 my ($ctx, $details, $msg) = @_;
523 2         9 my ($pkg, $file, $line, $sub, $depth) = @$details;
524              
525 2         12 my $oldframe = $ctx->{trace}->frame;
526 2         16 my $olddepth = $ctx->{_depth};
527              
528             # Older versions of Carp do not export longmess() function, so it needs to be called with package name
529 2         249 my $mess = Carp::longmess();
530              
531 2         499 warn <<" EOT";
532             $msg
533             Old context details:
534             File: $oldframe->[1]
535             Line: $oldframe->[2]
536             Tool: $oldframe->[3]
537             Depth: $olddepth
538              
539             New context details:
540             File: $file
541             Line: $line
542             Tool: $sub
543             Depth: $depth
544              
545             Trace: $mess
546              
547             Removing the old context and creating a new one...
548             EOT
549             }
550              
551             sub release($;$) {
552 3200     3200 1 9824 $_[0]->release;
553 3200         10066 return $_[1];
554             }
555              
556             sub intercept(&) {
557 62     62 1 600 my $code = shift;
558 62         237 my $ctx = context();
559              
560 62         301 my $events = _intercept($code, deep => 0);
561              
562 60         307 $ctx->release;
563              
564 60         353 return $events;
565             }
566              
567             sub intercept_deep(&) {
568 2     2 0 22 my $code = shift;
569 2         5 my $ctx = context();
570              
571 2         6 my $events = _intercept($code, deep => 1);
572              
573 2         7 $ctx->release;
574              
575 2         5 return $events;
576             }
577              
578             sub _intercept {
579 64     64   137 my $code = shift;
580 64         239 my %params = @_;
581 64         156 my $ctx = context();
582              
583 64         173 my $ipc;
584 64 100       248 if (my $global_ipc = test2_ipc()) {
585 13         64 my $driver = blessed($global_ipc);
586 13         87 $ipc = $driver->new;
587             }
588              
589 64         646 my $hub = Test2::Hub::Interceptor->new(
590             ipc => $ipc,
591             no_ending => 1,
592             );
593              
594 64         146 my @events;
595 64     168   735 $hub->listen(sub { push @events => $_[1] }, inherit => $params{deep});
  168         503  
596              
597 64         274 $ctx->stack->top; # Make sure there is a top hub before we begin.
598 64         208 $ctx->stack->push($hub);
599              
600 64         243 my $trace = $ctx->trace;
601 64         174 my $state = {};
602 64         317 $hub->clean_inherited(trace => $trace, state => $state);
603              
604 64         174 my ($ok, $err) = (1, undef);
605             T2_SUBTEST_WRAPPER: {
606             # Do not use 'try' cause it localizes __DIE__
607 64         124 $ok = eval { $code->(hub => $hub, context => $ctx->snapshot); 1 };
  64         126  
  64         301  
  54         231  
608 55         172 $err = $@;
609              
610             # They might have done 'BEGIN { skip_all => "whatever" }'
611 55 50 66     509 if (!$ok && $err =~ m/Label not found for "last T2_SUBTEST_WRAPPER"/ || (blessed($err) && $err->isa('Test2::Hub::Interceptor::Terminator'))) {
      33        
      33        
612 0         0 $ok = 1;
613 0         0 $err = undef;
614             }
615             }
616              
617 63         388 $hub->cull;
618 63         364 $ctx->stack->pop($hub);
619              
620 63         348 $hub->restore_inherited(trace => $trace, state => $state);
621              
622 63         304 $ctx->release;
623              
624 63 100       252 die $err unless $ok;
625              
626 62 100 66     525 $hub->finalize($trace, 1)
      100        
627             if $ok
628             && !$hub->no_ending
629             && !$hub->ended;
630              
631 62         19559 require Test2::API::InterceptResult;
632 62         552 return Test2::API::InterceptResult->new_from_ref(\@events);
633             }
634              
635             sub run_subtest {
636 121     121 1 551 my ($name, $code, $params, @args) = @_;
637              
638             $_->($name,$code,@args)
639 121         340 for Test2::API::test2_list_pre_subtest_callbacks();
640              
641 121 100       528 $params = {buffered => $params} unless ref $params;
642 121         282 my $inherit_trace = delete $params->{inherit_trace};
643              
644 121         291 my $ctx = context();
645              
646 121         490 my $parent = $ctx->hub;
647              
648             # If a parent is buffered then the child must be as well.
649 121   100     391 my $buffered = $params->{buffered} || $parent->{buffered};
650              
651 121 100       352 $ctx->note($name) unless $buffered;
652              
653 121   33     358 my $stack = $ctx->stack || $STACK;
654 121         645 my $hub = $stack->new_hub(
655             class => 'Test2::Hub::Subtest',
656             %$params,
657             buffered => $buffered,
658             );
659              
660 121         219 my @events;
661 121     827   961 $hub->listen(sub { push @events => $_[1] });
  827         2263  
662              
663 121 100       317 if ($buffered) {
664 105 100       386 if (my $format = $hub->format) {
665 79 100       572 my $hide = $format->can('hide_buffered') ? $format->hide_buffered : 1;
666 79 100       276 $hub->format(undef) if $hide;
667             }
668             }
669              
670 121 100       293 if ($inherit_trace) {
671 5         8 my $orig = $code;
672             $code = sub {
673 5     5   14 my $base_trace = $ctx->trace;
674 5         15 my $trace = $base_trace->snapshot(nested => 1 + $base_trace->nested);
675 5         16 my $st_ctx = Test2::API::Context->new(
676             trace => $trace,
677             hub => $hub,
678             );
679 5         17 $st_ctx->do_in_context($orig, @args);
680 5         29 };
681             }
682              
683 121         246 my ($ok, $err, $finished);
684             T2_SUBTEST_WRAPPER: {
685             # Do not use 'try' cause it localizes __DIE__
686 121         186 $ok = eval { $code->(@args); 1 };
  121         222  
  121         421  
  117         534  
687 118         1708 $err = $@;
688              
689             # They might have done 'BEGIN { skip_all => "whatever" }'
690 118 50 66     1070 if (!$ok && $err =~ m/Label not found for "last T2_SUBTEST_WRAPPER"/ || (blessed($err) && blessed($err) eq 'Test::Builder::Exception')) {
      33        
      33        
691 0         0 $ok = undef;
692 0         0 $err = undef;
693             }
694             else {
695 118         285 $finished = 1;
696             }
697             }
698              
699 120 100 33     1021 if ($params->{no_fork}) {
    50          
700 2 100       103 if ($$ != $ctx->trace->pid) {
701 1 50       19 warn $ok ? "Forked inside subtest, but subtest never finished!\n" : $err;
702 1         85 exit 255;
703             }
704              
705 1 50       5 if (get_tid() != $ctx->trace->tid) {
706 0 0       0 warn $ok ? "Started new thread inside subtest, but thread never finished!\n" : $err;
707 0         0 exit 255;
708             }
709             }
710             elsif (!$parent->is_local && !$parent->ipc) {
711 0 0       0 warn $ok ? "A new process or thread was started inside subtest, but IPC is not enabled!\n" : $err;
712 0         0 exit 255;
713             }
714              
715 119         586 $stack->pop($hub);
716              
717 119         407 my $trace = $ctx->trace;
718              
719 119         516 my $bailed = $hub->bailed_out;
720              
721 119 100       300 if (!$finished) {
722 2 50 33     13 if ($bailed && !$buffered) {
    50 33        
723 0         0 $ctx->bail($bailed->reason);
724             }
725             elsif ($bailed && $buffered) {
726 2         5 $ok = 1;
727             }
728             else {
729 0         0 my $code = $hub->exit_code;
730 0         0 $ok = !$code;
731 0 0       0 $err = "Subtest ended with exit code $code" if $code;
732             }
733             }
734              
735 119 50 33     641 $hub->finalize($trace->snapshot(huuid => $hub->uuid, hid => $hub->hid, nested => $hub->nested, buffered => $buffered), 1)
      33        
736             if $ok
737             && !$hub->no_ending
738             && !$hub->ended;
739              
740 119   66     510 my $pass = $ok && $hub->is_passing;
741 119         419 my $e = $ctx->build_event(
742             'Subtest',
743             pass => $pass,
744             name => $name,
745             subtest_id => $hub->id,
746             subtest_uuid => $hub->uuid,
747             buffered => $buffered,
748             subevents => \@events,
749             );
750              
751 119         549 my $plan_ok = $hub->check_plan;
752              
753 119         406 $ctx->hub->send($e);
754              
755 119 100       659 $ctx->failure_diag($e) unless $e->pass;
756              
757 119 50       309 $ctx->diag("Caught exception in subtest: $err") unless $ok;
758              
759 119 100 100     516 $ctx->diag("Bad subtest plan, expected " . $hub->plan . " but ran " . $hub->count)
760             if defined($plan_ok) && !$plan_ok;
761              
762 119 100 66     388 $ctx->bail($bailed->reason) if $bailed && $buffered;
763              
764 117         436 $ctx->release;
765 117         1155 return $pass;
766             }
767              
768             # There is a use-cycle between API and API/Context. Context needs to use some
769             # API functions as the package is compiling. Test2::API::context() needs
770             # Test2::API::Context to be loaded, but we cannot 'require' the module there as
771             # it causes a very noticeable performance impact with how often context() is
772             # called.
773             require Test2::API::Context;
774              
775             1;
776              
777             __END__