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