1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <functional>
6 #include <memory>
7 
8 #include <lib/fit/defer.h>
9 #include <lib/fit/function.h>
10 #include <lib/fit/nullable.h>
11 #include <unittest/unittest.h>
12 
13 #include "unittest_utils.h"
14 
15 namespace {
16 
17 // Counts instances.
18 class balance {
19 public:
balance(int * counter)20     balance(int* counter)
21         : counter_(counter) {
22         *counter_ += 1;
23     }
24 
balance(balance && other)25     balance(balance&& other)
26         : counter_(other.counter_) {
27         *counter_ += 1;
28     }
29 
~balance()30     ~balance() {
31         *counter_ -= 1;
32     }
33 
34     balance(const balance& other) = delete;
35     balance& operator=(const balance& other) = delete;
36     balance& operator=(balance&& other) = delete;
37 
38 private:
39     int* const counter_;
40 };
41 
incr_arg(int * p)42 void incr_arg(int* p) {
43     *p += 1;
44 }
45 
46 template <typename T>
default_construction()47 bool default_construction() {
48     BEGIN_TEST;
49 
50     fit::deferred_action<T> d;
51     EXPECT_FALSE(d);
52 
53     END_TEST;
54 }
55 
56 template <typename T>
null_construction()57 bool null_construction() {
58     BEGIN_TEST;
59 
60     fit::deferred_action<T> d(nullptr);
61     EXPECT_FALSE(d);
62 
63     END_TEST;
64 }
65 
66 template <typename T>
basic()67 bool basic() {
68     static_assert(fit::is_nullable<fit::deferred_action<T>>::value, "");
69 
70     BEGIN_TEST;
71 
72     int var = 0;
73     {
74         auto do_incr = fit::defer<T>([&var]() { incr_arg(&var); });
75         EXPECT_TRUE(do_incr);
76         EXPECT_EQ(var, 0);
77         EXPECT_FALSE(do_incr == nullptr);
78         EXPECT_FALSE(nullptr == do_incr);
79         EXPECT_TRUE(do_incr != nullptr);
80         EXPECT_TRUE(nullptr != do_incr);
81     }
82     EXPECT_EQ(var, 1);
83 
84     END_TEST;
85 }
86 
87 template <typename T>
cancel()88 bool cancel() {
89     BEGIN_TEST;
90 
91     int var = 0;
92     {
93         auto do_incr = fit::defer<T>([&var]() { incr_arg(&var); });
94         EXPECT_TRUE(do_incr);
95         EXPECT_EQ(var, 0);
96 
97         do_incr.cancel();
98         EXPECT_FALSE(do_incr);
99         EXPECT_EQ(var, 0);
100         EXPECT_TRUE(do_incr == nullptr);
101         EXPECT_TRUE(nullptr == do_incr);
102         EXPECT_FALSE(do_incr != nullptr);
103         EXPECT_FALSE(nullptr != do_incr);
104 
105         // Once cancelled, call has no effect.
106         do_incr.call();
107         EXPECT_FALSE(do_incr);
108         EXPECT_EQ(var, 0);
109     }
110     EXPECT_EQ(var, 0);
111 
112     END_TEST;
113 }
114 
115 template <typename T>
null_assignment()116 bool null_assignment() {
117     BEGIN_TEST;
118 
119     int var = 0;
120     {
121         auto do_incr = fit::defer<T>([&var]() { incr_arg(&var); });
122         EXPECT_TRUE(do_incr);
123         EXPECT_EQ(var, 0);
124 
125         do_incr = nullptr;
126         EXPECT_FALSE(do_incr);
127         EXPECT_EQ(var, 0);
128 
129         // Once cancelled, call has no effect.
130         do_incr.call();
131         EXPECT_FALSE(do_incr);
132         EXPECT_EQ(var, 0);
133     }
134     EXPECT_EQ(var, 0);
135 
136     END_TEST;
137 }
138 
139 template <typename T>
target_reassignment()140 bool target_reassignment() {
141     BEGIN_TEST;
142 
143     int var = 0;
144     {
145         fit::deferred_action<T> do_incr;
146         do_incr = []() { ASSERT_CRITICAL(false); };
147         EXPECT_TRUE(do_incr);
148         EXPECT_EQ(var, 0);
149 
150         do_incr = [&var]() { incr_arg(&var); };
151         EXPECT_TRUE(do_incr);
152         EXPECT_EQ(var, 0);
153     }
154     EXPECT_EQ(var, 1);
155 
156     END_TEST;
157 }
158 
159 template <typename T>
call()160 bool call() {
161     BEGIN_TEST;
162 
163     int var = 0;
164     {
165         auto do_incr = fit::defer<T>([&var]() { incr_arg(&var); });
166         EXPECT_TRUE(do_incr);
167         EXPECT_EQ(var, 0);
168 
169         do_incr.call();
170         EXPECT_FALSE(do_incr);
171         EXPECT_EQ(var, 1);
172 
173         // Call is effective only once.
174         do_incr.call();
175         EXPECT_FALSE(do_incr);
176         EXPECT_EQ(var, 1);
177     }
178     EXPECT_EQ(var, 1);
179 
180     END_TEST;
181 }
182 
183 template <typename T>
recursive_call()184 bool recursive_call() {
185     BEGIN_TEST;
186 
187     int var = 0;
188     {
189         auto do_incr = fit::defer<T>([]() { /* no-op */ });
190         EXPECT_TRUE(do_incr);
191         do_incr = fit::defer<T>([&do_incr, &var]() {
192             incr_arg(&var);
193             do_incr.call();
194             EXPECT_FALSE(do_incr);
195         });
196         EXPECT_TRUE(do_incr);
197         EXPECT_EQ(var, 0);
198 
199         do_incr.call();
200         EXPECT_FALSE(do_incr);
201         EXPECT_EQ(var, 1);
202     }
203     EXPECT_EQ(var, 1);
204 
205     END_TEST;
206 }
207 
208 template <typename T>
move_construct_basic()209 bool move_construct_basic() {
210     BEGIN_TEST;
211 
212     int var = 0;
213     {
214         auto do_incr = fit::defer<T>([&var]() { incr_arg(&var); });
215         EXPECT_TRUE(do_incr);
216 
217         auto do_incr2(std::move(do_incr));
218         EXPECT_FALSE(do_incr);
219         EXPECT_TRUE(do_incr2);
220         EXPECT_EQ(var, 0);
221     }
222     EXPECT_EQ(var, 1);
223 
224     END_TEST;
225 }
226 
227 template <typename T>
move_construct_from_canceled()228 bool move_construct_from_canceled() {
229     BEGIN_TEST;
230 
231     int var = 0;
232     {
233         auto do_incr = fit::defer<T>([&var]() { incr_arg(&var); });
234         EXPECT_TRUE(do_incr);
235 
236         do_incr.cancel();
237         EXPECT_FALSE(do_incr);
238 
239         auto do_incr2(std::move(do_incr));
240         EXPECT_FALSE(do_incr);
241         EXPECT_FALSE(do_incr2);
242         EXPECT_EQ(var, 0);
243     }
244     EXPECT_EQ(var, 0);
245 
246     END_TEST;
247 }
248 
249 template <typename T>
move_construct_from_called()250 bool move_construct_from_called() {
251     BEGIN_TEST;
252 
253     int var = 0;
254     {
255         auto do_incr = fit::defer<T>([&var]() { incr_arg(&var); });
256         EXPECT_TRUE(do_incr);
257         EXPECT_EQ(var, 0);
258 
259         do_incr.call();
260         EXPECT_FALSE(do_incr);
261         EXPECT_EQ(var, 1);
262 
263         // Must not be called again, since do_incr has triggered already.
264         auto do_incr2(std::move(do_incr));
265         EXPECT_FALSE(do_incr);
266     }
267     EXPECT_EQ(var, 1);
268 
269     END_TEST;
270 }
271 
272 template <typename T>
move_assign_basic()273 bool move_assign_basic() {
274     BEGIN_TEST;
275 
276     int var1 = 0, var2 = 0;
277     {
278         auto do_incr = fit::defer<T>([&var1]() { incr_arg(&var1); });
279         auto do_incr2 = fit::defer<T>([&var2]() { incr_arg(&var2); });
280         EXPECT_TRUE(do_incr);
281         EXPECT_TRUE(do_incr2);
282         EXPECT_EQ(var1, 0);
283         EXPECT_EQ(var2, 0);
284 
285         // do_incr2 is moved-to, so its associated function is called.
286         do_incr2 = std::move(do_incr);
287         EXPECT_FALSE(do_incr);
288         EXPECT_TRUE(do_incr2);
289         EXPECT_EQ(var1, 0);
290         EXPECT_EQ(var2, 1);
291 
292         // self-assignment does nothing
293         do_incr = std::move(do_incr);
294         do_incr2 = std::move(do_incr2);
295         EXPECT_TRUE(do_incr2);
296         EXPECT_EQ(var1, 0);
297         EXPECT_EQ(var2, 1);
298     }
299     EXPECT_EQ(var1, 1);
300     EXPECT_EQ(var2, 1);
301 
302     END_TEST;
303 }
304 
305 template <typename T>
move_assign_wider_scoped()306 bool move_assign_wider_scoped() {
307     BEGIN_TEST;
308 
309     int var1 = 0, var2 = 0;
310     {
311         auto do_incr = fit::defer<T>([&var1]() { incr_arg(&var1); });
312         EXPECT_TRUE(do_incr);
313         EXPECT_EQ(var1, 0);
314         EXPECT_EQ(var2, 0);
315         {
316             auto do_incr2 = fit::defer<T>([&var2]() { incr_arg(&var2); });
317             EXPECT_TRUE(do_incr);
318             EXPECT_TRUE(do_incr2);
319             EXPECT_EQ(var1, 0);
320             EXPECT_EQ(var2, 0);
321 
322             // do_incr is moved-to, so its associated function is called.
323             do_incr = std::move(do_incr2);
324             EXPECT_TRUE(do_incr);
325             EXPECT_FALSE(do_incr2);
326             EXPECT_EQ(var1, 1);
327             EXPECT_EQ(var2, 0);
328         }
329         // do_incr2 is out of scope but has been moved so its function is not
330         // called.
331         EXPECT_TRUE(do_incr);
332         EXPECT_EQ(var1, 1);
333         EXPECT_EQ(var2, 0);
334     }
335     EXPECT_EQ(var1, 1);
336     EXPECT_EQ(var2, 1);
337 
338     END_TEST;
339 }
340 
341 template <typename T>
move_assign_from_canceled()342 bool move_assign_from_canceled() {
343     BEGIN_TEST;
344 
345     int var1 = 0, var2 = 0;
346     {
347         auto do_incr = fit::defer<T>([&var1]() { incr_arg(&var1); });
348         auto do_incr2 = fit::defer<T>([&var2]() { incr_arg(&var2); });
349         EXPECT_TRUE(do_incr);
350         EXPECT_TRUE(do_incr2);
351         EXPECT_EQ(var1, 0);
352         EXPECT_EQ(var2, 0);
353 
354         do_incr.cancel();
355         EXPECT_FALSE(do_incr);
356         EXPECT_TRUE(do_incr2);
357         EXPECT_EQ(var1, 0);
358         EXPECT_EQ(var2, 0);
359 
360         // do_incr2 is moved-to, so its associated function is called.
361         do_incr2 = std::move(do_incr);
362         EXPECT_FALSE(do_incr);
363         EXPECT_FALSE(do_incr2);
364         EXPECT_EQ(var1, 0);
365         EXPECT_EQ(var2, 1);
366     }
367     // do_incr was cancelled, this state is preserved by the move.
368     EXPECT_EQ(var1, 0);
369     EXPECT_EQ(var2, 1);
370 
371     END_TEST;
372 }
373 
374 template <typename T>
move_assign_from_called()375 bool move_assign_from_called() {
376     BEGIN_TEST;
377 
378     int var1 = 0, var2 = 0;
379     {
380         auto do_incr = fit::defer<T>([&var1]() { incr_arg(&var1); });
381         auto do_incr2 = fit::defer<T>([&var2]() { incr_arg(&var2); });
382         EXPECT_TRUE(do_incr);
383         EXPECT_TRUE(do_incr2);
384         EXPECT_EQ(var1, 0);
385         EXPECT_EQ(var2, 0);
386 
387         do_incr.call();
388         EXPECT_FALSE(do_incr);
389         EXPECT_TRUE(do_incr2);
390         EXPECT_EQ(var1, 1);
391         EXPECT_EQ(var2, 0);
392 
393         // do_incr2 is moved-to, so its associated function is called.
394         do_incr2 = std::move(do_incr);
395         EXPECT_FALSE(do_incr);
396         EXPECT_FALSE(do_incr2);
397         EXPECT_EQ(var1, 1);
398         EXPECT_EQ(var2, 1);
399     }
400     // do_incr was called already, this state is preserved by the move.
401     EXPECT_EQ(var1, 1);
402     EXPECT_EQ(var2, 1);
403 
404     END_TEST;
405 }
406 
407 template <typename T>
move_assign_to_null()408 bool move_assign_to_null() {
409     BEGIN_TEST;
410 
411     int call_count = 0;
412     {
413         fit::deferred_action<T> deferred(nullptr);
414         EXPECT_FALSE(deferred);
415         deferred = fit::defer<T>([&call_count] { call_count++; });
416         EXPECT_EQ(0, call_count);
417     }
418     EXPECT_EQ(1, call_count);
419 
420     END_TEST;
421 }
422 
423 template <typename T>
move_assign_to_invalid()424 bool move_assign_to_invalid() {
425     BEGIN_TEST;
426 
427     int call_count = 0;
428     {
429         T fn;
430         fit::deferred_action<T> deferred(std::move(fn));
431         EXPECT_FALSE(deferred);
432         deferred = fit::defer<T>([&call_count] { call_count++; });
433         EXPECT_EQ(0, call_count);
434     }
435     EXPECT_EQ(1, call_count);
436 
437     END_TEST;
438 }
439 
440 template <typename T>
target_destroyed_when_scope_exited()441 bool target_destroyed_when_scope_exited() {
442     BEGIN_TEST;
443 
444     int call_count = 0;
445     int instance_count = 0;
446     {
447         auto action = fit::defer<T>(
448             [&call_count, balance = balance(&instance_count)] {
449                 incr_arg(&call_count);
450             });
451         EXPECT_EQ(0, call_count);
452         EXPECT_EQ(1, instance_count);
453     }
454     EXPECT_EQ(1, call_count);
455     EXPECT_EQ(0, instance_count);
456 
457     END_TEST;
458 }
459 
460 template <typename T>
target_destroyed_when_called()461 bool target_destroyed_when_called() {
462     BEGIN_TEST;
463 
464     int call_count = 0;
465     int instance_count = 0;
466     {
467         auto action = fit::defer<T>(
468             [&call_count, balance = balance(&instance_count)] {
469                 incr_arg(&call_count);
470             });
471         EXPECT_EQ(0, call_count);
472         EXPECT_EQ(1, instance_count);
473 
474         action.call();
475         EXPECT_EQ(1, call_count);
476         EXPECT_EQ(0, instance_count);
477     }
478     EXPECT_EQ(1, call_count);
479     EXPECT_EQ(0, instance_count);
480 
481     END_TEST;
482 }
483 
484 template <typename T>
target_destroyed_when_canceled()485 bool target_destroyed_when_canceled() {
486     BEGIN_TEST;
487 
488     int call_count = 0;
489     int instance_count = 0;
490     {
491         auto action = fit::defer<T>(
492             [&call_count, balance = balance(&instance_count)] {
493                 incr_arg(&call_count);
494             });
495         EXPECT_EQ(0, call_count);
496         EXPECT_EQ(1, instance_count);
497 
498         action.cancel();
499         EXPECT_EQ(0, call_count);
500         EXPECT_EQ(0, instance_count);
501     }
502     EXPECT_EQ(0, call_count);
503     EXPECT_EQ(0, instance_count);
504 
505     END_TEST;
506 }
507 
508 template <typename T>
target_destroyed_when_move_constructed()509 bool target_destroyed_when_move_constructed() {
510     BEGIN_TEST;
511 
512     int call_count = 0;
513     int instance_count = 0;
514     {
515         auto action = fit::defer<T>(
516             [&call_count, balance = balance(&instance_count)] {
517                 incr_arg(&call_count);
518             });
519         EXPECT_EQ(0, call_count);
520         EXPECT_EQ(1, instance_count);
521 
522         auto action2(std::move(action));
523         EXPECT_EQ(0, call_count);
524         EXPECT_EQ(1, instance_count);
525     }
526     EXPECT_EQ(1, call_count);
527     EXPECT_EQ(0, instance_count);
528 
529     END_TEST;
530 }
531 
532 template <typename T>
target_destroyed_when_move_assigned()533 bool target_destroyed_when_move_assigned() {
534     BEGIN_TEST;
535 
536     int call_count = 0;
537     int instance_count = 0;
538     {
539         auto action = fit::defer<T>(
540             [&call_count, balance = balance(&instance_count)] {
541                 incr_arg(&call_count);
542             });
543         EXPECT_EQ(0, call_count);
544         EXPECT_EQ(1, instance_count);
545 
546         auto action2 = fit::defer<T>([] {});
547         action2 = std::move(action);
548         EXPECT_EQ(0, call_count);
549         EXPECT_EQ(1, instance_count);
550     }
551     EXPECT_EQ(1, call_count);
552     EXPECT_EQ(0, instance_count);
553 
554     END_TEST;
555 }
556 
557 } // namespace
558 
559 BEGIN_TEST_CASE(defer_tests)
560 RUN_TEST(default_construction<fit::closure>)
561 RUN_TEST(default_construction<std::function<void()>>)
562 RUN_TEST(null_construction<fit::closure>)
563 RUN_TEST(null_construction<std::function<void()>>)
564 RUN_TEST(basic<fit::closure>)
565 RUN_TEST(basic<std::function<void()>>)
566 RUN_TEST(cancel<fit::closure>)
567 RUN_TEST(cancel<std::function<void()>>)
568 RUN_TEST(null_assignment<fit::closure>)
569 RUN_TEST(null_assignment<std::function<void()>>)
570 RUN_TEST(target_reassignment<fit::closure>)
571 RUN_TEST(target_reassignment<std::function<void()>>)
572 RUN_TEST(call<fit::closure>)
573 RUN_TEST(call<std::function<void()>>)
574 RUN_TEST(recursive_call<fit::closure>)
575 RUN_TEST(recursive_call<std::function<void()>>)
576 RUN_TEST(move_construct_basic<fit::closure>)
577 RUN_TEST(move_construct_basic<std::function<void()>>)
578 RUN_TEST(move_construct_from_canceled<fit::closure>)
579 RUN_TEST(move_construct_from_canceled<std::function<void()>>)
580 RUN_TEST(move_construct_from_called<fit::closure>)
581 RUN_TEST(move_construct_from_called<std::function<void()>>)
582 RUN_TEST(move_assign_basic<fit::closure>)
583 RUN_TEST(move_assign_basic<std::function<void()>>)
584 RUN_TEST(move_assign_wider_scoped<fit::closure>)
585 RUN_TEST(move_assign_wider_scoped<std::function<void()>>)
586 RUN_TEST(move_assign_from_canceled<fit::closure>)
587 RUN_TEST(move_assign_from_canceled<std::function<void()>>)
588 RUN_TEST(move_assign_from_called<fit::closure>)
589 RUN_TEST(move_assign_from_called<std::function<void()>>)
590 RUN_TEST(move_assign_to_null<fit::closure>)
591 RUN_TEST(move_assign_to_null<std::function<void()>>)
592 RUN_TEST(move_assign_to_invalid<fit::closure>)
593 RUN_TEST(move_assign_to_invalid<std::function<void()>>)
594 // These tests do not support std::function because std::function copies
595 // the captured values (which balance does not support).
596 RUN_TEST(target_destroyed_when_scope_exited<fit::closure>)
597 RUN_TEST(target_destroyed_when_called<fit::closure>)
598 RUN_TEST(target_destroyed_when_canceled<fit::closure>)
599 RUN_TEST(target_destroyed_when_move_constructed<fit::closure>)
600 RUN_TEST(target_destroyed_when_move_assigned<fit::closure>)
601 END_TEST_CASE(defer_tests)
602