1#!/usr/bin/perl 2 3use v5.10; 4use strict; 5use warnings; 6 7use Test::More; 8use Test::Identity; 9use Test::Refcount; 10 11use Future; 12 13{ 14 my $f1 = Future->new; 15 my $f2 = Future->new; 16 17 my $future = Future->wait_all( $f1, $f2 ); 18 is_oneref( $future, '$future has refcount 1 initially' ); 19 20 # Two refs; one lexical here, one in $future 21 is_refcount( $f1, 2, '$f1 has refcount 2 after adding to ->wait_all' ); 22 is_refcount( $f2, 2, '$f2 has refcount 2 after adding to ->wait_all' ); 23 24 is_deeply( [ $future->pending_futures ], 25 [ $f1, $f2 ], 26 '$future->pending_futures before any ready' ); 27 28 is_deeply( [ $future->ready_futures ], 29 [], 30 '$future->done_futures before any ready' ); 31 32 my @on_ready_args; 33 $future->on_ready( sub { @on_ready_args = @_ } ); 34 35 ok( !$future->is_ready, '$future not yet ready' ); 36 is( scalar @on_ready_args, 0, 'on_ready not yet invoked' ); 37 38 $f1->done( one => 1 ); 39 40 is_deeply( [ $future->pending_futures ], 41 [ $f2 ], 42 '$future->pending_futures after $f1 ready' ); 43 44 is_deeply( [ $future->ready_futures ], 45 [ $f1 ], 46 '$future->ready_futures after $f1 ready' ); 47 48 is_deeply( [ $future->done_futures ], 49 [ $f1 ], 50 '$future->done_futures after $f1 ready' ); 51 52 ok( !$future->is_ready, '$future still not yet ready after f1 ready' ); 53 is( scalar @on_ready_args, 0, 'on_ready not yet invoked' ); 54 55 $f2->done( two => 2 ); 56 57 is( scalar @on_ready_args, 1, 'on_ready passed 1 argument' ); 58 identical( $on_ready_args[0], $future, 'Future passed to on_ready' ); 59 undef @on_ready_args; 60 61 ok( $future->is_ready, '$future now ready after f2 ready' ); 62 my @results = $future->result; 63 identical( $results[0], $f1, 'Results[0] from $future->result is f1' ); 64 identical( $results[1], $f2, 'Results[1] from $future->result is f2' ); 65 undef @results; 66 67 is_deeply( [ $future->pending_futures ], 68 [], 69 '$future->pending_futures after $f2 ready' ); 70 71 is_deeply( [ $future->ready_futures ], 72 [ $f1, $f2 ], 73 '$future->ready_futures after $f2 ready' ); 74 75 is_deeply( [ $future->done_futures ], 76 [ $f1, $f2 ], 77 '$future->done_futures after $f2 ready' ); 78 79 is_refcount( $future, 1, '$future has refcount 1 at end of test' ); 80 undef $future; 81 82 is_refcount( $f1, 1, '$f1 has refcount 1 at end of test' ); 83 is_refcount( $f2, 1, '$f2 has refcount 1 at end of test' ); 84} 85 86# immediately done 87{ 88 my $f1 = Future->done; 89 90 my $future = Future->wait_all( $f1 ); 91 92 ok( $future->is_ready, '$future of already-ready sub already ready' ); 93 my @results = $future->result; 94 identical( $results[0], $f1, 'Results from $future->result of already ready' ); 95} 96 97# one immediately done 98{ 99 my $f1 = Future->done; 100 my $f2 = Future->new; 101 102 my $future = Future->wait_all( $f1, $f2 ); 103 104 ok( !$future->is_ready, '$future of partially-done subs not yet ready' ); 105 106 $f2->done; 107 108 ok( $future->is_ready, '$future of completely-done subs already ready' ); 109 my @results = $future->result; 110 identical( $results[0], $f1, 'Results from $future->result of already ready' ); 111} 112 113# cancel propagation 114{ 115 my $f1 = Future->new; 116 my $c1; 117 $f1->on_cancel( sub { $c1++ } ); 118 119 my $f2 = Future->new; 120 my $c2; 121 $f2->on_cancel( sub { $c2++ } ); 122 123 my $future = Future->wait_all( $f1, $f2 ); 124 125 $f2->done; 126 127 $future->cancel; 128 129 is( $c1, 1, '$future->cancel marks subs cancelled' ); 130 is( $c2, undef, '$future->cancel ignores ready subs' ); 131} 132 133# cancelled convergent 134{ 135 my $f1 = Future->new; 136 my $f2 = Future->new; 137 138 my $future = Future->wait_all( $f1, $f2 ); 139 140 $f1->done( "result" ); 141 $f2->cancel; 142 143 ok( $future->is_ready, '$future of cancelled sub is ready after final cancellation' ); 144 145 is_deeply( [ $future->done_futures ], 146 [ $f1 ], 147 '->done_futures with cancellation' ); 148 is_deeply( [ $future->cancelled_futures ], 149 [ $f2 ], 150 '->cancelled_futures with cancellation' ); 151} 152 153# wait_all on none 154{ 155 my $f = Future->wait_all( () ); 156 157 ok( $f->is_ready, 'wait_all on no Futures already done' ); 158 is_deeply( [ $f->result ], [], '->result on empty wait_all is empty' ); 159} 160 161done_testing; 162