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 151 152 153 154 155 156 157 158 159
|
#!/usr/bin/perl
use v5.10;
use strict;
use warnings;
use Test2::V0 0.000148; # is_refcount
use Future;
my $__dummy; # to defeat non-closure optimsation
# catch success
{
my $f1 = Future->new;
my $cb;
my $fseq = $f1->catch(
test => $cb = sub {
$__dummy++;
die "catch of successful future should not be invoked";
},
);
ok( defined $fseq, '$fseq defined' );
isa_ok( $fseq, [ "Future" ], '$fseq' );
is_oneref( $fseq, '$fseq has refcount 1 initially' );
is_refcount( $cb, 2, '$cb has refcount 2 captured by catch callback' );
$f1->done( results => "here" );
is( [ $fseq->result ], [ results => "here" ], '$fseq succeeds when $f1 succeeds' );
undef $f1;
is_oneref( $fseq, '$fseq has refcount 1 before EOF' );
is_oneref( $cb, '$cb has refcount 1 before EOF' );
}
# catch immediate (RT145699)
{
my $f1 = Future->new;
$f1->done();
my $cb;
my $fseq = $f1->catch(
test => $cb = sub {
$__dummy++;
die "catch of successful future should not be invoked";
},
);
undef $f1;
is_oneref( $fseq, '$fseq has refcount 1 before EOF' );
is_oneref( $cb, '$cb has refcount 1 before EOF' );
}
# catch matching failure
{
my $f1 = Future->new;
my $f2;
my $fseq = $f1->catch(
test => sub {
is( $_[0], "f1 failure\n", 'catch block passed result of $f1' );
return $f2 = Future->done;
},
);
ok( defined $fseq, '$fseq defined' );
isa_ok( $fseq, [ "Future" ], '$fseq' );
is_oneref( $fseq, '$fseq has refcount 1 initially' );
$f1->fail( "f1 failure\n", test => );
undef $f1;
is_oneref( $fseq, '$fseq has refcount 1 after $f1 fail and dropped' );
ok( defined $f2, '$f2 now defined after $f1 fails' );
ok( $fseq->is_ready, '$fseq is done after $f2 done' );
}
# catch non-matching failure
{
my $f1 = Future->new;
my $fseq = $f1->catch(
test => sub { die "catch of non-matching Failure should not be invoked" },
);
$f1->fail( "f1 failure\n", different => );
ok( $fseq->is_ready, '$fseq is done after $f1 fail' );
is( scalar $fseq->failure, "f1 failure\n", '$fseq failure' );
}
# catch default handler
{
my $fseq = Future->fail( "failure", other => )
->catch(
test => sub { die "'test' catch should not match" },
sub { Future->done( default => "handler" ) },
);
is( [ $fseq->result ], [ default => "handler" ],
'->catch accepts a default handler' );
}
# catch via 'then'
{
is( scalar ( Future->fail( "message", test => )
->then( sub { die "then &done should not be invoked" },
test => sub { Future->done( 1234 ) },
sub { die "then &fail should not be invoked" } )->result ),
1234, 'catch semantics via ->then' );
}
# catch_with_f
{
my $f1 = Future->new;
my $fseq = $f1->catch_with_f(
test => sub {
ref_is( $_[0], $f1, '$f1 passed to catch code' );
is( $_[1], "f1 failure\n", '$f1 failure message passed to catch code' );
Future->done;
},
);
ok( defined $fseq, 'defined $fseq' );
isa_ok( $fseq, [ "Future" ], '$fseq' );
$f1->fail( "f1 failure\n", test => );
ok( $fseq->is_ready, '$fseq is done after $f1 fail' );
}
# catch via 'then_with_f'
{
my $f1 = Future->new;
my $fseq = $f1->then_with_f(
sub { die "then &done should not be invoked" },
test => sub {
ref_is( $_[0], $f1, '$f1 passed to catch code' );
is( $_[1], "f1 failure\n", '$f1 failure message passed to catch code' );
Future->done;
}
);
$f1->fail( "f1 failure\n", test => );
ok( $fseq->is_ready, '$fseq is done after $f1 fail' );
}
done_testing;
|