xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Simple/t/Test2/modules/API/Context.t (revision de8cc8edbc71bd3e3bc7fbffa27ba0e564c37d8b)
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