1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
#!/usr/bin/perl
use v5.14;
use warnings;
use Test2::V0 0.000148; # is_refcount
use Future;
use Future::AsyncAwait;
my $orig_cxstack_ix = Future::AsyncAwait::__cxstack_ix;
my $file = quotemeta __FILE__;
my $errgv_ref = \*@;
async sub identity
{
return await $_[0];
}
async sub func
{
my ( $f, @vals ) = @_;
my $pad = "foo" . ref($f);
my $x = 123;
$x + 1 + [ "a", await identity $f ];
}
# abandoned chain
{
my $f1 = Future->new;
my $fret = func( $f1, 1, 2 );
undef $fret;
pass( 'abandoned chain does not crash' );
}
# abandoned subsequent (RT129303)
{
my $f1 = Future->new;
my $fret = func( $f1, 3, 4 );
undef $fret;
my $warnings = "";
{
local $SIG{__WARN__} = sub { $warnings .= join "", @_ };
$f1->done;
}
pass( 'abandoned subsequent does not crash' );
like( $warnings, qr/^Suspended async sub main::func lost its returning future at $file line \d+/,
'warning from attempted resume' );
}
# abandoned by code itself while not awaiting
{
my $fret;
async sub abandon
{
my ( $f1, $f2 ) = @_;
await $f1;
undef $fret;
await $f2;
}
$fret = abandon( my $f1 = Future->new, my $f2 = Future->new );
my $warnings = "";
{
local $SIG{__WARN__} = sub { $warnings .= join "", @_ };
$f1->done;
}
pass( 'abandoned by non-await code does not crash' );
like( $warnings, qr/^Suspended async sub main::abandon lost its returning future at $file line \d+/,
'warning from attempted resume' );
$f2->cancel;
}
# abandoned by code itself that throws
{
my $fret;
async sub abandon_and_die
{
my ( $f1 ) = @_;
await $f1;
undef $fret;
die "Oopsie\n";
}
$fret = abandon_and_die( my $f1 = Future->new );
my $warnings = "";
{
local $SIG{__WARN__} = sub { $warnings .= join "", @_ };
$f1->done;
}
pass( 'abandoned by non-await code does not crash' );
like( $warnings, qr/^Abandoned async sub main::abandon_and_die failed: Oopsie$/m,
'warning from attempted resume' );
}
# abandoned subsequent on anon sub
{
my $f1 = Future->new;
my $fret = (async sub { await $f1 })->();
undef $fret;
my $warnings = "";
{
local $SIG{__WARN__} = sub { $warnings .= join "", @_ };
$f1->done;
}
pass( 'abandoned subsequent does not crash' );
like( $warnings, qr/^Suspended async sub CODE\(0x[0-9a-f]+\) in package main lost its returning future at $file line \d+/,
'warning from attempted resume' );
}
# abandoned foreach loop (RT129320)
{
my $f1 = Future->new;
my $fret = (async sub { foreach my $f ($f1) { await $f } })->();
undef $fret;
pass( "abandoned foreach loop does not crash" );
}
# abandoned local $@
{
my $errsv_refcount = refcount(\$@);
my $errgv_refcount = refcount($errgv_ref);
my $f1 = Future->new;
my $fret = (async sub { local $@; await $f1 })->();
undef $fret;
undef $f1;
pass( "abandoned local \$@ does not crash" );
is_refcount( \$@, $errsv_refcount, '$@ refcount preserved' );
is_refcount( $errgv_ref, $errgv_refcount, '*@ refcount preserved' );
}
is( Future::AsyncAwait::__cxstack_ix, $orig_cxstack_ix,
'cxstack_ix did not grow during the test' );
done_testing;
|