#include #include #include #include using namespace psemek::util; test_case(util_function_empty_call) { function f; expect_throw(f(), std::bad_function_call); } using heavy = std::array; static void util_function_assign_test(bool light) { function f; expect(!f); int counter = 0; if (light) f = [&counter]{ ++counter; }; else f = [&counter, h = heavy{}]{ unused(h); ++counter; }; expect(f); expect_equal(counter, 0); f(); expect_equal(counter, 1); f(); expect_equal(counter, 2); } static void util_function_move_test(bool light) { function f; expect(!f); int counter = 0; if (light) f = [&counter]{ ++counter; }; else f = [&counter, h = heavy{}]{ unused(h); ++counter; }; expect(f); function g; expect(!g); g = std::move(f); expect(!f); expect(g); expect_equal(counter, 0); g(); expect_equal(counter, 1); g(); expect_equal(counter, 2); function h = std::move(g); expect(!f); expect(!g); expect(h); expect_equal(counter, 2); h(); expect_equal(counter, 3); h(); expect_equal(counter, 4); } static void util_function_destroy_test(bool light) { std::shared_ptr p = std::make_shared(0); auto wp = std::weak_ptr(p); { function f, g; expect(!f); expect(!g); if (light) { f = [p]{ ++*p; }; g = [p]{ --*p; }; } else { f = [p, h = heavy{}]{ unused(h); ++*p; }; g = [p, h = heavy{}]{ unused(h); --*p; }; } expect(f); expect(g); expect(p); expect_equal(p.use_count(), 3); expect_equal(*p, 0); p.reset(); expect(wp.lock()); expect_equal(wp.use_count(), 2); expect_equal(*wp.lock(), 0); f(); expect_equal(*wp.lock(), 1); f(); expect_equal(*wp.lock(), 2); g(); expect_equal(*wp.lock(), 1); g(); expect_equal(*wp.lock(), 0); f.reset(); expect(!f); expect(wp.lock()); expect_equal(wp.use_count(), 1); } expect(!wp.lock()); expect_equal(wp.use_count(), 0); } namespace { struct fake_exception : std::exception { char const * what() const noexcept { return "fake"; } }; template struct throw_on_move { Heavy heavy; throw_on_move() = default; throw_on_move(throw_on_move &&) { throw fake_exception{}; } void operator()() {} }; } static void util_function_guarantee_test(bool light) { function f; expect(!f); int counter = 0; f = [&counter]{ ++counter; }; expect(f); expect_equal(counter, 0); if (light) expect_throw(f = throw_on_move{}, fake_exception); else expect_throw(f = throw_on_move{}, fake_exception); expect(f); expect_equal(counter, 0); f(); expect_equal(counter, 1); } test_case(util_function_light_assign) { util_function_assign_test(true); } test_case(util_function_light_move) { util_function_move_test(true); } test_case(util_function_light_destroy) { util_function_destroy_test(true); } test_case(util_function_light_guarantee) { util_function_guarantee_test(true); } test_case(util_function_heavy_assign) { util_function_assign_test(false); } test_case(util_function_heavy_move) { util_function_move_test(false); } test_case(util_function_heavy_destroy) { util_function_destroy_test(false); } test_case(util_function_heavy_guarantee) { util_function_guarantee_test(false); }