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