1#!/usr/bin/perl 2 3use v5.10; 4use strict; 5use warnings; 6 7use Test::More; 8use Test::Identity; 9 10use Future; 11use Future::Utils qw( fmap_void ); 12 13# fmap_void from ARRAY, no concurrency 14{ 15 my @subf; 16 my $future = fmap_void { 17 is( $_, $_[0], 'item passed in $_ as well as @_' ); 18 return $subf[$_[0]] = Future->new 19 } foreach => [ 0 .. 2 ]; 20 21 ok( defined $future, '$future defined for fmap non-concurrent' ); 22 23 ok( defined $subf[0], '$subf[0] defined' ); 24 ok( !defined $subf[1], '$subf[1] not yet defined' ); 25 26 $subf[0]->done; 27 28 ok( defined $subf[1], '$subf[1] defined after $subf[0] done' ); 29 30 $subf[1]->done; 31 32 $subf[2]->done; 33 34 ok( $future->is_ready, '$future now ready after subs done' ); 35 is_deeply( [ $future->result ], [], '$future->result empty for fmap_void' ); 36} 37 38# fmap_void from CODE 39{ 40 my @subf; 41 my $future = fmap_void { 42 return $subf[$_[0]] = Future->new 43 } generate => do { my $count = 0; 44 sub { return unless $count < 3; $count++ } }; 45 46 ok( defined $future, '$future defined for fmap non-concurrent from CODE' ); 47 48 ok( defined $subf[0], '$subf[0] defined' ); 49 50 $subf[0]->done; 51 $subf[1]->done; 52 $subf[2]->done; 53 54 ok( $future->is_ready, '$future now ready after subs done from CODE' ); 55} 56 57# fmap_void concurrent 58{ 59 my @subf; 60 my $future = fmap_void { 61 return $subf[$_[0]] = Future->new 62 } foreach => [ 0 .. 4 ], 63 concurrent => 2; 64 65 ok( defined $future, '$future defined for fmap concurrent=2' ); 66 67 ok( defined $subf[0], '$subf[0] defined' ); 68 ok( defined $subf[1], '$subf[1] defined' ); 69 70 $subf[0]->done; $subf[1]->done; 71 72 ok( defined $subf[2], '$subf[2] defined' ); 73 ok( defined $subf[3], '$subf[3] defined' ); 74 75 $subf[2]->done; $subf[3]->done; 76 77 ok( defined $subf[4], '$subf[4] deifned' ); 78 ok( !$future->is_ready, '$future not yet ready while one sub remains' ); 79 80 $subf[4]->done; 81 82 ok( $future->is_ready, '$future now ready after concurrent subs done' ); 83} 84 85# fmap_void late-addition concurrently 86{ 87 my @items = ( 1, 2, 3 ); 88 my @subf; 89 my $future = fmap_void { 90 my $val = shift; 91 my $f = $subf[$val] = Future->new; 92 $f->on_done( sub { push @items, 4, 5, 6 } ) if $val == 3; 93 $f 94 } foreach => \@items, 95 concurrent => 4; 96 97 ok( defined $future, '$future defined for fmap concurrent=3 late-add' ); 98 99 ok( $subf[1] && $subf[2] && $subf[3], '3 subfutures initally ready' ); 100 101 $subf[1]->done; 102 $subf[2]->done; 103 104 ok( !$subf[4], 'No $subf[4] before $subf[3] done' ); 105 106 $subf[3]->done; 107 108 ok( $subf[4] && $subf[5] && $subf[6], '3 new subfutures now ready' ); 109 110 $subf[4]->done; 111 $subf[5]->done; 112 $subf[6]->done; 113 114 ok( $future->is_ready, '$future now ready after all 6 subfutures done' ); 115} 116 117# fmap_void on immediates 118{ 119 my $future = fmap_void { 120 return Future->done 121 } foreach => [ 0 .. 2 ]; 122 123 ok( $future->is_ready, '$future already ready for fmap on immediates' ); 124} 125 126# fmap_void on non/immediate mix 127{ 128 my @item_f = ( my $item = Future->new, Future->done, Future->done ); 129 my $future = fmap_void { 130 return $_[0]; 131 } foreach => \@item_f, 132 concurrent => 2; 133 134 ok( !$future->is_ready, '$future not yet ready before non-immediate done' ); 135 136 $item->done; 137 ok( $future->is_ready, '$future now ready after non-immediate done' ); 138} 139 140# fmap_void fail 141{ 142 my @subf; 143 my $future = fmap_void { 144 return $subf[$_[0]] = Future->new; 145 } foreach => [ 0, 1, 2 ], 146 concurrent => 2; 147 148 ok( !$subf[0]->is_cancelled, '$subf[0] not cancelled before failure' ); 149 150 $subf[1]->fail( "failure" ); 151 152 ok( $subf[0]->is_cancelled, '$subf[0] now cancelled after $subf[1] failure' ); 153 ok( $future->is_ready, '$future now ready after $sub[1] failure' ); 154 is( scalar $future->failure, "failure", '$future->failure after $sub[1] failure' ); 155 ok( !defined $subf[2], '$subf[2] was never started after $subf[1] failure' ); 156} 157 158# fmap_void immediate fail 159{ 160 my @subf; 161 my $future = fmap_void { 162 if( $_[0] eq "fail" ) { 163 return Future->fail( "failure" ); 164 } 165 else { 166 $subf[$_[0]] = Future->new; 167 } 168 } foreach => [ 0, "fail", 2 ], 169 concurrent => 3; 170 171 ok( $future->is_ready, '$future is already ready' ); 172 is( scalar $future->failure, "failure", '$future->failure after immediate failure' ); 173 174 ok( $subf[0]->is_cancelled, '$subf[0] is cancelled after immediate failure' ); 175 ok( !defined $subf[2], '$subf[2] was never started after immediate failure' ); 176} 177 178# fmap_void cancel 179{ 180 my @subf; 181 my $future = fmap_void { 182 return $subf[$_[0]] = Future->new; 183 } foreach => [ 0, 1, 2 ], 184 concurrent => 2; 185 186 $future->cancel; 187 188 ok( $subf[0]->is_cancelled, '$subf[0] now cancelled after ->cancel' ); 189 ok( $subf[1]->is_cancelled, '$subf[1] now cancelled after ->cancel' ); 190 ok( !defined $subf[2], '$subf[2] was never started after ->cancel' ); 191} 192 193# fmap_void return 194{ 195 my $future = fmap_void { 196 return Future->done; 197 } foreach => [ 0 ], return => my $ret = Future->new; 198 199 identical( $future, $ret, 'repeat with return yields correct instance' ); 200} 201 202done_testing; 203