2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
10 from future
import All
, Future
, Race
11 from mock_function
import MockFunction
14 class FutureTest(unittest
.TestCase
):
15 def testNoValueOrDelegate(self
):
16 self
.assertRaises(ValueError, Future
)
19 future
= Future(value
=42)
20 self
.assertEqual(42, future
.Get())
21 self
.assertEqual(42, future
.Get())
23 def testDelegateValue(self
):
26 self
.assertFalse(called
[0])
29 future
= Future(callback
=callback
)
30 self
.assertEqual(42, future
.Get())
31 self
.assertEqual(42, future
.Get())
33 def testErrorThrowingDelegate(self
):
34 class FunkyException(Exception):
37 # Set up a chain of functions to test the stack trace.
39 raise FunkyException()
46 chain
= [foo
, bar
, baz
, qux
]
50 self
.assertFalse(called
[0])
55 assertTrue
= self
.assertTrue
56 def assert_raises_full_stack(future
, err
):
59 fail('Did not raise %s' % err
)
60 except Exception as e
:
61 assertTrue(isinstance(e
, err
))
62 stack
= traceback
.format_exc()
63 assertTrue(all(stack
.find(fn
.__name
__) != -1 for fn
in chain
))
65 future
= Future(callback
=callback
)
66 assert_raises_full_stack(future
, FunkyException
)
67 assert_raises_full_stack(future
, FunkyException
)
70 def callback_with_value(value
):
71 return MockFunction(lambda: value
)
73 # Test a single value.
74 callback
= callback_with_value(42)
75 future
= All((Future(callback
=callback
),))
76 self
.assertTrue(*callback
.CheckAndReset(0))
77 self
.assertEqual([42], future
.Get())
78 self
.assertTrue(*callback
.CheckAndReset(1))
80 # Test multiple callbacks.
81 callbacks
= (callback_with_value(1),
82 callback_with_value(2),
83 callback_with_value(3))
84 future
= All(Future(callback
=callback
) for callback
in callbacks
)
85 for callback
in callbacks
:
86 self
.assertTrue(*callback
.CheckAndReset(0))
87 self
.assertEqual([1, 2, 3], future
.Get())
88 for callback
in callbacks
:
89 self
.assertTrue(*callback
.CheckAndReset(1))
91 # Test throwing an error.
94 callbacks
= (callback_with_value(1),
95 callback_with_value(2),
96 MockFunction(throws_error
))
98 future
= All(Future(callback
=callback
) for callback
in callbacks
)
99 for callback
in callbacks
:
100 self
.assertTrue(*callback
.CheckAndReset(0))
101 self
.assertRaises(ValueError, future
.Get
)
102 for callback
in callbacks
:
103 # Can't check that the callbacks were actually run because in theory the
104 # Futures can be resolved in any order.
105 callback
.CheckAndReset(0)
107 # Test throwing an error with except_pass.
108 future
= All((Future(callback
=callback
) for callback
in callbacks
),
109 except_pass
=ValueError)
110 for callback
in callbacks
:
111 self
.assertTrue(*callback
.CheckAndReset(0))
112 self
.assertEqual([1, 2, None], future
.Get())
114 def testRaceSuccess(self
):
115 callback
= MockFunction(lambda: 42)
117 # Test a single value.
118 race
= Race((Future(callback
=callback
),))
119 self
.assertTrue(*callback
.CheckAndReset(0))
120 self
.assertEqual(42, race
.Get())
121 self
.assertTrue(*callback
.CheckAndReset(1))
123 # Test multiple success values. Note that we could test different values
124 # and check that the first returned, but this is just an implementation
125 # detail of Race. When we have parallel Futures this might not always hold.
126 race
= Race((Future(callback
=callback
),
127 Future(callback
=callback
),
128 Future(callback
=callback
)))
129 self
.assertTrue(*callback
.CheckAndReset(0))
130 self
.assertEqual(42, race
.Get())
131 # Can't assert the actual count here for the same reason as above.
132 callback
.CheckAndReset(99)
134 # Test values with except_pass.
137 race
= Race((Future(callback
=callback
),
138 Future(callback
=throws_error
)),
139 except_pass
=(ValueError,))
140 self
.assertTrue(*callback
.CheckAndReset(0))
141 self
.assertEqual(42, race
.Get())
142 self
.assertTrue(*callback
.CheckAndReset(1))
144 def testRaceErrors(self
):
148 # Test a single error.
149 race
= Race((Future(callback
=throws_error
),))
150 self
.assertRaises(ValueError, race
.Get
)
152 # Test multiple errors. Can't use different error types for the same reason
153 # as described in testRaceSuccess.
154 race
= Race((Future(callback
=throws_error
),
155 Future(callback
=throws_error
),
156 Future(callback
=throws_error
)))
157 self
.assertRaises(ValueError, race
.Get
)
159 # Test values with except_pass.
160 def throws_except_error():
161 raise NotImplementedError()
162 race
= Race((Future(callback
=throws_error
),
163 Future(callback
=throws_except_error
)),
164 except_pass
=(NotImplementedError,))
165 self
.assertRaises(ValueError, race
.Get
)
167 race
= Race((Future(callback
=throws_error
),
168 Future(callback
=throws_error
)),
169 except_pass
=(ValueError,))
170 self
.assertRaises(ValueError, race
.Get
)
172 # Test except_pass with default values.
173 race
= Race((Future(callback
=throws_error
),
174 Future(callback
=throws_except_error
)),
175 except_pass
=(NotImplementedError,),
177 self
.assertRaises(ValueError, race
.Get
)
179 race
= Race((Future(callback
=throws_error
),
180 Future(callback
=throws_error
)),
181 except_pass
=(ValueError,),
183 self
.assertEqual(42, race
.Get())
187 self
.assertEqual(val
, 42)
190 then
= Future(value
=42).Then(assertIs42
)
191 # Shouldn't raise an error.
192 self
.assertEqual(42, then
.Get())
194 # Test raising an error.
195 then
= Future(value
=41).Then(assertIs42
)
196 self
.assertRaises(AssertionError, then
.Get
)
198 # Test setting up an error handler.
200 if isinstance(error
, ValueError):
204 def raiseValueError():
207 def raiseException():
210 then
= Future(callback
=raiseValueError
).Then(assertIs42
, handle
)
211 self
.assertEqual('Caught', then
.Get())
212 then
= Future(callback
=raiseException
).Then(assertIs42
, handle
)
213 self
.assertRaises(Exception, then
.Get
)
215 # Test chains of thens.
216 addOne
= lambda val
: val
+ 1
217 then
= Future(value
=40).Then(addOne
).Then(addOne
).Then(assertIs42
)
218 # Shouldn't raise an error.
219 self
.assertEqual(42, then
.Get())
221 # Test error in chain.
222 then
= Future(value
=40).Then(addOne
).Then(assertIs42
).Then(addOne
)
223 self
.assertRaises(AssertionError, then
.Get
)
225 # Test handle error in chain.
226 def raiseValueErrorWithVal(val
):
229 then
= Future(value
=40).Then(addOne
).Then(raiseValueErrorWithVal
).Then(
230 addOne
, handle
).Then(lambda val
: val
+ ' me')
231 self
.assertEquals(then
.Get(), 'Caught me')
233 # Test multiple handlers.
235 if isinstance(error
, AssertionError):
239 then
= Future(value
=40).Then(assertIs42
).Then(addOne
, handle
).Then(addOne
,
241 self
.assertEquals(then
.Get(), 10)
243 def testThenResolvesReturnedFutures(self
):
244 def returnsFortyTwo():
245 return Future(value
=42)
249 return Future(value
=x
+ 1)
251 self
.assertEqual(43, returnsFortyTwo().Then(inc
).Get())
252 self
.assertEqual(43, returnsFortyTwo().Then(incFuture
).Get())
253 self
.assertEqual(44, returnsFortyTwo().Then(inc
).Then(inc
).Get())
254 self
.assertEqual(44, returnsFortyTwo().Then(inc
).Then(incFuture
).Get())
255 self
.assertEqual(44, returnsFortyTwo().Then(incFuture
).Then(inc
).Get())
257 44, returnsFortyTwo().Then(incFuture
).Then(incFuture
).Get())
259 # The same behaviour should apply to error handlers.
260 def raisesSomething():
261 def boom(): raise ValueError
262 return Future(callback
=boom
)
263 def shouldNotHappen(_
):
264 raise AssertionError()
267 def oopsFuture(error
):
268 return Future(value
='oops')
271 'oops', raisesSomething().Then(shouldNotHappen
, oops
).Get())
273 'oops', raisesSomething().Then(shouldNotHappen
, oopsFuture
).Get())
276 raisesSomething().Then(shouldNotHappen
, raisesSomething
)
277 .Then(shouldNotHappen
, oops
).Get())
280 raisesSomething().Then(shouldNotHappen
, raisesSomething
)
281 .Then(shouldNotHappen
, oopsFuture
).Get())
284 if __name__
== '__main__':