1 | /* |
2 | * Copyright 2014-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #include <folly/futures/Future.h> |
18 | #include <folly/Executor.h> |
19 | #include <folly/Memory.h> |
20 | #include <folly/Unit.h> |
21 | #include <folly/dynamic.h> |
22 | #include <folly/executors/ManualExecutor.h> |
23 | #include <folly/portability/GTest.h> |
24 | #include <folly/synchronization/Baton.h> |
25 | |
26 | #include <algorithm> |
27 | #include <atomic> |
28 | #include <memory> |
29 | #include <numeric> |
30 | #include <queue> |
31 | #include <string> |
32 | #include <thread> |
33 | #include <type_traits> |
34 | |
35 | using namespace folly; |
36 | |
37 | #define EXPECT_TYPE(x, T) EXPECT_TRUE((std::is_same<decltype(x), T>::value)) |
38 | |
39 | typedef FutureException eggs_t; |
40 | static eggs_t eggs("eggs" ); |
41 | |
42 | // Future |
43 | |
44 | TEST(Future, makeEmpty) { |
45 | auto f = Future<int>::makeEmpty(); |
46 | EXPECT_THROW(f.isReady(), FutureInvalid); |
47 | } |
48 | |
49 | TEST(Future, futureDefaultCtor) { |
50 | Future<Unit>(); |
51 | } |
52 | |
53 | TEST(Future, futureToUnit) { |
54 | Future<Unit> fu = makeFuture(42).unit(); |
55 | fu.value(); |
56 | EXPECT_TRUE(makeFuture<int>(eggs).unit().hasException()); |
57 | } |
58 | |
59 | TEST(Future, voidFutureToUnit) { |
60 | Future<Unit> fu = makeFuture().unit(); |
61 | fu.value(); |
62 | EXPECT_TRUE(makeFuture<Unit>(eggs).unit().hasException()); |
63 | } |
64 | |
65 | TEST(Future, unitFutureToUnitIdentity) { |
66 | Future<Unit> fu = makeFuture(Unit{}).unit(); |
67 | fu.value(); |
68 | EXPECT_TRUE(makeFuture<Unit>(eggs).unit().hasException()); |
69 | } |
70 | |
71 | TEST(Future, toUnitWhileInProgress) { |
72 | Promise<int> p; |
73 | Future<Unit> fu = p.getFuture().unit(); |
74 | EXPECT_FALSE(fu.isReady()); |
75 | p.setValue(42); |
76 | EXPECT_TRUE(fu.isReady()); |
77 | } |
78 | |
79 | TEST(Future, makeFutureWithUnit) { |
80 | int count = 0; |
81 | Future<Unit> fu = makeFutureWith([&] { count++; }); |
82 | EXPECT_EQ(1, count); |
83 | } |
84 | |
85 | TEST(Future, getRequiresOnlyMoveCtor) { |
86 | struct MoveCtorOnly { |
87 | explicit MoveCtorOnly(int id) : id_(id) {} |
88 | MoveCtorOnly(const MoveCtorOnly&) = delete; |
89 | MoveCtorOnly(MoveCtorOnly&&) = default; |
90 | void operator=(MoveCtorOnly const&) = delete; |
91 | void operator=(MoveCtorOnly&&) = delete; |
92 | int id_; |
93 | }; |
94 | { |
95 | auto f = makeFuture<MoveCtorOnly>(MoveCtorOnly(42)); |
96 | EXPECT_TRUE(f.valid()); |
97 | EXPECT_TRUE(f.isReady()); |
98 | auto v = std::move(f).get(); |
99 | EXPECT_EQ(v.id_, 42); |
100 | } |
101 | { |
102 | auto f = makeFuture<MoveCtorOnly>(MoveCtorOnly(42)); |
103 | EXPECT_TRUE(f.valid()); |
104 | EXPECT_TRUE(f.isReady()); |
105 | auto v = std::move(f).get(); |
106 | EXPECT_EQ(v.id_, 42); |
107 | } |
108 | { |
109 | auto f = makeFuture<MoveCtorOnly>(MoveCtorOnly(42)); |
110 | EXPECT_TRUE(f.valid()); |
111 | EXPECT_TRUE(f.isReady()); |
112 | auto v = std::move(f).get(std::chrono::milliseconds(10)); |
113 | EXPECT_EQ(v.id_, 42); |
114 | } |
115 | { |
116 | auto f = makeFuture<MoveCtorOnly>(MoveCtorOnly(42)); |
117 | EXPECT_TRUE(f.valid()); |
118 | EXPECT_TRUE(f.isReady()); |
119 | auto v = std::move(f).get(std::chrono::milliseconds(10)); |
120 | EXPECT_EQ(v.id_, 42); |
121 | } |
122 | } |
123 | |
124 | namespace { |
125 | auto makeValid() { |
126 | auto valid = makeFuture<int>(42); |
127 | EXPECT_TRUE(valid.valid()); |
128 | return valid; |
129 | } |
130 | auto makeInvalid() { |
131 | auto invalid = Future<int>::makeEmpty(); |
132 | EXPECT_FALSE(invalid.valid()); |
133 | return invalid; |
134 | } |
135 | } // namespace |
136 | |
137 | TEST(Future, ctorPostconditionValid) { |
138 | // Ctors/factories that promise valid -- postcondition: valid() |
139 | |
140 | #define DOIT(CREATION_EXPR) \ |
141 | do { \ |
142 | auto f1 = (CREATION_EXPR); \ |
143 | EXPECT_TRUE(f1.valid()); \ |
144 | auto f2 = std::move(f1); \ |
145 | EXPECT_FALSE(f1.valid()); \ |
146 | EXPECT_TRUE(f2.valid()); \ |
147 | } while (false) |
148 | |
149 | auto const except = std::logic_error("foo" ); |
150 | auto const ewrap = folly::exception_wrapper(except); |
151 | |
152 | DOIT(makeValid()); |
153 | DOIT(Future<int>(42)); |
154 | DOIT(Future<int>{42}); |
155 | DOIT(Future<Unit>()); |
156 | DOIT(Future<Unit>{}); |
157 | DOIT(makeFuture()); |
158 | DOIT(makeFuture(Unit{})); |
159 | DOIT(makeFuture<Unit>(Unit{})); |
160 | DOIT(makeFuture(42)); |
161 | DOIT(makeFuture<int>(42)); |
162 | DOIT(makeFuture<int>(except)); |
163 | DOIT(makeFuture<int>(ewrap)); |
164 | DOIT(makeFuture(Try<int>(42))); |
165 | DOIT(makeFuture<int>(Try<int>(42))); |
166 | DOIT(makeFuture<int>(Try<int>(ewrap))); |
167 | |
168 | #undef DOIT |
169 | } |
170 | |
171 | TEST(Future, ctorPostconditionInvalid) { |
172 | // Ctors/factories that promise invalid -- postcondition: !valid() |
173 | |
174 | #define DOIT(CREATION_EXPR) \ |
175 | do { \ |
176 | auto f1 = (CREATION_EXPR); \ |
177 | EXPECT_FALSE(f1.valid()); \ |
178 | auto f2 = std::move(f1); \ |
179 | EXPECT_FALSE(f1.valid()); \ |
180 | EXPECT_FALSE(f2.valid()); \ |
181 | } while (false) |
182 | |
183 | DOIT(makeInvalid()); |
184 | DOIT(Future<int>::makeEmpty()); |
185 | |
186 | #undef DOIT |
187 | } |
188 | |
189 | TEST(Future, lacksPreconditionValid) { |
190 | // Ops that don't throw FutureInvalid if !valid() -- |
191 | // without precondition: valid() |
192 | |
193 | #define DOIT(STMT) \ |
194 | do { \ |
195 | auto f = makeValid(); \ |
196 | { STMT; } \ |
197 | copy(std::move(f)); \ |
198 | EXPECT_NO_THROW(STMT); \ |
199 | } while (false) |
200 | |
201 | // .valid() itself |
202 | DOIT(f.valid()); |
203 | |
204 | // move-ctor - move-copy to local, copy(), pass-by-move-value |
205 | DOIT(auto other = std::move(f)); |
206 | DOIT(copy(std::move(f))); |
207 | DOIT(([](auto) {})(std::move(f))); |
208 | |
209 | // move-assignment into either {valid | invalid} |
210 | DOIT({ |
211 | auto other = makeValid(); |
212 | other = std::move(f); |
213 | }); |
214 | DOIT({ |
215 | auto other = makeInvalid(); |
216 | other = std::move(f); |
217 | }); |
218 | |
219 | #undef DOIT |
220 | } |
221 | |
222 | TEST(Future, hasPreconditionValid) { |
223 | // Ops that require validity; precondition: valid(); |
224 | // throw FutureInvalid if !valid() |
225 | |
226 | #define DOIT(STMT) \ |
227 | do { \ |
228 | auto f = makeValid(); \ |
229 | EXPECT_NO_THROW(STMT); \ |
230 | copy(std::move(f)); \ |
231 | EXPECT_THROW(STMT, FutureInvalid); \ |
232 | } while (false) |
233 | |
234 | DOIT(f.isReady()); |
235 | DOIT(f.result()); |
236 | DOIT(std::move(f).get()); |
237 | DOIT(std::move(f).get(std::chrono::milliseconds(10))); |
238 | DOIT(f.getTry()); |
239 | DOIT(f.hasValue()); |
240 | DOIT(f.hasException()); |
241 | DOIT(f.value()); |
242 | DOIT(f.poll()); |
243 | DOIT(std::move(f).then()); |
244 | DOIT(std::move(f).thenValue([](auto&&) {})); |
245 | |
246 | #undef DOIT |
247 | } |
248 | |
249 | TEST(Future, hasPostconditionValid) { |
250 | // Ops that preserve validity -- postcondition: valid() |
251 | |
252 | #define DOIT(STMT) \ |
253 | do { \ |
254 | auto f = makeValid(); \ |
255 | EXPECT_NO_THROW(STMT); \ |
256 | EXPECT_TRUE(f.valid()); \ |
257 | } while (false) |
258 | |
259 | auto const swallow = [](auto) {}; |
260 | |
261 | DOIT(swallow(f.valid())); // f.valid() itself preserves validity |
262 | DOIT(swallow(f.isReady())); |
263 | DOIT(swallow(f.hasValue())); |
264 | DOIT(swallow(f.hasException())); |
265 | DOIT(swallow(f.value())); |
266 | DOIT(swallow(f.getTry())); |
267 | DOIT(swallow(f.poll())); |
268 | DOIT(f.raise(std::logic_error("foo" ))); |
269 | DOIT(f.cancel()); |
270 | DOIT(swallow(f.getTry())); |
271 | DOIT(f.wait()); |
272 | DOIT(std::move(f.wait())); |
273 | |
274 | #undef DOIT |
275 | } |
276 | |
277 | TEST(Future, hasPostconditionInvalid) { |
278 | // Ops that consume *this -- postcondition: !valid() |
279 | |
280 | #define DOIT(CTOR, STMT) \ |
281 | do { \ |
282 | auto f = (CTOR); \ |
283 | EXPECT_NO_THROW(STMT); \ |
284 | EXPECT_FALSE(f.valid()); \ |
285 | } while (false) |
286 | |
287 | // move-ctor of {valid|invalid} |
288 | DOIT(makeValid(), { auto other{std::move(f)}; }); |
289 | DOIT(makeInvalid(), { auto other{std::move(f)}; }); |
290 | |
291 | // move-assignment of {valid|invalid} into {valid|invalid} |
292 | DOIT(makeValid(), { |
293 | auto other = makeValid(); |
294 | other = std::move(f); |
295 | }); |
296 | DOIT(makeValid(), { |
297 | auto other = makeInvalid(); |
298 | other = std::move(f); |
299 | }); |
300 | DOIT(makeInvalid(), { |
301 | auto other = makeValid(); |
302 | other = std::move(f); |
303 | }); |
304 | DOIT(makeInvalid(), { |
305 | auto other = makeInvalid(); |
306 | other = std::move(f); |
307 | }); |
308 | |
309 | // pass-by-value of {valid|invalid} |
310 | DOIT(makeValid(), { |
311 | auto const byval = [](auto) {}; |
312 | byval(std::move(f)); |
313 | }); |
314 | DOIT(makeInvalid(), { |
315 | auto const byval = [](auto) {}; |
316 | byval(std::move(f)); |
317 | }); |
318 | |
319 | // other consuming ops |
320 | auto const swallow = [](auto) {}; |
321 | DOIT(makeValid(), swallow(std::move(f).wait())); |
322 | DOIT(makeValid(), swallow(std::move(f.wait()))); |
323 | DOIT(makeValid(), swallow(std::move(f).get())); |
324 | DOIT(makeValid(), swallow(std::move(f).get(std::chrono::milliseconds(10)))); |
325 | DOIT(makeValid(), swallow(std::move(f).semi())); |
326 | |
327 | #undef DOIT |
328 | } |
329 | |
330 | namespace { |
331 | Future<int> onErrorHelperEggs(const eggs_t&) { |
332 | return makeFuture(10); |
333 | } |
334 | Future<int> onErrorHelperGeneric(const std::exception&) { |
335 | return makeFuture(20); |
336 | } |
337 | Future<int> onErrorHelperWrapper(folly::exception_wrapper&&) { |
338 | return makeFuture(30); |
339 | } |
340 | } // namespace |
341 | |
342 | TEST(Future, onError) { |
343 | bool theFlag = false; |
344 | auto flag = [&] { theFlag = true; }; |
345 | #define EXPECT_FLAG() \ |
346 | do { \ |
347 | EXPECT_TRUE(theFlag); \ |
348 | theFlag = false; \ |
349 | } while (0); |
350 | |
351 | #define EXPECT_NO_FLAG() \ |
352 | do { \ |
353 | EXPECT_FALSE(theFlag); \ |
354 | theFlag = false; \ |
355 | } while (0); |
356 | |
357 | // By reference |
358 | { |
359 | auto f = makeFuture() |
360 | .thenValue([](auto&&) { throw eggs; }) |
361 | .onError([&](eggs_t& /* e */) { flag(); }); |
362 | EXPECT_FLAG(); |
363 | EXPECT_NO_THROW(f.value()); |
364 | } |
365 | |
366 | { |
367 | auto f = makeFuture() |
368 | .thenValue([](auto&&) { throw eggs; }) |
369 | .onError([&](eggs_t& /* e */) { |
370 | flag(); |
371 | return makeFuture(); |
372 | }); |
373 | EXPECT_FLAG(); |
374 | EXPECT_NO_THROW(f.value()); |
375 | } |
376 | |
377 | // By value |
378 | { |
379 | auto f = makeFuture() |
380 | .thenValue([](auto&&) { throw eggs; }) |
381 | .onError([&](eggs_t /* e */) { flag(); }); |
382 | EXPECT_FLAG(); |
383 | EXPECT_NO_THROW(f.value()); |
384 | } |
385 | |
386 | { |
387 | auto f = makeFuture() |
388 | .thenValue([](auto&&) { throw eggs; }) |
389 | .onError([&](eggs_t /* e */) { |
390 | flag(); |
391 | return makeFuture(); |
392 | }); |
393 | EXPECT_FLAG(); |
394 | EXPECT_NO_THROW(f.value()); |
395 | } |
396 | |
397 | // Polymorphic |
398 | { |
399 | auto f = makeFuture() |
400 | .thenValue([](auto&&) { throw eggs; }) |
401 | .onError([&](std::exception& /* e */) { flag(); }); |
402 | EXPECT_FLAG(); |
403 | EXPECT_NO_THROW(f.value()); |
404 | } |
405 | |
406 | { |
407 | auto f = makeFuture() |
408 | .thenValue([](auto&&) { throw eggs; }) |
409 | .onError([&](std::exception& /* e */) { |
410 | flag(); |
411 | return makeFuture(); |
412 | }); |
413 | EXPECT_FLAG(); |
414 | EXPECT_NO_THROW(f.value()); |
415 | } |
416 | |
417 | // Non-exceptions |
418 | { |
419 | auto f = makeFuture() |
420 | .thenValue([](auto&&) { throw - 1; }) |
421 | .onError([&](int /* e */) { flag(); }); |
422 | EXPECT_FLAG(); |
423 | EXPECT_NO_THROW(f.value()); |
424 | } |
425 | |
426 | { |
427 | auto f = makeFuture() |
428 | .thenValue([](auto&&) { throw - 1; }) |
429 | .onError([&](int /* e */) { |
430 | flag(); |
431 | return makeFuture(); |
432 | }); |
433 | EXPECT_FLAG(); |
434 | EXPECT_NO_THROW(f.value()); |
435 | } |
436 | |
437 | // Mutable lambda |
438 | { |
439 | auto f = makeFuture() |
440 | .thenValue([](auto&&) { throw eggs; }) |
441 | .onError([&](eggs_t& /* e */) mutable { flag(); }); |
442 | EXPECT_FLAG(); |
443 | EXPECT_NO_THROW(f.value()); |
444 | } |
445 | |
446 | { |
447 | auto f = makeFuture() |
448 | .thenValue([](auto&&) { throw eggs; }) |
449 | .onError([&](eggs_t& /* e */) mutable { |
450 | flag(); |
451 | return makeFuture(); |
452 | }); |
453 | EXPECT_FLAG(); |
454 | EXPECT_NO_THROW(f.value()); |
455 | } |
456 | |
457 | // Function pointer |
458 | { |
459 | auto f = makeFuture() |
460 | .thenValue([](auto &&) -> int { throw eggs; }) |
461 | .onError(onErrorHelperEggs) |
462 | .onError(onErrorHelperGeneric); |
463 | EXPECT_EQ(10, f.value()); |
464 | } |
465 | { |
466 | auto f = |
467 | makeFuture() |
468 | .thenValue([](auto &&) -> int { throw std::runtime_error("test" ); }) |
469 | .onError(onErrorHelperEggs) |
470 | .onError(onErrorHelperGeneric); |
471 | EXPECT_EQ(20, f.value()); |
472 | } |
473 | { |
474 | auto f = |
475 | makeFuture() |
476 | .thenValue([](auto &&) -> int { throw std::runtime_error("test" ); }) |
477 | .onError(onErrorHelperEggs); |
478 | EXPECT_THROW(f.value(), std::runtime_error); |
479 | } |
480 | { |
481 | auto f = makeFuture() |
482 | .thenValue([](auto &&) -> int { throw eggs; }) |
483 | .thenError<eggs_t>(onErrorHelperEggs) |
484 | .thenError<std::exception>(onErrorHelperGeneric); |
485 | EXPECT_EQ(10, f.value()); |
486 | } |
487 | { |
488 | auto f = |
489 | makeFuture() |
490 | .thenValue([](auto &&) -> int { throw std::runtime_error("test" ); }) |
491 | .thenError<eggs_t>(onErrorHelperEggs) |
492 | .thenError(onErrorHelperWrapper); |
493 | EXPECT_EQ(30, f.value()); |
494 | } |
495 | { |
496 | auto f = |
497 | makeFuture() |
498 | .thenValue([](auto &&) -> int { throw std::runtime_error("test" ); }) |
499 | .thenError<eggs_t>(onErrorHelperEggs); |
500 | EXPECT_THROW(f.value(), std::runtime_error); |
501 | } |
502 | |
503 | // No throw |
504 | { |
505 | auto f = makeFuture() |
506 | .thenValue([](auto&&) { return 42; }) |
507 | .onError([&](eggs_t& /* e */) { |
508 | flag(); |
509 | return -1; |
510 | }); |
511 | EXPECT_NO_FLAG(); |
512 | EXPECT_EQ(42, f.value()); |
513 | } |
514 | |
515 | { |
516 | auto f = makeFuture() |
517 | .thenValue([](auto&&) { return 42; }) |
518 | .onError([&](eggs_t& /* e */) { |
519 | flag(); |
520 | return makeFuture<int>(-1); |
521 | }); |
522 | EXPECT_NO_FLAG(); |
523 | EXPECT_EQ(42, f.value()); |
524 | } |
525 | |
526 | // Catch different exception |
527 | { |
528 | auto f = makeFuture() |
529 | .thenValue([](auto&&) { throw eggs; }) |
530 | .onError([&](std::runtime_error& /* e */) { flag(); }); |
531 | EXPECT_NO_FLAG(); |
532 | EXPECT_THROW(f.value(), eggs_t); |
533 | } |
534 | |
535 | { |
536 | auto f = makeFuture() |
537 | .thenValue([](auto&&) { throw eggs; }) |
538 | .onError([&](std::runtime_error& /* e */) { |
539 | flag(); |
540 | return makeFuture(); |
541 | }); |
542 | EXPECT_NO_FLAG(); |
543 | EXPECT_THROW(f.value(), eggs_t); |
544 | } |
545 | |
546 | // Returned value propagates |
547 | { |
548 | auto f = makeFuture() |
549 | .thenValue([](auto &&) -> int { throw eggs; }) |
550 | .onError([&](eggs_t& /* e */) { return 42; }); |
551 | EXPECT_EQ(42, f.value()); |
552 | } |
553 | |
554 | // Returned future propagates |
555 | { |
556 | auto f = makeFuture() |
557 | .thenValue([](auto &&) -> int { throw eggs; }) |
558 | .onError([&](eggs_t& /* e */) { return makeFuture<int>(42); }); |
559 | EXPECT_EQ(42, f.value()); |
560 | } |
561 | |
562 | // Throw in callback |
563 | { |
564 | auto f = makeFuture() |
565 | .thenValue([](auto &&) -> int { throw eggs; }) |
566 | .onError([&](eggs_t& e) -> int { throw e; }); |
567 | EXPECT_THROW(f.value(), eggs_t); |
568 | } |
569 | |
570 | { |
571 | auto f = makeFuture() |
572 | .thenValue([](auto &&) -> int { throw eggs; }) |
573 | .onError([&](eggs_t& e) -> Future<int> { throw e; }); |
574 | EXPECT_THROW(f.value(), eggs_t); |
575 | } |
576 | |
577 | // exception_wrapper, return Future<T> |
578 | { |
579 | auto f = makeFuture() |
580 | .thenValue([](auto&&) { throw eggs; }) |
581 | .onError([&](exception_wrapper /* e */) { |
582 | flag(); |
583 | return makeFuture(); |
584 | }); |
585 | EXPECT_FLAG(); |
586 | EXPECT_NO_THROW(f.value()); |
587 | } |
588 | |
589 | // exception_wrapper, return Future<T> but throw |
590 | { |
591 | auto f = makeFuture() |
592 | .thenValue([](auto &&) -> int { throw eggs; }) |
593 | .onError([&](exception_wrapper /* e */) -> Future<int> { |
594 | flag(); |
595 | throw eggs; |
596 | }); |
597 | EXPECT_FLAG(); |
598 | EXPECT_THROW(f.value(), eggs_t); |
599 | } |
600 | |
601 | // exception_wrapper, return T |
602 | { |
603 | auto f = makeFuture() |
604 | .thenValue([](auto &&) -> int { throw eggs; }) |
605 | .onError([&](exception_wrapper /* e */) { |
606 | flag(); |
607 | return -1; |
608 | }); |
609 | EXPECT_FLAG(); |
610 | EXPECT_EQ(-1, f.value()); |
611 | } |
612 | |
613 | // exception_wrapper, return T but throw |
614 | { |
615 | auto f = makeFuture() |
616 | .thenValue([](auto &&) -> int { throw eggs; }) |
617 | .onError([&](exception_wrapper /* e */) -> int { |
618 | flag(); |
619 | throw eggs; |
620 | }); |
621 | EXPECT_FLAG(); |
622 | EXPECT_THROW(f.value(), eggs_t); |
623 | } |
624 | |
625 | // const exception_wrapper& |
626 | { |
627 | auto f = makeFuture() |
628 | .thenValue([](auto&&) { throw eggs; }) |
629 | .onError([&](const exception_wrapper& /* e */) { |
630 | flag(); |
631 | return makeFuture(); |
632 | }); |
633 | EXPECT_FLAG(); |
634 | EXPECT_NO_THROW(f.value()); |
635 | } |
636 | #undef EXPECT_FLAG |
637 | #undef EXPECT_NO_FLAG |
638 | } |
639 | |
640 | TEST(Future, thenError) { |
641 | bool theFlag = false; |
642 | auto flag = [&] { theFlag = true; }; |
643 | #define EXPECT_FLAG() \ |
644 | do { \ |
645 | EXPECT_TRUE(theFlag); \ |
646 | theFlag = false; \ |
647 | } while (0); |
648 | |
649 | #define EXPECT_NO_FLAG() \ |
650 | do { \ |
651 | EXPECT_FALSE(theFlag); \ |
652 | theFlag = false; \ |
653 | } while (0); |
654 | |
655 | // By reference |
656 | { |
657 | auto f = makeFuture() |
658 | .thenValue([](auto&&) { throw eggs; }) |
659 | .thenError<eggs_t>([&](const eggs_t& /* e */) { flag(); }); |
660 | EXPECT_FLAG(); |
661 | EXPECT_NO_THROW(f.value()); |
662 | } |
663 | |
664 | // By auto reference |
665 | { |
666 | auto f = makeFuture() |
667 | .thenValue([](auto&&) { throw eggs; }) |
668 | .thenError<eggs_t>([&](auto const& /* e */) { flag(); }); |
669 | EXPECT_FLAG(); |
670 | EXPECT_NO_THROW(f.value()); |
671 | } |
672 | |
673 | { |
674 | auto f = makeFuture() |
675 | .thenValue([](auto&&) { throw eggs; }) |
676 | .onError([&](eggs_t& /* e */) { |
677 | flag(); |
678 | return makeFuture(); |
679 | }); |
680 | EXPECT_FLAG(); |
681 | EXPECT_NO_THROW(f.value()); |
682 | } |
683 | |
684 | // By value |
685 | { |
686 | auto f = makeFuture() |
687 | .thenValue([](auto&&) { throw eggs; }) |
688 | .onError([&](eggs_t /* e */) { flag(); }); |
689 | EXPECT_FLAG(); |
690 | EXPECT_NO_THROW(f.value()); |
691 | } |
692 | |
693 | { |
694 | auto f = makeFuture() |
695 | .thenValue([](auto&&) { throw eggs; }) |
696 | .onError([&](eggs_t /* e */) { |
697 | flag(); |
698 | return makeFuture(); |
699 | }); |
700 | EXPECT_FLAG(); |
701 | EXPECT_NO_THROW(f.value()); |
702 | } |
703 | |
704 | // Polymorphic |
705 | { |
706 | auto f = makeFuture() |
707 | .thenValue([](auto&&) { throw eggs; }) |
708 | .onError([&](std::exception& /* e */) { flag(); }); |
709 | EXPECT_FLAG(); |
710 | EXPECT_NO_THROW(f.value()); |
711 | } |
712 | |
713 | { |
714 | auto f = makeFuture() |
715 | .thenValue([](auto&&) { throw eggs; }) |
716 | .onError([&](std::exception& /* e */) { |
717 | flag(); |
718 | return makeFuture(); |
719 | }); |
720 | EXPECT_FLAG(); |
721 | EXPECT_NO_THROW(f.value()); |
722 | } |
723 | |
724 | // Non-exceptions |
725 | { |
726 | auto f = makeFuture() |
727 | .thenValue([](auto&&) { throw - 1; }) |
728 | .onError([&](int /* e */) { flag(); }); |
729 | EXPECT_FLAG(); |
730 | EXPECT_NO_THROW(f.value()); |
731 | } |
732 | |
733 | { |
734 | auto f = makeFuture() |
735 | .thenValue([](auto&&) { throw - 1; }) |
736 | .onError([&](int /* e */) { |
737 | flag(); |
738 | return makeFuture(); |
739 | }); |
740 | EXPECT_FLAG(); |
741 | EXPECT_NO_THROW(f.value()); |
742 | } |
743 | |
744 | // Mutable lambda |
745 | { |
746 | auto f = makeFuture() |
747 | .thenValue([](auto&&) { throw eggs; }) |
748 | .onError([&](eggs_t& /* e */) mutable { flag(); }); |
749 | EXPECT_FLAG(); |
750 | EXPECT_NO_THROW(f.value()); |
751 | } |
752 | |
753 | { |
754 | auto f = makeFuture() |
755 | .thenValue([](auto&&) { throw eggs; }) |
756 | .onError([&](eggs_t& /* e */) mutable { |
757 | flag(); |
758 | return makeFuture(); |
759 | }); |
760 | EXPECT_FLAG(); |
761 | EXPECT_NO_THROW(f.value()); |
762 | } |
763 | |
764 | // Function pointer |
765 | { |
766 | auto f = makeFuture() |
767 | .thenValue([](auto &&) -> int { throw eggs; }) |
768 | .onError(onErrorHelperEggs) |
769 | .onError(onErrorHelperGeneric); |
770 | EXPECT_EQ(10, f.value()); |
771 | } |
772 | { |
773 | auto f = |
774 | makeFuture() |
775 | .thenValue([](auto &&) -> int { throw std::runtime_error("test" ); }) |
776 | .onError(onErrorHelperEggs) |
777 | .onError(onErrorHelperGeneric); |
778 | EXPECT_EQ(20, f.value()); |
779 | } |
780 | { |
781 | auto f = |
782 | makeFuture() |
783 | .thenValue([](auto &&) -> int { throw std::runtime_error("test" ); }) |
784 | .onError(onErrorHelperEggs); |
785 | EXPECT_THROW(f.value(), std::runtime_error); |
786 | } |
787 | |
788 | // No throw |
789 | { |
790 | auto f = makeFuture() |
791 | .thenValue([](auto&&) { return 42; }) |
792 | .onError([&](eggs_t& /* e */) { |
793 | flag(); |
794 | return -1; |
795 | }); |
796 | EXPECT_NO_FLAG(); |
797 | EXPECT_EQ(42, f.value()); |
798 | } |
799 | |
800 | { |
801 | auto f = makeFuture() |
802 | .thenValue([](auto&&) { return 42; }) |
803 | .onError([&](eggs_t& /* e */) { |
804 | flag(); |
805 | return makeFuture<int>(-1); |
806 | }); |
807 | EXPECT_NO_FLAG(); |
808 | EXPECT_EQ(42, f.value()); |
809 | } |
810 | |
811 | // Catch different exception |
812 | { |
813 | auto f = makeFuture() |
814 | .thenValue([](auto&&) { throw eggs; }) |
815 | .onError([&](std::runtime_error& /* e */) { flag(); }); |
816 | EXPECT_NO_FLAG(); |
817 | EXPECT_THROW(f.value(), eggs_t); |
818 | } |
819 | |
820 | { |
821 | auto f = makeFuture() |
822 | .thenValue([](auto&&) { throw eggs; }) |
823 | .onError([&](std::runtime_error& /* e */) { |
824 | flag(); |
825 | return makeFuture(); |
826 | }); |
827 | EXPECT_NO_FLAG(); |
828 | EXPECT_THROW(f.value(), eggs_t); |
829 | } |
830 | |
831 | // Returned value propagates |
832 | { |
833 | auto f = makeFuture() |
834 | .thenValue([](auto &&) -> int { throw eggs; }) |
835 | .onError([&](eggs_t& /* e */) { return 42; }); |
836 | EXPECT_EQ(42, f.value()); |
837 | } |
838 | |
839 | // Returned future propagates |
840 | { |
841 | auto f = makeFuture() |
842 | .thenValue([](auto &&) -> int { throw eggs; }) |
843 | .onError([&](eggs_t& /* e */) { return makeFuture<int>(42); }); |
844 | EXPECT_EQ(42, f.value()); |
845 | } |
846 | |
847 | // Throw in callback |
848 | { |
849 | auto f = makeFuture() |
850 | .thenValue([](auto &&) -> int { throw eggs; }) |
851 | .onError([&](eggs_t& e) -> int { throw e; }); |
852 | EXPECT_THROW(f.value(), eggs_t); |
853 | } |
854 | |
855 | { |
856 | auto f = makeFuture() |
857 | .thenValue([](auto &&) -> int { throw eggs; }) |
858 | .onError([&](eggs_t& e) -> Future<int> { throw e; }); |
859 | EXPECT_THROW(f.value(), eggs_t); |
860 | } |
861 | |
862 | // exception_wrapper, return Future<T> |
863 | { |
864 | auto f = makeFuture() |
865 | .thenValue([](auto&&) { throw eggs; }) |
866 | .onError([&](exception_wrapper /* e */) { |
867 | flag(); |
868 | return makeFuture(); |
869 | }); |
870 | EXPECT_FLAG(); |
871 | EXPECT_NO_THROW(f.value()); |
872 | } |
873 | |
874 | // exception_wrapper, return Future<T> but throw |
875 | { |
876 | auto f = makeFuture() |
877 | .thenValue([](auto &&) -> int { throw eggs; }) |
878 | .onError([&](exception_wrapper /* e */) -> Future<int> { |
879 | flag(); |
880 | throw eggs; |
881 | }); |
882 | EXPECT_FLAG(); |
883 | EXPECT_THROW(f.value(), eggs_t); |
884 | } |
885 | |
886 | // exception_wrapper, return T |
887 | { |
888 | auto f = makeFuture() |
889 | .thenValue([](auto &&) -> int { throw eggs; }) |
890 | .onError([&](exception_wrapper /* e */) { |
891 | flag(); |
892 | return -1; |
893 | }); |
894 | EXPECT_FLAG(); |
895 | EXPECT_EQ(-1, f.value()); |
896 | } |
897 | |
898 | // exception_wrapper, return T but throw |
899 | { |
900 | auto f = makeFuture() |
901 | .thenValue([](auto &&) -> int { throw eggs; }) |
902 | .onError([&](exception_wrapper /* e */) -> int { |
903 | flag(); |
904 | throw eggs; |
905 | }); |
906 | EXPECT_FLAG(); |
907 | EXPECT_THROW(f.value(), eggs_t); |
908 | } |
909 | |
910 | // const exception_wrapper& |
911 | { |
912 | auto f = makeFuture() |
913 | .thenValue([](auto&&) { throw eggs; }) |
914 | .onError([&](const exception_wrapper& /* e */) { |
915 | flag(); |
916 | return makeFuture(); |
917 | }); |
918 | EXPECT_FLAG(); |
919 | EXPECT_NO_THROW(f.value()); |
920 | } |
921 | #undef EXPECT_FLAG |
922 | #undef EXPECT_NO_FLAG |
923 | } |
924 | |
925 | TEST(Future, special) { |
926 | EXPECT_FALSE(std::is_copy_constructible<Future<int>>::value); |
927 | EXPECT_FALSE(std::is_copy_assignable<Future<int>>::value); |
928 | EXPECT_TRUE(std::is_move_constructible<Future<int>>::value); |
929 | EXPECT_TRUE(std::is_move_assignable<Future<int>>::value); |
930 | } |
931 | |
932 | TEST(Future, then) { |
933 | auto f = |
934 | makeFuture<std::string>("0" ) |
935 | .thenValue([](auto&&) { return makeFuture<std::string>("1" ); }) |
936 | .then( |
937 | [](Try<std::string>&& t) { return makeFuture(t.value() + ";2" ); }) |
938 | .then([](const Try<std::string>&& t) { |
939 | return makeFuture(t.value() + ";3" ); |
940 | }) |
941 | .then([](const Try<std::string>& t) { |
942 | return makeFuture(t.value() + ";4" ); |
943 | }) |
944 | .then([](Try<std::string> t) { return makeFuture(t.value() + ";5" ); }) |
945 | .then([](const Try<std::string> t) { |
946 | return makeFuture(t.value() + ";6" ); |
947 | }) |
948 | .thenValue([](std::string&& s) { return makeFuture(s + ";7" ); }) |
949 | .thenValue([](const std::string&& s) { return makeFuture(s + ";8" ); }) |
950 | .thenValue([](const std::string& s) { return makeFuture(s + ";9" ); }) |
951 | .thenValue([](std::string s) { return makeFuture(s + ";10" ); }) |
952 | .thenValue([](const std::string s) { return makeFuture(s + ";11" ); }); |
953 | EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11" ); |
954 | } |
955 | |
956 | static folly::Future<std::string> doWorkStaticTry(Try<std::string>&& t) { |
957 | return makeFuture(t.value() + ";7" ); |
958 | } |
959 | |
960 | TEST(Future, thenTrythenValue) { |
961 | auto f = |
962 | makeFuture() |
963 | .thenTry([](auto&&) { return makeFuture<std::string>("1" ); }) |
964 | .thenTry( |
965 | [](Try<std::string>&& t) { return makeFuture(t.value() + ";2" ); }) |
966 | .thenTry([](const Try<std::string>&& t) { |
967 | return makeFuture(t.value() + ";3" ); |
968 | }) |
969 | .thenTry([](const Try<std::string>& t) { |
970 | return makeFuture(t.value() + ";4" ); |
971 | }) |
972 | .thenTry( |
973 | [](Try<std::string> t) { return makeFuture(t.value() + ";5" ); }) |
974 | .thenTry([](const Try<std::string> t) { |
975 | return makeFuture(t.value() + ";6" ); |
976 | }) |
977 | .thenTry(doWorkStaticTry) |
978 | .thenValue([](std::string&& s) { return makeFuture(s + ";8" ); }) |
979 | .thenValue([](const std::string&& s) { return makeFuture(s + ";9" ); }) |
980 | .thenValue([](const std::string& s) { return makeFuture(s + ";10" ); }) |
981 | .thenValue([](std::string s) { return makeFuture(s + ";11" ); }) |
982 | .thenValue([](const std::string s) { return makeFuture(s + ";12" ); }); |
983 | EXPECT_EQ(f.value(), "1;2;3;4;5;6;7;8;9;10;11;12" ); |
984 | } |
985 | |
986 | TEST(Future, thenTry) { |
987 | bool flag = false; |
988 | |
989 | makeFuture<int>(42).then([&](Try<int>&& t) { |
990 | flag = true; |
991 | EXPECT_EQ(42, t.value()); |
992 | }); |
993 | EXPECT_TRUE(flag); |
994 | flag = false; |
995 | |
996 | makeFuture<int>(42) |
997 | .then([](Try<int>&& t) { return t.value(); }) |
998 | .then([&](Try<int>&& t) { |
999 | flag = true; |
1000 | EXPECT_EQ(42, t.value()); |
1001 | }); |
1002 | EXPECT_TRUE(flag); |
1003 | flag = false; |
1004 | |
1005 | makeFuture().then([&](Try<Unit>&& t) { |
1006 | flag = true; |
1007 | t.value(); |
1008 | }); |
1009 | EXPECT_TRUE(flag); |
1010 | flag = false; |
1011 | |
1012 | Promise<Unit> p; |
1013 | auto f = p.getFuture().then([&](Try<Unit>&& /* t */) { flag = true; }); |
1014 | EXPECT_FALSE(flag); |
1015 | EXPECT_FALSE(f.isReady()); |
1016 | p.setValue(); |
1017 | EXPECT_TRUE(flag); |
1018 | EXPECT_TRUE(f.isReady()); |
1019 | } |
1020 | |
1021 | TEST(Future, thenValue) { |
1022 | bool flag = false; |
1023 | makeFuture<int>(42).thenValue([&](int i) { |
1024 | EXPECT_EQ(42, i); |
1025 | flag = true; |
1026 | }); |
1027 | EXPECT_TRUE(flag); |
1028 | flag = false; |
1029 | |
1030 | makeFuture<int>(42).thenValue([](int i) { return i; }).thenValue([&](int i) { |
1031 | flag = true; |
1032 | EXPECT_EQ(42, i); |
1033 | }); |
1034 | EXPECT_TRUE(flag); |
1035 | flag = false; |
1036 | |
1037 | makeFuture().thenValue([&](auto&&) { flag = true; }); |
1038 | EXPECT_TRUE(flag); |
1039 | flag = false; |
1040 | |
1041 | auto f = makeFuture<int>(eggs).thenValue([&](int /* i */) {}); |
1042 | EXPECT_THROW(f.value(), eggs_t); |
1043 | |
1044 | f = makeFuture<Unit>(eggs).thenValue([&](auto&&) {}); |
1045 | EXPECT_THROW(f.value(), eggs_t); |
1046 | } |
1047 | |
1048 | TEST(Future, thenValueFuture) { |
1049 | bool flag = false; |
1050 | makeFuture<int>(42) |
1051 | .thenValue([](int i) { return makeFuture<int>(std::move(i)); }) |
1052 | .then([&](Try<int>&& t) { |
1053 | flag = true; |
1054 | EXPECT_EQ(42, t.value()); |
1055 | }); |
1056 | EXPECT_TRUE(flag); |
1057 | flag = false; |
1058 | |
1059 | makeFuture() |
1060 | .thenValue([](auto&&) { return makeFuture(); }) |
1061 | .then([&](Try<Unit>&& /* t */) { flag = true; }); |
1062 | EXPECT_TRUE(flag); |
1063 | flag = false; |
1064 | } |
1065 | |
1066 | static std::string doWorkStatic(Try<std::string>&& t) { |
1067 | return t.value() + ";static" ; |
1068 | } |
1069 | |
1070 | static std::string doWorkStaticValue(std::string&& t) { |
1071 | return t + ";value" ; |
1072 | } |
1073 | |
1074 | TEST(Future, thenFunction) { |
1075 | struct Worker { |
1076 | std::string doWork(Try<std::string>&& t) { |
1077 | return t.value() + ";class" ; |
1078 | } |
1079 | static std::string doWorkStatic(Try<std::string>&& t) { |
1080 | return t.value() + ";class-static" ; |
1081 | } |
1082 | } w; |
1083 | |
1084 | auto f = makeFuture<std::string>("start" ) |
1085 | .then(doWorkStatic) |
1086 | .then(Worker::doWorkStatic) |
1087 | .then(&Worker::doWork, &w) |
1088 | .thenValue(doWorkStaticValue); |
1089 | |
1090 | EXPECT_EQ(f.value(), "start;static;class-static;class;value" ); |
1091 | } |
1092 | |
1093 | static Future<std::string> doWorkStaticFuture(Try<std::string>&& t) { |
1094 | return makeFuture(t.value() + ";static" ); |
1095 | } |
1096 | |
1097 | TEST(Future, thenFunctionFuture) { |
1098 | struct Worker { |
1099 | Future<std::string> doWorkFuture(Try<std::string>&& t) { |
1100 | return makeFuture(t.value() + ";class" ); |
1101 | } |
1102 | static Future<std::string> doWorkStaticFuture(Try<std::string>&& t) { |
1103 | return makeFuture(t.value() + ";class-static" ); |
1104 | } |
1105 | } w; |
1106 | |
1107 | auto f = makeFuture<std::string>("start" ) |
1108 | .then(doWorkStaticFuture) |
1109 | .then(Worker::doWorkStaticFuture) |
1110 | .then(&Worker::doWorkFuture, &w); |
1111 | |
1112 | EXPECT_EQ(f.value(), "start;static;class-static;class" ); |
1113 | } |
1114 | |
1115 | TEST(Future, thenStdFunction) { |
1116 | { |
1117 | std::function<int(folly::Unit)> fn = [](folly::Unit) { return 42; }; |
1118 | auto f = makeFuture().thenValue(std::move(fn)); |
1119 | EXPECT_EQ(f.value(), 42); |
1120 | } |
1121 | { |
1122 | std::function<int(int)> fn = [](int i) { return i + 23; }; |
1123 | auto f = makeFuture(19).thenValue(std::move(fn)); |
1124 | EXPECT_EQ(f.value(), 42); |
1125 | } |
1126 | { |
1127 | std::function<int(Try<int>)> fn = [](Try<int> t) { return t.value() + 2; }; |
1128 | auto f = makeFuture(1).then(std::move(fn)); |
1129 | EXPECT_EQ(f.value(), 3); |
1130 | } |
1131 | { |
1132 | bool flag = false; |
1133 | std::function<void(folly::Unit)> fn = [&flag](folly::Unit) { flag = true; }; |
1134 | auto f = makeFuture().thenValue(std::move(fn)); |
1135 | EXPECT_TRUE(f.isReady()); |
1136 | EXPECT_TRUE(flag); |
1137 | } |
1138 | } |
1139 | |
1140 | TEST(Future, thenBind) { |
1141 | auto l = [](folly::Unit) { return makeFuture("bind" ); }; |
1142 | auto b = std::bind(l, std::placeholders::_1); |
1143 | auto f = makeFuture().thenValue(std::move(b)); |
1144 | EXPECT_EQ(f.value(), "bind" ); |
1145 | } |
1146 | |
1147 | TEST(Future, thenBindTry) { |
1148 | auto l = [](Try<std::string>&& t) { return makeFuture(t.value() + ";bind" ); }; |
1149 | auto b = std::bind(l, std::placeholders::_1); |
1150 | auto f = makeFuture<std::string>("start" ).then(std::move(b)); |
1151 | |
1152 | EXPECT_EQ(f.value(), "start;bind" ); |
1153 | } |
1154 | |
1155 | TEST(Future, value) { |
1156 | auto f = makeFuture(std::make_unique<int>(42)); |
1157 | auto up = std::move(f.value()); |
1158 | EXPECT_EQ(42, *up); |
1159 | |
1160 | EXPECT_THROW(makeFuture<int>(eggs).value(), eggs_t); |
1161 | } |
1162 | |
1163 | TEST(Future, isReady) { |
1164 | Promise<int> p; |
1165 | auto f = p.getFuture(); |
1166 | EXPECT_FALSE(f.isReady()); |
1167 | p.setValue(42); |
1168 | EXPECT_TRUE(f.isReady()); |
1169 | } |
1170 | |
1171 | TEST(Future, futureNotReady) { |
1172 | Promise<int> p; |
1173 | Future<int> f = p.getFuture(); |
1174 | EXPECT_THROW(f.value(), eggs_t); |
1175 | } |
1176 | |
1177 | TEST(Future, hasException) { |
1178 | EXPECT_TRUE(makeFuture<int>(eggs).getTry().hasException()); |
1179 | EXPECT_FALSE(makeFuture(42).getTry().hasException()); |
1180 | } |
1181 | |
1182 | TEST(Future, hasValue) { |
1183 | EXPECT_TRUE(makeFuture(42).getTry().hasValue()); |
1184 | EXPECT_FALSE(makeFuture<int>(eggs).getTry().hasValue()); |
1185 | } |
1186 | |
1187 | TEST(Future, makeFuture) { |
1188 | EXPECT_TYPE(makeFuture(42), Future<int>); |
1189 | EXPECT_EQ(42, makeFuture(42).value()); |
1190 | |
1191 | EXPECT_TYPE(makeFuture<float>(42), Future<float>); |
1192 | EXPECT_EQ(42, makeFuture<float>(42).value()); |
1193 | |
1194 | auto fun = [] { return 42; }; |
1195 | EXPECT_TYPE(makeFutureWith(fun), Future<int>); |
1196 | EXPECT_EQ(42, makeFutureWith(fun).value()); |
1197 | |
1198 | auto funf = [] { return makeFuture<int>(43); }; |
1199 | EXPECT_TYPE(makeFutureWith(funf), Future<int>); |
1200 | EXPECT_EQ(43, makeFutureWith(funf).value()); |
1201 | |
1202 | auto failfun = []() -> int { throw eggs; }; |
1203 | EXPECT_TYPE(makeFutureWith(failfun), Future<int>); |
1204 | EXPECT_NO_THROW(makeFutureWith(failfun)); |
1205 | EXPECT_THROW(makeFutureWith(failfun).value(), eggs_t); |
1206 | |
1207 | auto failfunf = []() -> Future<int> { throw eggs; }; |
1208 | EXPECT_TYPE(makeFutureWith(failfunf), Future<int>); |
1209 | EXPECT_NO_THROW(makeFutureWith(failfunf)); |
1210 | EXPECT_THROW(makeFutureWith(failfunf).value(), eggs_t); |
1211 | |
1212 | EXPECT_TYPE(makeFuture(), Future<Unit>); |
1213 | } |
1214 | |
1215 | TEST(Future, finish) { |
1216 | auto x = std::make_shared<int>(0); |
1217 | |
1218 | Promise<int> p; |
1219 | auto f = p.getFuture().then([x](Try<int>&& t) { *x = t.value(); }); |
1220 | |
1221 | // The callback hasn't executed |
1222 | EXPECT_EQ(0, *x); |
1223 | |
1224 | // The callback has a reference to x |
1225 | EXPECT_EQ(2, x.use_count()); |
1226 | |
1227 | p.setValue(42); |
1228 | |
1229 | // the callback has executed |
1230 | EXPECT_EQ(42, *x); |
1231 | |
1232 | // the callback has been destructed |
1233 | // and has released its reference to x |
1234 | EXPECT_EQ(1, x.use_count()); |
1235 | } |
1236 | |
1237 | TEST(Future, finishBigLambda) { |
1238 | auto x = std::make_shared<int>(0); |
1239 | |
1240 | // bulk_data, to be captured in the lambda passed to Future::then. |
1241 | // This is meant to force that the lambda can't be stored inside |
1242 | // the Future object. |
1243 | std::array<char, sizeof(futures::detail::Core<int>)> bulk_data = {{0}}; |
1244 | |
1245 | // suppress gcc warning about bulk_data not being used |
1246 | EXPECT_EQ(bulk_data[0], 0); |
1247 | |
1248 | Promise<int> p; |
1249 | auto f = p.getFuture().then([x, bulk_data](Try<int>&& t) { |
1250 | (void)bulk_data; |
1251 | *x = t.value(); |
1252 | }); |
1253 | |
1254 | // The callback hasn't executed |
1255 | EXPECT_EQ(0, *x); |
1256 | |
1257 | // The callback has a reference to x |
1258 | EXPECT_EQ(2, x.use_count()); |
1259 | |
1260 | p.setValue(42); |
1261 | |
1262 | // the callback has executed |
1263 | EXPECT_EQ(42, *x); |
1264 | |
1265 | // the callback has been destructed |
1266 | // and has released its reference to x |
1267 | EXPECT_EQ(1, x.use_count()); |
1268 | } |
1269 | |
1270 | TEST(Future, unwrap) { |
1271 | Promise<int> a; |
1272 | Promise<int> b; |
1273 | |
1274 | auto fa = a.getFuture(); |
1275 | auto fb = b.getFuture(); |
1276 | |
1277 | bool flag1 = false; |
1278 | bool flag2 = false; |
1279 | |
1280 | // do a, then do b, and get the result of a + b. |
1281 | Future<int> f = std::move(fa).then([&](Try<int>&& ta) { |
1282 | auto va = ta.value(); |
1283 | flag1 = true; |
1284 | return std::move(fb).then([va, &flag2](Try<int>&& tb) { |
1285 | flag2 = true; |
1286 | return va + tb.value(); |
1287 | }); |
1288 | }); |
1289 | |
1290 | EXPECT_FALSE(flag1); |
1291 | EXPECT_FALSE(flag2); |
1292 | EXPECT_FALSE(f.isReady()); |
1293 | |
1294 | a.setValue(3); |
1295 | EXPECT_TRUE(flag1); |
1296 | EXPECT_FALSE(flag2); |
1297 | EXPECT_FALSE(f.isReady()); |
1298 | |
1299 | b.setValue(4); |
1300 | EXPECT_TRUE(flag1); |
1301 | EXPECT_TRUE(flag2); |
1302 | EXPECT_EQ(7, f.value()); |
1303 | } |
1304 | |
1305 | TEST(Future, throwCaughtInImmediateThen) { |
1306 | // Neither of these should throw "Promise already satisfied" |
1307 | makeFuture().then([=](Try<Unit> &&) -> int { throw std::exception(); }); |
1308 | makeFuture().then( |
1309 | [=](Try<Unit> &&) -> Future<int> { throw std::exception(); }); |
1310 | } |
1311 | |
1312 | TEST(Future, throwIfFailed) { |
1313 | makeFuture<Unit>(eggs).then( |
1314 | [=](Try<Unit>&& t) { EXPECT_THROW(t.throwIfFailed(), eggs_t); }); |
1315 | makeFuture().then([=](Try<Unit>&& t) { EXPECT_NO_THROW(t.throwIfFailed()); }); |
1316 | |
1317 | makeFuture<int>(eggs).then( |
1318 | [=](Try<int>&& t) { EXPECT_THROW(t.throwIfFailed(), eggs_t); }); |
1319 | makeFuture<int>(42).then( |
1320 | [=](Try<int>&& t) { EXPECT_NO_THROW(t.throwIfFailed()); }); |
1321 | } |
1322 | |
1323 | TEST(Future, getFutureAfterSetValue) { |
1324 | Promise<int> p; |
1325 | p.setValue(42); |
1326 | EXPECT_EQ(42, p.getFuture().value()); |
1327 | } |
1328 | |
1329 | TEST(Future, getFutureAfterSetException) { |
1330 | Promise<Unit> p; |
1331 | p.setWith([]() -> void { throw std::logic_error("foo" ); }); |
1332 | EXPECT_THROW(p.getFuture().value(), std::logic_error); |
1333 | } |
1334 | |
1335 | TEST(Future, detachRace) { |
1336 | // Task #5438209 |
1337 | // This test is designed to detect a race that was in Core::detachOne() |
1338 | // where detached_ was incremented and then tested, and that |
1339 | // allowed a race where both Promise and Future would think they were the |
1340 | // second and both try to delete. This showed up at scale but was very |
1341 | // difficult to reliably repro in a test. As it is, this only fails about |
1342 | // once in every 1,000 executions. Doing this 1,000 times is going to make a |
1343 | // slow test so I won't do that but if it ever fails, take it seriously, and |
1344 | // run the test binary with "--gtest_repeat=10000 --gtest_filter=*detachRace" |
1345 | // (Don't forget to enable ASAN) |
1346 | auto p = std::make_unique<Promise<bool>>(); |
1347 | auto f = std::make_unique<Future<bool>>(p->getFuture()); |
1348 | folly::Baton<> baton; |
1349 | std::thread t1([&] { |
1350 | baton.post(); |
1351 | p.reset(); |
1352 | }); |
1353 | baton.wait(); |
1354 | f.reset(); |
1355 | t1.join(); |
1356 | } |
1357 | |
1358 | // Test of handling of a circular dependency. It's never recommended |
1359 | // to have one because of possible memory leaks. Here we test that |
1360 | // we can handle freeing of the Future while it is running. |
1361 | TEST(Future, CircularDependencySharedPtrSelfReset) { |
1362 | Promise<int64_t> promise; |
1363 | auto ptr = std::make_shared<Future<int64_t>>(promise.getFuture()); |
1364 | |
1365 | std::move(*ptr).thenTry([ptr](folly::Try<int64_t>&& /* uid */) mutable { |
1366 | EXPECT_EQ(1, ptr.use_count()); |
1367 | |
1368 | // Leaving no references to ourselves. |
1369 | ptr.reset(); |
1370 | EXPECT_EQ(0, ptr.use_count()); |
1371 | }); |
1372 | |
1373 | EXPECT_EQ(2, ptr.use_count()); |
1374 | |
1375 | ptr.reset(); |
1376 | |
1377 | promise.setValue(1); |
1378 | } |
1379 | |
1380 | TEST(Future, Constructor) { |
1381 | auto f1 = []() -> Future<int> { return Future<int>(3); }(); |
1382 | EXPECT_EQ(f1.value(), 3); |
1383 | auto f2 = []() -> Future<Unit> { return Future<Unit>(); }(); |
1384 | EXPECT_NO_THROW(f2.value()); |
1385 | } |
1386 | |
1387 | TEST(Future, ImplicitConstructor) { |
1388 | auto f1 = []() -> Future<int> { return 3; }(); |
1389 | EXPECT_EQ(f1.value(), 3); |
1390 | // Unfortunately, the C++ standard does not allow the |
1391 | // following implicit conversion to work: |
1392 | // auto f2 = []() -> Future<Unit> { }(); |
1393 | } |
1394 | |
1395 | TEST(Future, InPlaceConstructor) { |
1396 | auto f = Future<std::pair<int, double>>(in_place, 5, 3.2); |
1397 | EXPECT_EQ(5, f.value().first); |
1398 | } |
1399 | |
1400 | TEST(Future, thenDynamic) { |
1401 | // folly::dynamic has a constructor that takes any T, this test makes |
1402 | // sure that we call the then lambda with folly::dynamic and not |
1403 | // Try<folly::dynamic> because that then fails to compile |
1404 | Promise<folly::dynamic> p; |
1405 | Future<folly::dynamic> f = p.getFuture().thenValue( |
1406 | [](const folly::dynamic& d) { return folly::dynamic(d.asInt() + 3); }); |
1407 | p.setValue(2); |
1408 | EXPECT_EQ(std::move(f).get(), 5); |
1409 | } |
1410 | |
1411 | TEST(Future, RequestContext) { |
1412 | class NewThreadExecutor : public Executor { |
1413 | public: |
1414 | ~NewThreadExecutor() override { |
1415 | std::for_each(v_.begin(), v_.end(), [](std::thread& t) { t.join(); }); |
1416 | } |
1417 | void add(Func f) override { |
1418 | if (throwsOnAdd_) { |
1419 | throw std::exception(); |
1420 | } |
1421 | v_.emplace_back(std::move(f)); |
1422 | } |
1423 | void addWithPriority(Func f, int8_t /* prio */) override { |
1424 | add(std::move(f)); |
1425 | } |
1426 | uint8_t getNumPriorities() const override { |
1427 | return numPriorities_; |
1428 | } |
1429 | |
1430 | void setHandlesPriorities() { |
1431 | numPriorities_ = 2; |
1432 | } |
1433 | void setThrowsOnAdd() { |
1434 | throwsOnAdd_ = true; |
1435 | } |
1436 | |
1437 | private: |
1438 | std::vector<std::thread> v_; |
1439 | uint8_t numPriorities_ = 1; |
1440 | bool throwsOnAdd_ = false; |
1441 | }; |
1442 | |
1443 | struct MyRequestData : RequestData { |
1444 | MyRequestData(bool value_ = false) : value(value_) {} |
1445 | |
1446 | bool hasCallback() override { |
1447 | return false; |
1448 | } |
1449 | |
1450 | bool value; |
1451 | }; |
1452 | |
1453 | Promise<int> p1, p2; |
1454 | NewThreadExecutor e; |
1455 | { |
1456 | folly::RequestContextScopeGuard rctx; |
1457 | RequestContext::get()->setContextData( |
1458 | "key" , std::make_unique<MyRequestData>(true)); |
1459 | auto checker = [](int lineno) { |
1460 | return [lineno](Try<int>&& /* t */) { |
1461 | auto d = static_cast<MyRequestData*>( |
1462 | RequestContext::get()->getContextData("key" )); |
1463 | EXPECT_TRUE(d && d->value) << "on line " << lineno; |
1464 | }; |
1465 | }; |
1466 | |
1467 | makeFuture(1).via(&e).then(checker(__LINE__)); |
1468 | |
1469 | e.setHandlesPriorities(); |
1470 | makeFuture(2).via(&e).then(checker(__LINE__)); |
1471 | |
1472 | p1.getFuture().then(checker(__LINE__)); |
1473 | |
1474 | e.setThrowsOnAdd(); |
1475 | p2.getFuture().via(&e).then(checker(__LINE__)); |
1476 | } |
1477 | // Assert that no RequestContext is set |
1478 | EXPECT_FALSE(RequestContext::saveContext()); |
1479 | p1.setValue(3); |
1480 | p2.setValue(4); |
1481 | } |
1482 | |
1483 | TEST(Future, makeFutureNoThrow) { |
1484 | makeFuture().value(); |
1485 | } |
1486 | |
1487 | TEST(Future, invokeCallbackReturningValueAsRvalue) { |
1488 | struct Foo { |
1489 | int operator()(int x) & { |
1490 | return x + 1; |
1491 | } |
1492 | int operator()(int x) const& { |
1493 | return x + 2; |
1494 | } |
1495 | int operator()(int x) && { |
1496 | return x + 3; |
1497 | } |
1498 | }; |
1499 | |
1500 | Foo foo; |
1501 | Foo const cfoo; |
1502 | |
1503 | // The continuation will be forward-constructed - copied if given as & and |
1504 | // moved if given as && - everywhere construction is required. |
1505 | // The continuation will be invoked with the same cvref as it is passed. |
1506 | EXPECT_EQ(101, makeFuture<int>(100).thenValue(foo).value()); |
1507 | EXPECT_EQ(202, makeFuture<int>(200).thenValue(cfoo).value()); |
1508 | EXPECT_EQ(303, makeFuture<int>(300).thenValue(Foo()).value()); |
1509 | } |
1510 | |
1511 | TEST(Future, invokeCallbackReturningFutureAsRvalue) { |
1512 | struct Foo { |
1513 | Future<int> operator()(int x) & { |
1514 | return x + 1; |
1515 | } |
1516 | Future<int> operator()(int x) const& { |
1517 | return x + 2; |
1518 | } |
1519 | Future<int> operator()(int x) && { |
1520 | return x + 3; |
1521 | } |
1522 | }; |
1523 | |
1524 | Foo foo; |
1525 | Foo const cfoo; |
1526 | |
1527 | // The continuation will be forward-constructed - copied if given as & and |
1528 | // moved if given as && - everywhere construction is required. |
1529 | // The continuation will be invoked with the same cvref as it is passed. |
1530 | EXPECT_EQ(101, makeFuture<int>(100).thenValue(foo).value()); |
1531 | EXPECT_EQ(202, makeFuture<int>(200).thenValue(cfoo).value()); |
1532 | EXPECT_EQ(303, makeFuture<int>(300).thenValue(Foo()).value()); |
1533 | } |
1534 | |
1535 | TEST(Future, futureWithinCtxCleanedUpWhenTaskFinishedInTime) { |
1536 | // Used to track the use_count of callbackInput even outside of its scope |
1537 | std::weak_ptr<int> target; |
1538 | { |
1539 | Promise<std::shared_ptr<int>> promise; |
1540 | auto input = std::make_shared<int>(1); |
1541 | auto longEnough = std::chrono::milliseconds(1000); |
1542 | |
1543 | promise.getFuture() |
1544 | .within(longEnough) |
1545 | .then([&target]( |
1546 | folly::Try<std::shared_ptr<int>>&& callbackInput) mutable { |
1547 | target = callbackInput.value(); |
1548 | }); |
1549 | promise.setValue(input); |
1550 | } |
1551 | // After promise's life cycle is finished, make sure no one is holding the |
1552 | // input anymore, in other words, ctx should have been cleaned up. |
1553 | EXPECT_EQ(0, target.use_count()); |
1554 | } |
1555 | |
1556 | TEST(Future, futureWithinNoValueReferenceWhenTimeOut) { |
1557 | Promise<std::shared_ptr<int>> promise; |
1558 | auto veryShort = std::chrono::milliseconds(1); |
1559 | |
1560 | promise.getFuture().within(veryShort).then( |
1561 | [](folly::Try<std::shared_ptr<int>>&& callbackInput) { |
1562 | // Timeout is fired. Verify callbackInput is not referenced |
1563 | EXPECT_EQ(0, callbackInput.value().use_count()); |
1564 | }); |
1565 | } |
1566 | |
1567 | TEST(Future, makePromiseContract) { |
1568 | class ManualExecutor : public Executor { |
1569 | private: |
1570 | std::queue<Func> queue_; |
1571 | |
1572 | public: |
1573 | void add(Func f) override { |
1574 | queue_.push(std::move(f)); |
1575 | } |
1576 | void drain() { |
1577 | while (!queue_.empty()) { |
1578 | auto f = std::move(queue_.front()); |
1579 | queue_.pop(); |
1580 | f(); |
1581 | } |
1582 | } |
1583 | }; |
1584 | |
1585 | ManualExecutor e; |
1586 | auto c = makePromiseContract<int>(&e); |
1587 | c.second = std::move(c.second).thenValue([](int _) { return _ + 1; }); |
1588 | EXPECT_FALSE(c.second.isReady()); |
1589 | c.first.setValue(3); |
1590 | EXPECT_FALSE(c.second.isReady()); |
1591 | e.drain(); |
1592 | ASSERT_TRUE(c.second.isReady()); |
1593 | EXPECT_EQ(4, std::move(c.second).get()); |
1594 | } |
1595 | |
1596 | Future<bool> call(int depth, Executor* executor) { |
1597 | return makeFuture().then(executor, [=] { return depth == 0; }); |
1598 | } |
1599 | |
1600 | Future<int> recursion(Executor* executor, int depth) { |
1601 | return makeFuture().thenValue([=](auto) { |
1602 | return call(depth, executor).thenValue([=](auto result) { |
1603 | if (result) { |
1604 | return folly::makeFuture(42); |
1605 | } |
1606 | |
1607 | return recursion(executor, depth - 1); |
1608 | }); |
1609 | }); |
1610 | } |
1611 | |
1612 | TEST(Future, ThenRecursion) { |
1613 | ManualExecutor executor; |
1614 | |
1615 | EXPECT_EQ(42, recursion(&executor, 100000).getVia(&executor)); |
1616 | } |
1617 | |