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