Commit ff54e90a authored by Dominik Charousset's avatar Dominik Charousset

Use fixtures in unit tests

parent a79b8628
......@@ -31,9 +31,9 @@ using namespace caf;
using check_atom = caf::atom_constant<caf::atom("check")>;
namespace {
std::atomic<long> s_testees;
std::atomic<long> s_pending_on_exits;
} // namespace <anonymous>
class testee : public event_based_actor {
public:
......@@ -67,16 +67,13 @@ behavior testee::make_behavior() {
template <class ExitMsgType>
behavior tester(event_based_actor* self, const actor& aut) {
CAF_MESSAGE("tester behaivor entered");
if (std::is_same<ExitMsgType, exit_msg>::value) {
self->trap_exit(true);
self->link_to(aut);
} else {
self->monitor(aut);
}
CAF_MESSAGE("tester before `anon_send_exit`");
anon_send_exit(aut, exit_reason::user_shutdown);
CAF_MESSAGE("tester after `anon_send_exit`");
return {
[self](const ExitMsgType& msg) {
// must be still alive at this point
......@@ -100,32 +97,47 @@ behavior tester(event_based_actor* self, const actor& aut) {
};
}
CAF_TEST(no_spawn_options) {
spawn<no_spawn_options>(tester<exit_msg>, spawn<testee, no_spawn_options>());
struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
}
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(actor_lifetime_tests, fixture)
CAF_TEST(no_spawn_options_and_exit_msg) {
spawn<no_spawn_options>(tester<exit_msg>, spawn<testee, no_spawn_options>());
}
CAF_TEST(no_spawn_options_and_down_msg) {
spawn<no_spawn_options>(tester<down_msg>, spawn<testee, no_spawn_options>());
await_all_actors_done();
}
CAF_TEST(mixed_spawn_options) {
CAF_TEST(mixed_spawn_options_and_exit_msg) {
spawn<detached>(tester<exit_msg>, spawn<testee, no_spawn_options>());
await_all_actors_done();
}
CAF_TEST(mixed_spawn_options_and_down_msg) {
spawn<detached>(tester<down_msg>, spawn<testee, no_spawn_options>());
await_all_actors_done();
}
CAF_TEST(mixed_spawn_options2) {
CAF_TEST(mixed_spawn_options2_and_exit_msg) {
spawn<no_spawn_options>(tester<exit_msg>, spawn<testee, detached>());
await_all_actors_done();
}
CAF_TEST(mixed_spawn_options2_and_down_msg) {
spawn<no_spawn_options>(tester<down_msg>, spawn<testee, detached>());
await_all_actors_done();
}
CAF_TEST(detached_spawn_options) {
CAF_TEST(detached_and_exit_msg) {
spawn<detached>(tester<exit_msg>, spawn<testee, detached>());
await_all_actors_done();
}
CAF_TEST(detached_and_down_msg) {
spawn<detached>(tester<down_msg>, spawn<testee, detached>());
await_all_actors_done();
shutdown();
}
CAF_TEST_FIXTURE_SCOPE_END()
......@@ -29,8 +29,6 @@ namespace {
std::atomic<size_t> s_ctors;
std::atomic<size_t> s_dtors;
} // namespace <anonymous>
class worker : public event_based_actor {
public:
worker();
......@@ -58,8 +56,18 @@ actor spawn_worker() {
return spawn<worker>();
}
CAF_TEST(test_actor_pool) {
struct fixture {
fixture() {
announce<std::vector<int>>("vector<int>");
}
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(actor_pool_tests, fixture)
CAF_TEST(round_robin_actor_pool) {
{ // lifetime scope of self
scoped_actor self;
auto w = actor_pool::make(5, spawn_worker, actor_pool::round_robin{});
self->monitor(w);
......@@ -131,9 +139,14 @@ CAF_TEST(test_actor_pool) {
}
);
}
}
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
}
CAF_TEST(test_broadcast_actor_pool) {
CAF_TEST(broadcast_actor_pool) {
{ // lifetime scope of self
scoped_actor self;
auto spawn5 = []() {
return actor_pool::make(5, spawn_worker, actor_pool::broadcast{});
......@@ -154,10 +167,14 @@ CAF_TEST(test_broadcast_actor_pool) {
CAF_CHECK(std::all_of(results.begin(), results.end(),
[](int res) { return res == 3; }));
self->send_exit(w, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
}
CAF_TEST(test_random_actor_pool) {
CAF_TEST(random_actor_pool) {
{ // lifetime scope of self
scoped_actor self;
auto w = actor_pool::make(5, spawn_worker, actor_pool::random{});
for (int i = 0; i < 5; ++i) {
......@@ -171,11 +188,13 @@ CAF_TEST(test_random_actor_pool) {
);
}
self->send_exit(w, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
}
CAF_TEST(test_split_join_actor_pool) {
announce<std::vector<int>>("vector<int>");
CAF_TEST(split_join_actor_pool) {
auto spawn_split_worker = [] {
return spawn<lazy_init>([]() -> behavior {
return {
......@@ -195,6 +214,7 @@ CAF_TEST(test_split_join_actor_pool) {
res += x;
});
};
{ // lifetime scope of self
scoped_actor self;
auto w = actor_pool::make(5, spawn_split_worker,
actor_pool::split_join<int>(join_fun, split_fun));
......@@ -209,11 +229,10 @@ CAF_TEST(test_split_join_actor_pool) {
}
);
self->send_exit(w, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}
CAF_TEST(test_dtors) {
}
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
}
CAF_TEST_FIXTURE_SCOPE_END()
......@@ -30,18 +30,28 @@ using namespace caf;
namespace {
constexpr auto s_foo = atom("FooBar");
using abc_atom = atom_constant<atom("abc")>;
struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
}
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(atom_tests, fixture)
CAF_TEST(basics) {
// check if there are leading bits that distinguish "zzz" and "000 "
CAF_CHECK(atom("zzz") != atom("000 "));
// check if there are leading bits that distinguish "abc" and " abc"
CAF_CHECK(atom("abc") != atom(" abc"));
// 'illegal' characters are mapped to whitespaces
CAF_CHECK_EQUAL(atom(" "), atom("@!?"));
// check to_string impl.
CAF_CHECK(atom(" ") == atom("@!?"));
// check to_string impl
CAF_CHECK_EQUAL(to_string(s_foo), "FooBar");
}
......@@ -111,7 +121,6 @@ using testee = typed_actor<replies_to<abc_atom>::with<int>>;
testee::behavior_type testee_impl(testee::pointer self) {
return {
[=](abc_atom) {
CAF_MESSAGE("received abc_atom");
self->quit();
return 42;
}
......@@ -119,7 +128,6 @@ testee::behavior_type testee_impl(testee::pointer self) {
}
CAF_TEST(sync_send_atom_constants) {
{
scoped_actor self;
auto tst = spawn_typed(testee_impl);
self->sync_send(tst, abc_atom::value).await(
......@@ -127,7 +135,6 @@ CAF_TEST(sync_send_atom_constants) {
CAF_CHECK_EQUAL(i, 42);
}
);
self->await_all_other_actors_done();
}
shutdown();
}
CAF_TEST_FIXTURE_SCOPE_END()
......@@ -31,6 +31,13 @@ using namespace caf;
namespace {
struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
}
};
class testee : public event_based_actor {
public:
testee();
......@@ -81,13 +88,13 @@ behavior tester::make_behavior() {
send(m_aut, m_msg);
return {
on(1, 2, 3) >> [=] {
CAF_CHECK_EQUAL(current_message().cvals()->get_reference_count(), 2);
CAF_CHECK(current_message().cvals().get() == m_msg.cvals().get());
CAF_CHECK(current_message().cvals()->get_reference_count() == 2
&& current_message().cvals().get() == m_msg.cvals().get());
},
[=](const down_msg& dm) {
CAF_CHECK(dm.source == m_aut);
CAF_CHECK_EQUAL(dm.reason, exit_reason::normal);
CAF_CHECK_EQUAL(current_message().cvals()->get_reference_count(), 1);
CAF_CHECK(dm.source == m_aut
&& dm.reason == exit_reason::normal
&& current_message().cvals()->get_reference_count() == 1);
quit();
},
others >> [&] {
......@@ -96,7 +103,19 @@ behavior tester::make_behavior() {
};
}
void message_lifetime_in_scoped_actor() {
template <spawn_options Os>
void test_message_lifetime() {
// put some preassure on the scheduler (check for thread safety)
for (size_t i = 0; i < 100; ++i) {
spawn<tester>(spawn<testee, Os>());
}
}
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(message_lifetime_tests, fixture)
CAF_TEST(message_lifetime_in_scoped_actor) {
auto msg = make_message(1, 2, 3);
scoped_actor self;
self->send(self, msg);
......@@ -121,30 +140,12 @@ void message_lifetime_in_scoped_actor() {
CAF_CHECK_EQUAL(msg.get_as<int>(0), 42);
}
template <spawn_options Os>
void test_message_lifetime() {
message_lifetime_in_scoped_actor();
// put some preassure on the scheduler (check for thread safety)
for (size_t i = 0; i < 100; ++i) {
spawn<tester>(spawn<testee, Os>());
}
}
} // namespace <anonymous>
CAF_TEST(test_message_lifetime_in_scoped_actor) {
message_lifetime_in_scoped_actor();
}
CAF_TEST(test_message_lifetime_no_spawn_options) {
CAF_MESSAGE("test_message_lifetime<no_spawn_options>");
CAF_TEST(message_lifetime_no_spawn_options) {
test_message_lifetime<no_spawn_options>();
}
CAF_TEST(test_message_lifetime_priority_aware) {
CAF_MESSAGE("test_message_lifetime<priority_aware>");
CAF_TEST(message_lifetime_priority_aware) {
test_message_lifetime<priority_aware>();
await_all_actors_done();
shutdown();
}
CAF_TEST_FIXTURE_SCOPE_END()
......@@ -122,21 +122,21 @@ enum class test_enum {
c
};
struct common_fixture {
struct fixture {
int32_t i32 = -345;
test_enum te = test_enum::b;
string str = "Lorem ipsum dolor sit amet.";
raw_struct rs;
message msg;
common_fixture() {
fixture() {
announce<test_enum>("test_enum");
announce(typeid(raw_struct), uniform_type_info_ptr{new raw_struct_type_info});
rs.str.assign(string(str.rbegin(), str.rend()));
msg = make_message(i32, te, str, rs);
}
~common_fixture() {
~fixture() {
await_all_actors_done();
shutdown();
}
......@@ -211,7 +211,7 @@ struct is_message {
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(serialization_tests, common_fixture)
CAF_TEST_FIXTURE_SCOPE(serialization_tests, fixture)
CAF_TEST(test_serialization) {
using token = std::integral_constant<int, detail::impl_id<strmap>()>;
......
......@@ -925,6 +925,36 @@ CAF_TEST(test_exit_reason_scoped_actor) {
shutdown();
}
CAF_TEST(test_spawn_fun) {
class my_actor : public event_based_actor {
public:
behavior make_behavior() override {
return {
[=](sys_atom, std::function<behavior (my_actor*)>& fun) {
become(fun(this));
}
};
}
};
auto ma = spawn<my_actor>();
std::function<behavior (my_actor*)> fun = [](my_actor*) -> behavior {
return {
[](int x, int y) {
return x + y;
}
};
};
scoped_actor self;
self->send(ma, sys_atom::value, fun);
self->sync_send(ma, 10, 20).await(
[](int res) {
CAF_CHECK_EQUAL(res, 10 + 20);
}
);
self->send_exit(ma, exit_reason::kill);
self->await_all_other_actors_done();
}
CAF_TEST(test_number_of_instances) {
CAF_CHECK_EQUAL(s_actor_instances.load(), 0);
CAF_MESSAGE("max. nr. of actor instances: " << s_max_actor_instances.load());
......
......@@ -36,6 +36,14 @@ namespace caf {
class message;
namespace test {
/**
* A sequence of *checks*.
*/
class check_sequence {
virtual ~check_sequence();
virtual void run() = 0;
};
/**
* A sequence of *checks*.
*/
......@@ -61,7 +69,9 @@ class test {
return m_bad;
}
virtual void run() = 0;
void run();
virtual std::unique_ptr<check_sequence> make_sequence() = 0;
private:
size_t m_expected_failures;
......@@ -219,14 +229,12 @@ class engine {
*/
static char* path();
using test_generator = std::function<std::unique_ptr<test> ()>;
/**
* Adds a test to the engine.
* @param name The name of the suite.
* @param t The test to register.
*/
static void add(const char* name, test_generator generator);
static void add(const char* name, std::unique_ptr<test> ptr);
/**
* Invokes tests in all suites.
......@@ -296,7 +304,7 @@ class engine {
const char* m_check_file = "<none>";
size_t m_check_line = 0;
test* m_current_test = nullptr;
std::map<std::string, std::vector<test_generator>> m_suites;
std::map<std::string, std::vector<std::unique_ptr<test>>> m_suites;
};
namespace detail {
......@@ -598,8 +606,7 @@ using caf_test_case_auto_fixture = caf::test::dummy_fixture;
#define CAF_TEST(name) \
namespace { \
struct CAF_UNIQUE(test) : public ::caf::test::test, \
public caf_test_case_auto_fixture { \
struct CAF_UNIQUE(test) : public ::caf::test::test { \
CAF_UNIQUE(test)() : test{CAF_XSTR(name)} { } \
void run() final; \
}; \
......
......@@ -81,6 +81,10 @@ void watchdog::stop() {
delete s_watchdog;
}
check_sequence::~check_sequence() {
// nop
}
test::test(std::string test_name)
: m_expected_failures(0),
m_name(std::move(test_name)),
......@@ -114,6 +118,11 @@ const std::string& test::name() const {
return m_name;
}
void test::run() {
auto runner = make_sequence();
runner->run();
}
namespace detail {
require_error::require_error(const std::string& msg) : std::logic_error(msg) {
......@@ -241,10 +250,16 @@ char* engine::path() {
return instance().m_path;
}
void engine::add(const char* cstr_name, test_generator generator) {
void engine::add(const char* cstr_name, std::unique_ptr<test> ptr) {
std::string name = cstr_name ? cstr_name : "";
auto& suite = instance().m_suites[name];
suite.emplace_back(std::move(generator));
for (auto& x : suite) {
if (x->name() == ptr->name()) {
std::cout << "duplicate test name: " << ptr->name() << '\n';
std::abort();
}
}
suite.emplace_back(std::move(ptr));
}
bool engine::run(bool colorize,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment