211 lines
3.3 KiB
C++
211 lines
3.3 KiB
C++
#include <psemek/test/test.hpp>
|
|
|
|
#include <psemek/util/function.hpp>
|
|
#include <psemek/util/unused.hpp>
|
|
|
|
#include <memory>
|
|
#include <array>
|
|
|
|
using namespace psemek::util;
|
|
|
|
test_case(util_function_empty_call)
|
|
{
|
|
function<void()> f;
|
|
expect_throw(f(), std::bad_function_call);
|
|
}
|
|
|
|
using heavy = std::array<int, 256>;
|
|
|
|
static void util_function_assign_test(bool light)
|
|
{
|
|
function<void()> 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<void()> f;
|
|
expect(!f);
|
|
|
|
int counter = 0;
|
|
if (light)
|
|
f = [&counter]{ ++counter; };
|
|
else
|
|
f = [&counter, h = heavy{}]{ unused(h); ++counter; };
|
|
expect(f);
|
|
|
|
function<void()> 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<void()> 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<int> p = std::make_shared<int>(0);
|
|
|
|
auto wp = std::weak_ptr(p);
|
|
|
|
{
|
|
function<void()> 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 <typename Heavy>
|
|
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<void()> f;
|
|
expect(!f);
|
|
|
|
int counter = 0;
|
|
f = [&counter]{ ++counter; };
|
|
expect(f);
|
|
expect_equal(counter, 0);
|
|
|
|
if (light)
|
|
expect_throw(f = throw_on_move<int>{}, fake_exception);
|
|
else
|
|
expect_throw(f = throw_on_move<heavy>{}, 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);
|
|
}
|