15759b3d2Safresh1use strict; 25759b3d2Safresh1use warnings; 35759b3d2Safresh1 45759b3d2Safresh1BEGIN { $Test2::API::DO_DEPTH_CHECK = 1 } 55759b3d2Safresh1use Test2::Tools::Tiny; 65759b3d2Safresh1 75759b3d2Safresh1use Test2::API qw{ 85759b3d2Safresh1 context intercept 95759b3d2Safresh1 test2_stack 105759b3d2Safresh1 test2_add_callback_context_acquire 115759b3d2Safresh1 test2_add_callback_context_init 125759b3d2Safresh1 test2_add_callback_context_release 135759b3d2Safresh1}; 145759b3d2Safresh1 155759b3d2Safresh1my $error = exception { context(); 1 }; 165759b3d2Safresh1my $exception = "context() called, but return value is ignored at " . __FILE__ . ' line ' . (__LINE__ - 1); 175759b3d2Safresh1like($error, qr/^\Q$exception\E/, "Got the exception" ); 185759b3d2Safresh1 195759b3d2Safresh1my $ref; 205759b3d2Safresh1my $frame; 215759b3d2Safresh1sub wrap(&) { 225759b3d2Safresh1 my $ctx = context(); 235759b3d2Safresh1 my ($pkg, $file, $line, $sub) = caller(0); 245759b3d2Safresh1 $frame = [$pkg, $file, $line, $sub]; 255759b3d2Safresh1 265759b3d2Safresh1 $_[0]->($ctx); 275759b3d2Safresh1 285759b3d2Safresh1 $ref = "$ctx"; 295759b3d2Safresh1 305759b3d2Safresh1 $ctx->release; 315759b3d2Safresh1} 325759b3d2Safresh1 335759b3d2Safresh1wrap { 345759b3d2Safresh1 my $ctx = shift; 355759b3d2Safresh1 ok($ctx->hub, "got hub"); 365759b3d2Safresh1 delete $ctx->trace->frame->[4]; 375759b3d2Safresh1 is_deeply($ctx->trace->frame, $frame, "Found place to report errors"); 385759b3d2Safresh1}; 395759b3d2Safresh1 405759b3d2Safresh1wrap { 415759b3d2Safresh1 my $ctx = shift; 425759b3d2Safresh1 ok("$ctx" ne "$ref", "Got a new context"); 435759b3d2Safresh1 my $new = context(); 445759b3d2Safresh1 my @caller = caller(0); 455759b3d2Safresh1 is_deeply( 465759b3d2Safresh1 $new, 475759b3d2Safresh1 {%$ctx, _is_canon => undef, _is_spawn => [@caller[0,1,2,3]]}, 485759b3d2Safresh1 "Additional call to context gets spawn" 495759b3d2Safresh1 ); 505759b3d2Safresh1 delete $ctx->trace->frame->[4]; 515759b3d2Safresh1 is_deeply($ctx->trace->frame, $frame, "Found place to report errors"); 525759b3d2Safresh1 $new->release; 535759b3d2Safresh1}; 545759b3d2Safresh1 555759b3d2Safresh1wrap { 565759b3d2Safresh1 my $ctx = shift; 575759b3d2Safresh1 my $snap = $ctx->snapshot; 585759b3d2Safresh1 595759b3d2Safresh1 is_deeply( 605759b3d2Safresh1 $snap, 615759b3d2Safresh1 {%$ctx, _is_canon => undef, _is_spawn => undef, _aborted => undef}, 625759b3d2Safresh1 "snapshot is identical except for canon/spawn/aborted" 635759b3d2Safresh1 ); 645759b3d2Safresh1 ok($ctx != $snap, "snapshot is a new instance"); 655759b3d2Safresh1}; 665759b3d2Safresh1 675759b3d2Safresh1my $end_ctx; 685759b3d2Safresh1{ # Simulate an END block... 695759b3d2Safresh1 local *END = sub { local *__ANON__ = 'END'; context() }; 705759b3d2Safresh1 my $ctx = END(); 715759b3d2Safresh1 $frame = [ __PACKAGE__, __FILE__, __LINE__ - 1, 'main::END' ]; 725759b3d2Safresh1 # "__LINE__ - 1" on the preceding line forces the value to be an IV 735759b3d2Safresh1 # (even though __LINE__ on its own is a PV), just as (caller)[2] is. 745759b3d2Safresh1 $end_ctx = $ctx->snapshot; 755759b3d2Safresh1 $ctx->release; 765759b3d2Safresh1} 775759b3d2Safresh1delete $end_ctx->trace->frame->[4]; 785759b3d2Safresh1is_deeply( $end_ctx->trace->frame, $frame, 'context is ok in an end block'); 795759b3d2Safresh1 805759b3d2Safresh1# Test event generation 815759b3d2Safresh1{ 825759b3d2Safresh1 package My::Formatter; 835759b3d2Safresh1 845759b3d2Safresh1 sub write { 855759b3d2Safresh1 my $self = shift; 865759b3d2Safresh1 my ($e) = @_; 875759b3d2Safresh1 push @$self => $e; 885759b3d2Safresh1 } 895759b3d2Safresh1} 905759b3d2Safresh1my $events = bless [], 'My::Formatter'; 915759b3d2Safresh1my $hub = Test2::Hub->new( 925759b3d2Safresh1 formatter => $events, 935759b3d2Safresh1); 945759b3d2Safresh1my $trace = Test2::EventFacet::Trace->new( 955759b3d2Safresh1 frame => [ 'Foo::Bar', 'foo_bar.t', 42, 'Foo::Bar::baz' ], 965759b3d2Safresh1); 975759b3d2Safresh1my $ctx = Test2::API::Context->new( 985759b3d2Safresh1 trace => $trace, 995759b3d2Safresh1 hub => $hub, 1005759b3d2Safresh1); 1015759b3d2Safresh1 1025759b3d2Safresh1my $e = $ctx->build_event('Ok', pass => 1, name => 'foo'); 1035759b3d2Safresh1is($e->pass, 1, "Pass"); 1045759b3d2Safresh1is($e->name, 'foo', "got name"); 1055759b3d2Safresh1is_deeply($e->trace, $trace, "Got the trace info"); 1065759b3d2Safresh1ok(!@$events, "No events yet"); 1075759b3d2Safresh1 1085759b3d2Safresh1$e = $ctx->send_event('Ok', pass => 1, name => 'foo'); 1095759b3d2Safresh1is($e->pass, 1, "Pass"); 1105759b3d2Safresh1is($e->name, 'foo', "got name"); 1115759b3d2Safresh1is_deeply($e->trace, $trace, "Got the trace info"); 1125759b3d2Safresh1is(@$events, 1, "1 event"); 1135759b3d2Safresh1is_deeply($events, [$e], "Hub saw the event"); 1145759b3d2Safresh1pop @$events; 1155759b3d2Safresh1 1165759b3d2Safresh1$e = $ctx->ok(1, 'foo'); 1175759b3d2Safresh1is($e->pass, 1, "Pass"); 1185759b3d2Safresh1is($e->name, 'foo', "got name"); 1195759b3d2Safresh1is_deeply($e->trace, $trace, "Got the trace info"); 1205759b3d2Safresh1is(@$events, 1, "1 event"); 1215759b3d2Safresh1is_deeply($events, [$e], "Hub saw the event"); 1225759b3d2Safresh1pop @$events; 1235759b3d2Safresh1 1245759b3d2Safresh1$e = $ctx->note('foo'); 1255759b3d2Safresh1is($e->message, 'foo', "got message"); 1265759b3d2Safresh1is_deeply($e->trace, $trace, "Got the trace info"); 1275759b3d2Safresh1is(@$events, 1, "1 event"); 1285759b3d2Safresh1is_deeply($events, [$e], "Hub saw the event"); 1295759b3d2Safresh1pop @$events; 1305759b3d2Safresh1 1315759b3d2Safresh1$e = $ctx->diag('foo'); 1325759b3d2Safresh1is($e->message, 'foo', "got message"); 1335759b3d2Safresh1is_deeply($e->trace, $trace, "Got the trace info"); 1345759b3d2Safresh1is(@$events, 1, "1 event"); 1355759b3d2Safresh1is_deeply($events, [$e], "Hub saw the event"); 1365759b3d2Safresh1pop @$events; 1375759b3d2Safresh1 1385759b3d2Safresh1$e = $ctx->plan(100); 1395759b3d2Safresh1is($e->max, 100, "got max"); 1405759b3d2Safresh1is_deeply($e->trace, $trace, "Got the trace info"); 1415759b3d2Safresh1is(@$events, 1, "1 event"); 1425759b3d2Safresh1is_deeply($events, [$e], "Hub saw the event"); 1435759b3d2Safresh1pop @$events; 1445759b3d2Safresh1 1455759b3d2Safresh1$e = $ctx->skip('foo', 'because'); 1465759b3d2Safresh1is($e->name, 'foo', "got name"); 1475759b3d2Safresh1is($e->reason, 'because', "got reason"); 1485759b3d2Safresh1ok($e->pass, "skip events pass by default"); 1495759b3d2Safresh1is_deeply($e->trace, $trace, "Got the trace info"); 1505759b3d2Safresh1is(@$events, 1, "1 event"); 1515759b3d2Safresh1is_deeply($events, [$e], "Hub saw the event"); 1525759b3d2Safresh1pop @$events; 1535759b3d2Safresh1 1545759b3d2Safresh1$e = $ctx->skip('foo', 'because', pass => 0); 1555759b3d2Safresh1ok(!$e->pass, "can override skip params"); 1565759b3d2Safresh1pop @$events; 1575759b3d2Safresh1 1585759b3d2Safresh1# Test hooks 1595759b3d2Safresh1 1605759b3d2Safresh1my @hooks; 1615759b3d2Safresh1$hub = test2_stack()->top; 1625759b3d2Safresh1my $ref1 = $hub->add_context_init(sub { die "Bad Arg" unless ref($_[0]) eq 'Test2::API::Context'; push @hooks => 'hub_init' }); 1635759b3d2Safresh1my $ref2 = $hub->add_context_release(sub { die "Bad Arg" unless ref($_[0]) eq 'Test2::API::Context'; push @hooks => 'hub_release' }); 1645759b3d2Safresh1test2_add_callback_context_init(sub { die "Bad Arg" unless ref($_[0]) eq 'Test2::API::Context'; push @hooks => 'global_init' }); 1655759b3d2Safresh1test2_add_callback_context_release(sub { die "Bad Arg" unless ref($_[0]) eq 'Test2::API::Context'; push @hooks => 'global_release' }); 1665759b3d2Safresh1 1675759b3d2Safresh1my $ref3 = $hub->add_context_acquire(sub { die "Bad Arg" unless ref($_[0]) eq 'HASH'; push @hooks => 'hub_acquire' }); 1685759b3d2Safresh1test2_add_callback_context_acquire(sub { die "Bad Arg" unless ref($_[0]) eq 'HASH'; push @hooks => 'global_acquire' }); 1695759b3d2Safresh1 1705759b3d2Safresh1sub { 1715759b3d2Safresh1 push @hooks => 'start'; 1725759b3d2Safresh1 my $ctx = context(on_init => sub { push @hooks => 'ctx_init' }, on_release => sub { push @hooks => 'ctx_release' }); 1735759b3d2Safresh1 push @hooks => 'deep'; 1745759b3d2Safresh1 my $ctx2 = sub { 1755759b3d2Safresh1 context(on_init => sub { push @hooks => 'ctx_init_deep' }, on_release => sub { push @hooks => 'ctx_release_deep' }); 1765759b3d2Safresh1 }->(); 1775759b3d2Safresh1 push @hooks => 'release_deep'; 1785759b3d2Safresh1 $ctx2->release; 1795759b3d2Safresh1 push @hooks => 'release_parent'; 1805759b3d2Safresh1 $ctx->release; 1815759b3d2Safresh1 push @hooks => 'released_all'; 1825759b3d2Safresh1 1835759b3d2Safresh1 push @hooks => 'new'; 1845759b3d2Safresh1 $ctx = context(on_init => sub { push @hooks => 'ctx_init2' }, on_release => sub { push @hooks => 'ctx_release2' }); 1855759b3d2Safresh1 push @hooks => 'release_new'; 1865759b3d2Safresh1 $ctx->release; 1875759b3d2Safresh1 push @hooks => 'done'; 1885759b3d2Safresh1}->(); 1895759b3d2Safresh1 1905759b3d2Safresh1$hub->remove_context_init($ref1); 1915759b3d2Safresh1$hub->remove_context_release($ref2); 1925759b3d2Safresh1$hub->remove_context_acquire($ref3); 1935759b3d2Safresh1@{Test2::API::_context_init_callbacks_ref()} = (); 1945759b3d2Safresh1@{Test2::API::_context_release_callbacks_ref()} = (); 1955759b3d2Safresh1@{Test2::API::_context_acquire_callbacks_ref()} = (); 1965759b3d2Safresh1 1975759b3d2Safresh1is_deeply( 1985759b3d2Safresh1 \@hooks, 1995759b3d2Safresh1 [qw{ 2005759b3d2Safresh1 start 2015759b3d2Safresh1 global_acquire 2025759b3d2Safresh1 hub_acquire 2035759b3d2Safresh1 global_init 2045759b3d2Safresh1 hub_init 2055759b3d2Safresh1 ctx_init 2065759b3d2Safresh1 deep 2075759b3d2Safresh1 global_acquire 2085759b3d2Safresh1 hub_acquire 2095759b3d2Safresh1 release_deep 2105759b3d2Safresh1 release_parent 2115759b3d2Safresh1 ctx_release_deep 2125759b3d2Safresh1 ctx_release 2135759b3d2Safresh1 hub_release 2145759b3d2Safresh1 global_release 2155759b3d2Safresh1 released_all 2165759b3d2Safresh1 new 2175759b3d2Safresh1 global_acquire 2185759b3d2Safresh1 hub_acquire 2195759b3d2Safresh1 global_init 2205759b3d2Safresh1 hub_init 2215759b3d2Safresh1 ctx_init2 2225759b3d2Safresh1 release_new 2235759b3d2Safresh1 ctx_release2 2245759b3d2Safresh1 hub_release 2255759b3d2Safresh1 global_release 2265759b3d2Safresh1 done 2275759b3d2Safresh1 }], 2285759b3d2Safresh1 "Got all hook in correct order" 2295759b3d2Safresh1); 2305759b3d2Safresh1 2315759b3d2Safresh1{ 2325759b3d2Safresh1 my $ctx = context(level => -1); 2335759b3d2Safresh1 2345759b3d2Safresh1 my $one = Test2::API::Context->new( 2355759b3d2Safresh1 trace => Test2::EventFacet::Trace->new(frame => [__PACKAGE__, __FILE__, __LINE__, 'blah']), 2365759b3d2Safresh1 hub => test2_stack()->top, 2375759b3d2Safresh1 ); 2385759b3d2Safresh1 is($one->_depth, 0, "default depth"); 2395759b3d2Safresh1 2405759b3d2Safresh1 my $ran = 0; 2415759b3d2Safresh1 my $doit = sub { 2425759b3d2Safresh1 is_deeply(\@_, [qw/foo bar/], "got args"); 2435759b3d2Safresh1 $ran++; 2445759b3d2Safresh1 die "Make sure old context is restored"; 2455759b3d2Safresh1 }; 2465759b3d2Safresh1 2475759b3d2Safresh1 eval { $one->do_in_context($doit, 'foo', 'bar') }; 2485759b3d2Safresh1 2495759b3d2Safresh1 my $spawn = context(level => -1, wrapped => -2); 2505759b3d2Safresh1 is($spawn->trace, $ctx->trace, "Old context restored"); 2515759b3d2Safresh1 $spawn->release; 2525759b3d2Safresh1 $ctx->release; 2535759b3d2Safresh1 2545759b3d2Safresh1 ok(!exception { $one->do_in_context(sub {1}) }, "do_in_context works without an original") 2555759b3d2Safresh1} 2565759b3d2Safresh1 2575759b3d2Safresh1{ 2585759b3d2Safresh1 like(exception { Test2::API::Context->new() }, qr/The 'trace' attribute is required/, "need to have trace"); 2595759b3d2Safresh1 2605759b3d2Safresh1 my $trace = Test2::EventFacet::Trace->new(frame => [__PACKAGE__, __FILE__, __LINE__, 'foo']); 2615759b3d2Safresh1 like(exception { Test2::API::Context->new(trace => $trace) }, qr/The 'hub' attribute is required/, "need to have hub"); 2625759b3d2Safresh1 2635759b3d2Safresh1 my $hub = test2_stack()->top; 2645759b3d2Safresh1 my $ctx = Test2::API::Context->new(trace => $trace, hub => $hub); 2655759b3d2Safresh1 is($ctx->{_depth}, 0, "depth set to 0 when not defined."); 2665759b3d2Safresh1 2675759b3d2Safresh1 $ctx = Test2::API::Context->new(trace => $trace, hub => $hub, _depth => 1); 2685759b3d2Safresh1 is($ctx->{_depth}, 1, "Do not reset depth"); 2695759b3d2Safresh1 2705759b3d2Safresh1 like( 2715759b3d2Safresh1 exception { $ctx->release }, 2725759b3d2Safresh1 qr/release\(\) should not be called on context that is neither canon nor a child/, 2735759b3d2Safresh1 "Non canonical context, do not release" 2745759b3d2Safresh1 ); 2755759b3d2Safresh1} 2765759b3d2Safresh1 2775759b3d2Safresh1sub { 2785759b3d2Safresh1 like( 2795759b3d2Safresh1 exception { my $ctx = context(level => 20) }, 2805759b3d2Safresh1 qr/Could not find context at depth 21/, 2815759b3d2Safresh1 "Level sanity" 2825759b3d2Safresh1 ); 2835759b3d2Safresh1 2845759b3d2Safresh1 ok( 2855759b3d2Safresh1 !exception { 2865759b3d2Safresh1 my $ctx = context(level => 20, fudge => 1); 2875759b3d2Safresh1 $ctx->release; 2885759b3d2Safresh1 }, 2895759b3d2Safresh1 "Was able to get context when fudging level" 2905759b3d2Safresh1 ); 2915759b3d2Safresh1}->(); 2925759b3d2Safresh1 2935759b3d2Safresh1sub { 2945759b3d2Safresh1 my ($ctx1, $ctx2); 2955759b3d2Safresh1 sub { $ctx1 = context() }->(); 2965759b3d2Safresh1 2975759b3d2Safresh1 my @warnings; 2985759b3d2Safresh1 { 2995759b3d2Safresh1 local $SIG{__WARN__} = sub { push @warnings => @_ }; 3005759b3d2Safresh1 $ctx2 = context(); 3015759b3d2Safresh1 $ctx1 = undef; 3025759b3d2Safresh1 } 3035759b3d2Safresh1 3045759b3d2Safresh1 $ctx2->release; 3055759b3d2Safresh1 3065759b3d2Safresh1 is(@warnings, 1, "1 warning"); 3075759b3d2Safresh1 like( 3085759b3d2Safresh1 $warnings[0], 3095759b3d2Safresh1 qr/^context\(\) was called to retrieve an existing context, however the existing/, 3105759b3d2Safresh1 "Got expected warning" 3115759b3d2Safresh1 ); 3125759b3d2Safresh1}->(); 3135759b3d2Safresh1 3145759b3d2Safresh1sub { 3155759b3d2Safresh1 my $ctx = context(); 3165759b3d2Safresh1 my $e = exception { $ctx->throw('xxx') }; 3175759b3d2Safresh1 like($e, qr/xxx/, "got exception"); 3185759b3d2Safresh1 3195759b3d2Safresh1 $ctx = context(); 3205759b3d2Safresh1 my $warnings = warnings { $ctx->alert('xxx') }; 3215759b3d2Safresh1 like($warnings->[0], qr/xxx/, "got warning"); 3225759b3d2Safresh1 $ctx->release; 3235759b3d2Safresh1}->(); 3245759b3d2Safresh1 3255759b3d2Safresh1sub { 3265759b3d2Safresh1 my $ctx = context; 3275759b3d2Safresh1 3285759b3d2Safresh1 is($ctx->_parse_event('Ok'), 'Test2::Event::Ok', "Got the Ok event class"); 3295759b3d2Safresh1 is($ctx->_parse_event('+Test2::Event::Ok'), 'Test2::Event::Ok', "Got the +Ok event class"); 3305759b3d2Safresh1 3315759b3d2Safresh1 like( 3325759b3d2Safresh1 exception { $ctx->_parse_event('+DFASGFSDFGSDGSD') }, 3335759b3d2Safresh1 qr/Could not load event module 'DFASGFSDFGSDGSD': Can't locate DFASGFSDFGSDGSD\.pm/, 3345759b3d2Safresh1 "Bad event type" 3355759b3d2Safresh1 ); 3365759b3d2Safresh1}->(); 3375759b3d2Safresh1 3385759b3d2Safresh1{ 3395759b3d2Safresh1 my ($e1, $e2); 3405759b3d2Safresh1 my $events = intercept { 3415759b3d2Safresh1 my $ctx = context(); 3425759b3d2Safresh1 $e1 = $ctx->ok(0, 'foo', ['xxx']); 3435759b3d2Safresh1 $e2 = $ctx->ok(0, 'foo'); 3445759b3d2Safresh1 $ctx->release; 3455759b3d2Safresh1 }; 3465759b3d2Safresh1 3475759b3d2Safresh1 ok($e1->isa('Test2::Event::Ok'), "returned ok event"); 3485759b3d2Safresh1 ok($e2->isa('Test2::Event::Ok'), "returned ok event"); 3495759b3d2Safresh1 3505759b3d2Safresh1 is($events->[0], $e1, "got ok event 1"); 3515759b3d2Safresh1 is($events->[3], $e2, "got ok event 2"); 3525759b3d2Safresh1 3535759b3d2Safresh1 is($events->[2]->message, 'xxx', "event 1 diag 2"); 3545759b3d2Safresh1 ok($events->[2]->isa('Test2::Event::Diag'), "event 1 diag 2 is diag"); 3555759b3d2Safresh1 3565759b3d2Safresh1 is($events->[3], $e2, "got ok event 2"); 3575759b3d2Safresh1} 3585759b3d2Safresh1 3595759b3d2Safresh1sub { 3605759b3d2Safresh1 local $! = 100; 3615759b3d2Safresh1 local $@ = 'foobarbaz'; 3625759b3d2Safresh1 local $? = 123; 3635759b3d2Safresh1 3645759b3d2Safresh1 my $ctx = context(); 3655759b3d2Safresh1 3665759b3d2Safresh1 is($ctx->errno, 100, "saved errno"); 3675759b3d2Safresh1 is($ctx->eval_error, 'foobarbaz', "saved eval error"); 3685759b3d2Safresh1 is($ctx->child_error, 123, "saved child exit"); 3695759b3d2Safresh1 3705759b3d2Safresh1 $! = 22; 3715759b3d2Safresh1 $@ = 'xyz'; 3725759b3d2Safresh1 $? = 33; 3735759b3d2Safresh1 3745759b3d2Safresh1 is(0 + $!, 22, "altered \$! in tool"); 3755759b3d2Safresh1 is($@, 'xyz', "altered \$@ in tool"); 3765759b3d2Safresh1 is($?, 33, "altered \$? in tool"); 3775759b3d2Safresh1 3785759b3d2Safresh1 sub { 3795759b3d2Safresh1 my $ctx2 = context(); 3805759b3d2Safresh1 3815759b3d2Safresh1 $! = 42; 3825759b3d2Safresh1 $@ = 'app'; 3835759b3d2Safresh1 $? = 43; 3845759b3d2Safresh1 3855759b3d2Safresh1 is(0 + $!, 42, "altered \$! in tool (nested)"); 3865759b3d2Safresh1 is($@, 'app', "altered \$@ in tool (nested)"); 3875759b3d2Safresh1 is($?, 43, "altered \$? in tool (nested)"); 3885759b3d2Safresh1 3895759b3d2Safresh1 $ctx2->release; 3905759b3d2Safresh1 3915759b3d2Safresh1 is(0 + $!, 22, "restored the nested \$! in tool"); 3925759b3d2Safresh1 is($@, 'xyz', "restored the nested \$@ in tool"); 3935759b3d2Safresh1 is($?, 33, "restored the nested \$? in tool"); 3945759b3d2Safresh1 }->(); 3955759b3d2Safresh1 3965759b3d2Safresh1 sub { 3975759b3d2Safresh1 my $ctx2 = context(); 3985759b3d2Safresh1 3995759b3d2Safresh1 $! = 42; 4005759b3d2Safresh1 $@ = 'app'; 4015759b3d2Safresh1 $? = 43; 4025759b3d2Safresh1 4035759b3d2Safresh1 is(0 + $!, 42, "altered \$! in tool (nested)"); 4045759b3d2Safresh1 is($@, 'app', "altered \$@ in tool (nested)"); 4055759b3d2Safresh1 is($?, 43, "altered \$? in tool (nested)"); 4065759b3d2Safresh1 4075759b3d2Safresh1 # Will not warn since $@ is changed 4085759b3d2Safresh1 $ctx2 = undef; 4095759b3d2Safresh1 4105759b3d2Safresh1 is(0 + $!, 42, 'Destroy does not reset $!'); 4115759b3d2Safresh1 is($@, 'app', 'Destroy does not reset $@'); 4125759b3d2Safresh1 is($?, 43, 'Destroy does not reset $?'); 4135759b3d2Safresh1 }->(); 4145759b3d2Safresh1 4155759b3d2Safresh1 $ctx->release; 4165759b3d2Safresh1 4175759b3d2Safresh1 is($ctx->errno, 100, "restored errno"); 4185759b3d2Safresh1 is($ctx->eval_error, 'foobarbaz', "restored eval error"); 4195759b3d2Safresh1 is($ctx->child_error, 123, "restored child exit"); 4205759b3d2Safresh1}->(); 4215759b3d2Safresh1 4225759b3d2Safresh1 4235759b3d2Safresh1sub { 4245759b3d2Safresh1 local $! = 100; 4255759b3d2Safresh1 local $@ = 'foobarbaz'; 4265759b3d2Safresh1 local $? = 123; 4275759b3d2Safresh1 4285759b3d2Safresh1 my $ctx = context(); 4295759b3d2Safresh1 4305759b3d2Safresh1 is($ctx->errno, 100, "saved errno"); 4315759b3d2Safresh1 is($ctx->eval_error, 'foobarbaz', "saved eval error"); 4325759b3d2Safresh1 is($ctx->child_error, 123, "saved child exit"); 4335759b3d2Safresh1 4345759b3d2Safresh1 $! = 22; 4355759b3d2Safresh1 $@ = 'xyz'; 4365759b3d2Safresh1 $? = 33; 4375759b3d2Safresh1 4385759b3d2Safresh1 is(0 + $!, 22, "altered \$! in tool"); 4395759b3d2Safresh1 is($@, 'xyz', "altered \$@ in tool"); 4405759b3d2Safresh1 is($?, 33, "altered \$? in tool"); 4415759b3d2Safresh1 4425759b3d2Safresh1 # Will not warn since $@ is changed 4435759b3d2Safresh1 $ctx = undef; 4445759b3d2Safresh1 4455759b3d2Safresh1 is(0 + $!, 22, "Destroy does not restore \$!"); 4465759b3d2Safresh1 is($@, 'xyz', "Destroy does not restore \$@"); 4475759b3d2Safresh1 is($?, 33, "Destroy does not restore \$?"); 4485759b3d2Safresh1}->(); 4495759b3d2Safresh1 450f3efcd01Safresh1sub { 451f3efcd01Safresh1 require Test2::EventFacet::Info::Table; 452f3efcd01Safresh1 453f3efcd01Safresh1 my $events = intercept { 454f3efcd01Safresh1 my $ctx = context(); 455f3efcd01Safresh1 456f3efcd01Safresh1 $ctx->fail('foo', 'bar', Test2::EventFacet::Info::Table->new(rows => [['a', 'b']])); 457f3efcd01Safresh1 $ctx->fail_and_release('foo', 'bar', Test2::EventFacet::Info::Table->new(rows => [['a', 'b']], as_string => 'a, b')); 458f3efcd01Safresh1 }; 459f3efcd01Safresh1 460f3efcd01Safresh1 is(@$events, 2, "got 2 events"); 461f3efcd01Safresh1 462f3efcd01Safresh1 is($events->[0]->{info}->[0]->{details}, 'bar', "got first diag"); 463f3efcd01Safresh1 is($events->[0]->{info}->[1]->{details}, '<TABLE NOT DISPLAYED>', "second diag has default details"); 464f3efcd01Safresh1 is_deeply( 465f3efcd01Safresh1 $events->[0]->{info}->[1]->{table}, 466f3efcd01Safresh1 {rows => [['a', 'b']]}, 467f3efcd01Safresh1 "Got the table rows" 468f3efcd01Safresh1 ); 469f3efcd01Safresh1 470f3efcd01Safresh1 is($events->[1]->{info}->[0]->{details}, 'bar', "got first diag"); 471f3efcd01Safresh1 is($events->[1]->{info}->[1]->{details}, 'a, b', "second diag has custom details"); 472f3efcd01Safresh1 is_deeply( 473f3efcd01Safresh1 $events->[1]->{info}->[1]->{table}, 474f3efcd01Safresh1 {rows => [['a', 'b']]}, 475f3efcd01Safresh1 "Got the table rows" 476f3efcd01Safresh1 ); 477f3efcd01Safresh1 478f3efcd01Safresh1}->(); 479f3efcd01Safresh1 480*de8cc8edSafresh1sub ctx_destroy_test { 481*de8cc8edSafresh1 my (undef, undef, $line1) = caller(); 482*de8cc8edSafresh1 my (@warn, $line2); 483*de8cc8edSafresh1 local $SIG{__WARN__} = sub { push @warn => $_[0] }; 484*de8cc8edSafresh1 485*de8cc8edSafresh1 { my $ctx = context(); $ctx = undef } $line2 = __LINE__; 486*de8cc8edSafresh1 487*de8cc8edSafresh1 use Data::Dumper; 488*de8cc8edSafresh1# print Dumper(@warn); 489*de8cc8edSafresh1 490*de8cc8edSafresh1 like($warn[0], qr/context appears to have been destroyed without first calling release/, "Is normal context warning"); 491*de8cc8edSafresh1 like($warn[0], qr{\QContext destroyed at ${ \__FILE__ } line $line2\E}, "Reported context destruction trace"); 492*de8cc8edSafresh1 493*de8cc8edSafresh1 my $created = <<" EOT"; 494*de8cc8edSafresh1Here are the context creation details, just in case a tool forgot to call 495*de8cc8edSafresh1release(): 496*de8cc8edSafresh1 File: ${ \__FILE__ } 497*de8cc8edSafresh1 Line: $line1 498*de8cc8edSafresh1 Tool: main::ctx_destroy_test 499*de8cc8edSafresh1 EOT 500*de8cc8edSafresh1 501*de8cc8edSafresh1 like($warn[0], qr{\Q$created\E}, "Reported context creation details"); 502*de8cc8edSafresh1}; 503*de8cc8edSafresh1 504*de8cc8edSafresh1ctx_destroy_test(); 505*de8cc8edSafresh1 5065759b3d2Safresh1done_testing; 507