#!/usr/bin/perl use strict; use warnings; use Test::More; use Test::Identity; use Future; use Future::Utils qw( fmap_void ); # fmap_void from ARRAY, no concurrency { my @subf; my $future = fmap_void { return $subf[$_[0]] = Future->new } foreach => [ 0 .. 2 ]; ok( defined $future, '$future defined for fmap non-concurrent' ); ok( defined $subf[0], '$subf[0] defined' ); ok( !defined $subf[1], '$subf[1] not yet defined' ); $subf[0]->done; ok( defined $subf[1], '$subf[1] defined after $subf[0] done' ); $subf[1]->done; $subf[2]->done; ok( $future->is_ready, '$future now ready after subs done' ); is_deeply( [ $future->get ], [], '$future->get empty for fmap_void' ); } # fmap_void from CODE { my @subf; my $future = fmap_void { return $subf[$_[0]] = Future->new } generate => do { my $count = 0; sub { return unless $count < 3; $count++ } }; ok( defined $future, '$future defined for fmap non-concurrent from CODE' ); ok( defined $subf[0], '$subf[0] defined' ); $subf[0]->done; $subf[1]->done; $subf[2]->done; ok( $future->is_ready, '$future now ready after subs done from CODE' ); } # fmap_void concurrent { my @subf; my $future = fmap_void { return $subf[$_[0]] = Future->new } foreach => [ 0 .. 4 ], concurrent => 2; ok( defined $future, '$future defined for fmap concurrent=2' ); ok( defined $subf[0], '$subf[0] defined' ); ok( defined $subf[1], '$subf[1] defined' ); $subf[0]->done; $subf[1]->done; ok( defined $subf[2], '$subf[2] defined' ); ok( defined $subf[3], '$subf[3] defined' ); $subf[2]->done; $subf[3]->done; ok( defined $subf[4], '$subf[4] deifned' ); ok( !$future->is_ready, '$future not yet ready while one sub remains' ); $subf[4]->done; ok( $future->is_ready, '$future now ready after concurrent subs done' ); } # fmap_void late-addition concurrently { my @items = ( 1, 2, 3 ); my @subf; my $future = fmap_void { my $val = shift; my $f = $subf[$val] = Future->new; $f->on_done( sub { push @items, 4, 5, 6 } ) if $val == 3; $f } foreach => \@items, concurrent => 4; ok( defined $future, '$future defined for fmap concurrent=3 late-add' ); ok( $subf[1] && $subf[2] && $subf[3], '3 subfutures initally ready' ); $subf[1]->done; $subf[2]->done; ok( !$subf[4], 'No $subf[4] before $subf[3] done' ); $subf[3]->done; ok( $subf[4] && $subf[5] && $subf[6], '3 new subfutures now ready' ); $subf[4]->done; $subf[5]->done; $subf[6]->done; ok( $future->is_ready, '$future now ready after all 6 subfutures done' ); } # fmap_void on immediates { my $future = fmap_void { return Future->done } foreach => [ 0 .. 2 ]; ok( $future->is_ready, '$future already ready for fmap on immediates' ); } # fmap_void on non/immediate mix { my @item_f = ( my $item = Future->new, Future->done, Future->done ); my $future = fmap_void { return $_[0]; } foreach => \@item_f, concurrent => 2; ok( !$future->is_ready, '$future not yet ready before non-immediate done' ); $item->done; ok( $future->is_ready, '$future now ready after non-immediate done' ); } # fmap_void fail { my @subf; my $future = fmap_void { return $subf[$_[0]] = Future->new; } foreach => [ 0, 1, 2 ], concurrent => 2; ok( !$subf[0]->is_cancelled, '$subf[0] not cancelled before failure' ); $subf[1]->fail( "failure" ); ok( $subf[0]->is_cancelled, '$subf[0] now cancelled after $subf[1] failure' ); ok( $future->is_ready, '$future now ready after $sub[1] failure' ); is( scalar $future->failure, "failure", '$future->failure after $sub[1] failure' ); ok( !defined $subf[2], '$subf[2] was never started after $subf[1] failure' ); } # fmap_void immediate fail { my @subf; my $future = fmap_void { if( $_[0] eq "fail" ) { return Future->fail( "failure" ); } else { $subf[$_[0]] = Future->new; } } foreach => [ 0, "fail", 2 ], concurrent => 3; ok( $future->is_ready, '$future is already ready' ); is( scalar $future->failure, "failure", '$future->failure after immediate failure' ); ok( $subf[0]->is_cancelled, '$subf[0] is cancelled after immediate failure' ); ok( !defined $subf[2], '$subf[2] was never started after immediate failure' ); } # fmap_void cancel { my @subf; my $future = fmap_void { return $subf[$_[0]] = Future->new; } foreach => [ 0, 1, 2 ], concurrent => 2; $future->cancel; ok( $subf[0]->is_cancelled, '$subf[0] now cancelled after ->cancel' ); ok( $subf[1]->is_cancelled, '$subf[1] now cancelled after ->cancel' ); ok( !defined $subf[2], '$subf[2] was never started after ->cancel' ); } # fmap_void return { my $future = fmap_void { return Future->done; } foreach => [ 0 ], return => my $ret = Future->new; identical( $future, $ret, 'repeat with return yields correct instance' ); } done_testing;