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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
#!/usr/bin/perl
use v5.14;
use warnings;
use Test2::V0;
use Future;
use Future::Utils qw( repeat try_repeat try_repeat_until_success );
{
my $trial_f;
my $previous_trial;
my $arg;
my $again;
my $future = repeat {
$previous_trial = shift;
return $trial_f = Future->new
} while => sub { $arg = shift; $again };
ok( defined $future, '$future defined for repeat while' );
ok( defined $trial_f, 'An initial future is running' );
my $first_f = $trial_f;
$again = 1;
$trial_f->done( "one" );
ok( defined $arg, '$arg defined for while test' );
is( scalar $arg->result, "one", '$arg->result for first' );
ref_is( $previous_trial, $first_f, 'code block is passed previous trial' );
$again = 0;
$trial_f->done( "two" );
ok( $future->is_ready, '$future is now ready after second attempt ->done' );
is( scalar $future->result, "two", '$future->result' );
}
# return keyword
{
my $trial_f;
my $future = repeat {
return $trial_f = Future->new
} while => sub { 1 }, return => my $ret = Future->new;
ref_is( $future, $ret, 'repeat with return yields correct instance' );
}
# cancellation
{
my @running; my $i = 0;
my $future = repeat {
return $running[$i++] = Future->new
} while => sub { 1 };
ok( defined $future, '$future defined for repeat while' );
ok( defined $running[0], 'An initial future is running' );
$running[0]->done;
$future->cancel;
ok( !$running[0]->is_cancelled, 'previously running future not cancelled' );
ok( $running[1]->is_cancelled, 'running future cancelled after eventual is cancelled' );
ok( !$running[2], 'a third trial is not started' );
}
# until
{
my $trial_f;
my $arg;
my $accept;
my $future = repeat {
return $trial_f = Future->new
} until => sub { $arg = shift; $accept };
ok( defined $future, '$future defined for repeat until' );
ok( defined $trial_f, 'An initial future is running' );
$accept = 0;
$trial_f->done( "three" );
ok( defined $arg, '$arg defined for while test' );
is( scalar $arg->result, "three", '$arg->result for first' );
$accept = 1;
$trial_f->done( "four" );
ok( $future->is_ready, '$future is now ready after second attempt ->done' );
is( scalar $future->result, "four", '$future->result' );
}
# body code dies
{
my $future;
$future = repeat {
die "It failed\n";
} while => sub { !shift->failure };
is( $future->failure, "It failed\n", 'repeat while failure after code exception' );
$future = repeat {
die "It failed\n";
} until => sub { shift->failure };
is( $future->failure, "It failed\n", 'repeat until failure after code exception' );
}
# condition code dies (RT100067)
{
my $future = repeat {
Future->done(1);
} while => sub { die "it dies!\n" };
is( $future->failure, "it dies!\n", 'repeat while failure after condition exception' );
}
# Non-Future return fails
{
my $future;
$future = repeat {
"non-Future"
} while => sub { !shift->failure };
like( $future->failure, qr/^Expected __ANON__.*\(\S+ line \d+\) to return a Future$/,
'repeat failure for non-Future return' );
}
# try_repeat catches failures
{
my $attempt = 0;
my $future = try_repeat {
if( ++$attempt < 3 ) {
return Future->new->fail( "Too low" );
}
else {
return Future->done( $attempt );
}
} while => sub { shift->failure };
ok( $future->is_ready, '$future is now ready for try_repeat' );
is( scalar $future->result, 3, '$future->result' );
}
{
my $attempt = 0;
my $future = try_repeat_until_success {
if( ++$attempt < 3 ) {
return Future->fail( "Too low" );
}
else {
return Future->done( $attempt );
}
};
ok( $future->is_ready, '$future is now ready for try_repeat_until_success' );
is( scalar $future->result, 3, '$future->result' );
}
# repeat prints a warning if asked to retry a failure
{
my $warnings = "";
local $SIG{__WARN__} = sub { $warnings .= join "", @_ };
my $attempt = 0;
my $future = repeat {
if( ++$attempt < 3 ) {
return Future->fail( "try again" );
}
else {
return Future->done( "OK" );
}
} while => sub { $_[0]->failure };
ok( $future->is_ready, '$future is now ready after repeat retries failures' );
like( $warnings, qr/(?:^Using Future::Utils::repeat to retry a failure is deprecated; use try_repeat instead at \Q$0\E line \d+\.?$)+/m,
'Warnings printing by repeat retries failures' );
}
done_testing;
|