Commit e87824c6 authored by Dominik Charousset's avatar Dominik Charousset

Use fixtures in unit tests + cleanup

parent ff54e90a
...@@ -60,6 +60,11 @@ struct fixture { ...@@ -60,6 +60,11 @@ struct fixture {
fixture() { fixture() {
announce<std::vector<int>>("vector<int>"); announce<std::vector<int>>("vector<int>");
} }
~fixture() {
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
}
}; };
} // namespace <anonymous> } // namespace <anonymous>
...@@ -67,131 +72,116 @@ struct fixture { ...@@ -67,131 +72,116 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(actor_pool_tests, fixture) CAF_TEST_FIXTURE_SCOPE(actor_pool_tests, fixture)
CAF_TEST(round_robin_actor_pool) { CAF_TEST(round_robin_actor_pool) {
{ // lifetime scope of self scoped_actor self;
scoped_actor self; auto w = actor_pool::make(5, spawn_worker, actor_pool::round_robin{});
auto w = actor_pool::make(5, spawn_worker, actor_pool::round_robin{}); self->monitor(w);
self->monitor(w); self->send(w, sys_atom::value, put_atom::value, spawn_worker());
self->send(w, sys_atom::value, put_atom::value, spawn_worker()); std::vector<actor_addr> workers;
std::vector<actor_addr> workers; for (int i = 0; i < 6; ++i) {
for (int i = 0; i < 6; ++i) { self->sync_send(w, i, i).await(
self->sync_send(w, i, i).await( [&](int res) {
[&](int res) { CAF_CHECK_EQUAL(res, i + i);
CAF_CHECK_EQUAL(res, i + i); auto sender = self->current_sender();
auto sender = self->current_sender(); self->monitor(sender);
self->monitor(sender); workers.push_back(sender);
workers.push_back(sender); }
);
}
CAF_CHECK(workers.size() == 6);
CAF_CHECK(std::unique(workers.begin(), workers.end()) == workers.end());
auto is_invalid = [](const actor_addr& addr) {
return addr == invalid_actor_addr;
};
CAF_CHECK(std::none_of(workers.begin(), workers.end(), is_invalid));
self->sync_send(w, sys_atom::value, get_atom::value).await(
[&](std::vector<actor>& ws) {
std::sort(workers.begin(), workers.end());
std::sort(ws.begin(), ws.end());
CAF_CHECK(workers.size() == ws.size()
&& std::equal(workers.begin(), workers.end(), ws.begin()));
}
);
anon_send_exit(workers.back(), exit_reason::user_shutdown);
self->receive(
after(std::chrono::milliseconds(25)) >> [] {
// wait some time to give the pool time to remove the failed worker
}
);
self->receive(
[&](const down_msg& dm) {
CAF_CHECK(dm.source == workers.back());
workers.pop_back();
// check whether actor pool removed failed worker
self->sync_send(w, sys_atom::value, get_atom::value).await(
[&](std::vector<actor>& ws) {
std::sort(ws.begin(), ws.end());
CAF_CHECK(workers.size() == ws.size()
&& std::equal(workers.begin(), workers.end(), ws.begin()));
} }
); );
},
after(std::chrono::milliseconds(250)) >> [] {
CAF_TEST_ERROR("didn't receive a down message");
} }
CAF_CHECK(workers.size() == 6); );
CAF_CHECK(std::unique(workers.begin(), workers.end()) == workers.end()); CAF_MESSAGE("about to send exit to workers");
auto is_invalid = [](const actor_addr& addr) { self->send_exit(w, exit_reason::user_shutdown);
return addr == invalid_actor_addr; for (int i = 0; i < 6; ++i) {
};
CAF_CHECK(std::none_of(workers.begin(), workers.end(), is_invalid));
self->sync_send(w, sys_atom::value, get_atom::value).await(
[&](std::vector<actor>& ws) {
std::sort(workers.begin(), workers.end());
std::sort(ws.begin(), ws.end());
CAF_CHECK(workers.size() == ws.size()
&& std::equal(workers.begin(), workers.end(), ws.begin()));
}
);
anon_send_exit(workers.back(), exit_reason::user_shutdown);
self->receive(
after(std::chrono::milliseconds(25)) >> [] {
// wait some time to give the pool time to remove the failed worker
}
);
self->receive( self->receive(
[&](const down_msg& dm) { [&](const down_msg& dm) {
CAF_CHECK(dm.source == workers.back()); auto last = workers.end();
workers.pop_back(); auto src = dm.source;
// check whether actor pool removed failed worker CAF_CHECK(src != invalid_actor_addr);
self->sync_send(w, sys_atom::value, get_atom::value).await( auto pos = std::find(workers.begin(), last, src);
[&](std::vector<actor>& ws) { //CAF_CHECK(pos != last || src == w); fail?
std::sort(ws.begin(), ws.end()); if (pos != last) {
CAF_CHECK(workers.size() == ws.size() workers.erase(pos);
&& std::equal(workers.begin(), workers.end(), ws.begin())); }
}
);
}, },
after(std::chrono::milliseconds(250)) >> [] { after(std::chrono::milliseconds(250)) >> [] {
CAF_TEST_ERROR("didn't receive a down message"); CAF_TEST_ERROR("didn't receive a down message");
} }
); );
CAF_MESSAGE("about to send exit to workers");
self->send_exit(w, exit_reason::user_shutdown);
for (int i = 0; i < 6; ++i) {
self->receive(
[&](const down_msg& dm) {
auto last = workers.end();
auto src = dm.source;
CAF_CHECK(src != invalid_actor_addr);
auto pos = std::find(workers.begin(), last, src);
//CAF_CHECK(pos != last || src == w); fail?
if (pos != last) {
workers.erase(pos);
}
},
after(std::chrono::milliseconds(250)) >> [] {
CAF_TEST_ERROR("didn't receive a down message");
}
);
}
} }
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
} }
CAF_TEST(broadcast_actor_pool) { CAF_TEST(broadcast_actor_pool) {
{ // lifetime scope of self scoped_actor self;
scoped_actor self; auto spawn5 = []() {
auto spawn5 = []() { return actor_pool::make(5, spawn_worker, actor_pool::broadcast{});
return actor_pool::make(5, spawn_worker, actor_pool::broadcast{}); };
}; auto w = actor_pool::make(5, spawn5, actor_pool::broadcast{});
auto w = actor_pool::make(5, spawn5, actor_pool::broadcast{}); self->send(w, 1, 2);
self->send(w, 1, 2); std::vector<int> results;
std::vector<int> results; int i = 0;
int i = 0; self->receive_for(i, 25)(
self->receive_for(i, 25)( [&](int res) {
results.push_back(res);
},
after(std::chrono::milliseconds(250)) >> [] {
CAF_TEST_ERROR("didn't receive a result");
}
);
CAF_CHECK_EQUAL(results.size(), 25);
CAF_CHECK(std::all_of(results.begin(), results.end(),
[](int res) { return res == 3; }));
self->send_exit(w, exit_reason::user_shutdown);
}
CAF_TEST(random_actor_pool) {
scoped_actor self;
auto w = actor_pool::make(5, spawn_worker, actor_pool::random{});
for (int i = 0; i < 5; ++i) {
self->sync_send(w, 1, 2).await(
[&](int res) { [&](int res) {
results.push_back(res); CAF_CHECK_EQUAL(res, 3);
}, },
after(std::chrono::milliseconds(250)) >> [] { after(std::chrono::milliseconds(250)) >> [] {
CAF_TEST_ERROR("didn't receive a result"); CAF_TEST_ERROR("didn't receive a down message");
} }
); );
CAF_CHECK_EQUAL(results.size(), 25);
CAF_CHECK(std::all_of(results.begin(), results.end(),
[](int res) { return res == 3; }));
self->send_exit(w, exit_reason::user_shutdown);
}
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
}
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) {
self->sync_send(w, 1, 2).await(
[&](int res) {
CAF_CHECK_EQUAL(res, 3);
},
after(std::chrono::milliseconds(250)) >> [] {
CAF_TEST_ERROR("didn't receive a down message");
}
);
}
self->send_exit(w, exit_reason::user_shutdown);
} }
await_all_actors_done(); self->send_exit(w, exit_reason::user_shutdown);
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
} }
CAF_TEST(split_join_actor_pool) { CAF_TEST(split_join_actor_pool) {
...@@ -214,25 +204,20 @@ CAF_TEST(split_join_actor_pool) { ...@@ -214,25 +204,20 @@ CAF_TEST(split_join_actor_pool) {
res += x; res += x;
}); });
}; };
{ // lifetime scope of self scoped_actor self;
scoped_actor self; auto w = actor_pool::make(5, spawn_split_worker,
auto w = actor_pool::make(5, spawn_split_worker, actor_pool::split_join<int>(join_fun, split_fun));
actor_pool::split_join<int>(join_fun, split_fun)); self->sync_send(w, std::vector<int>{1, 2, 3, 4, 5}).await(
self->sync_send(w, std::vector<int>{1, 2, 3, 4, 5}).await( [&](int res) {
[&](int res) { CAF_CHECK_EQUAL(res, 15);
CAF_CHECK_EQUAL(res, 15); }
} );
); self->sync_send(w, std::vector<int>{6, 7, 8, 9, 10}).await(
self->sync_send(w, std::vector<int>{6, 7, 8, 9, 10}).await( [&](int res) {
[&](int res) { CAF_CHECK_EQUAL(res, 40);
CAF_CHECK_EQUAL(res, 40); }
} );
); self->send_exit(w, exit_reason::user_shutdown);
self->send_exit(w, exit_reason::user_shutdown);
}
await_all_actors_done();
shutdown();
CAF_CHECK_EQUAL(s_dtors.load(), s_ctors.load());
} }
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
using namespace caf; using namespace caf;
CAF_TEST(test_constructor_attach) { CAF_TEST(constructor_attach) {
class testee : public event_based_actor { class testee : public event_based_actor {
public: public:
testee(actor buddy) : m_buddy(buddy) { testee(actor buddy) : m_buddy(buddy) {
......
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
using namespace caf; using namespace caf;
namespace {
using foo = typed_actor<replies_to<int>::with_either<int>::or_else<float>>; using foo = typed_actor<replies_to<int>::with_either<int>::or_else<float>>;
foo::behavior_type my_foo() { foo::behavior_type my_foo() {
...@@ -37,7 +39,18 @@ foo::behavior_type my_foo() { ...@@ -37,7 +39,18 @@ foo::behavior_type my_foo() {
}; };
} }
CAF_TEST(either) { struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
}
};
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(atom_tests, fixture)
CAF_TEST(basic_usage) {
auto f1 = []() -> either<int>::or_else<float> { auto f1 = []() -> either<int>::or_else<float> {
return 42; return 42;
}; };
...@@ -50,31 +63,36 @@ CAF_TEST(either) { ...@@ -50,31 +63,36 @@ CAF_TEST(either) {
} }
return {3.f, 4.f}; return {3.f, 4.f};
}; };
f1(); CAF_CHECK(f1().value == make_message(42));
f2(); CAF_CHECK(f2().value == make_message(42.f));
f3(true); CAF_CHECK(f3(true).value == make_message(1, 2));
f3(false); CAF_CHECK(f3(false).value == make_message(3.f, 4.f));
either<int>::or_else<float> x1{4}; either<int>::or_else<float> x1{4};
CAF_CHECK(x1.value == make_message(4));
either<int>::or_else<float> x2{4.f}; either<int>::or_else<float> x2{4.f};
CAF_CHECK(x2.value == make_message(4.f));
}
CAF_TEST(either_in_typed_interfaces) {
auto mf = spawn_typed(my_foo); auto mf = spawn_typed(my_foo);
{ scoped_actor self;
scoped_actor self; self->sync_send(mf, 42).await(
self->sync_send(mf, 42).await( [](int val) {
[](int val) { CAF_CHECK_EQUAL(val, 42);
CAF_CHECK_EQUAL(val, 42); },
}, [](float) {
[](float) { CAF_TEST_ERROR("expected an integer");
CAF_TEST_ERROR("expected an integer"); }
} );
); self->sync_send(mf, 10).await(
self->sync_send(mf, 10).await( [](int) {
[](int) { CAF_TEST_ERROR("expected a float");
CAF_TEST_ERROR("expected a float"); },
}, [](float val) {
[](float val) { CAF_CHECK_EQUAL(val, 10.f);
CAF_CHECK_EQUAL(val, 10.f); }
} );
); self->send_exit(mf, exit_reason::kill);
}
shutdown();
} }
CAF_TEST_FIXTURE_SCOPE_END()
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE fixed_stack_actor
#include "caf/test/unit_test.hpp"
#include <vector>
#include "caf/all.hpp"
using namespace caf;
using pop_atom = atom_constant<atom("pop")>;
using push_atom = atom_constant<atom("push")>;
class fixed_stack : public sb_actor<fixed_stack> {
public:
friend class sb_actor<fixed_stack>;
fixed_stack(size_t max) : max_size(max) {
full.assign(
[=](push_atom, int) {
/* discard */
},
[=](pop_atom) -> message {
auto result = data.back();
data.pop_back();
become(filled);
return make_message(ok_atom::value, result);
}
);
filled.assign(
[=](push_atom, int what) {
data.push_back(what);
if (data.size() == max_size) {
become(full);
}
},
[=](pop_atom) -> message {
auto result = data.back();
data.pop_back();
if (data.empty()) {
become(empty);
}
return make_message(ok_atom::value, result);
}
);
empty.assign(
[=](push_atom, int what) {
data.push_back(what);
become(filled);
},
[=](pop_atom) {
return error_atom::value;
}
);
}
~fixed_stack();
private:
size_t max_size = 10;
std::vector<int> data;
behavior full;
behavior filled;
behavior empty;
behavior& init_state = empty;
};
fixed_stack::~fixed_stack() {
// avoid weak-vtables warning
}
CAF_TEST(test_fixed_stack_actor) {
{
scoped_actor self;
auto st = spawn<fixed_stack>(size_t{10});
// push 20 values
for (int i = 0; i < 20; ++i) self->send(st, push_atom::value, i);
// pop 20 times
for (int i = 0; i < 20; ++i) self->send(st, pop_atom::value);
// expect 10 failure messages
{
int i = 0;
self->receive_for(i, 10) (
[](error_atom) {
CAF_MESSAGE("received `error_atom`");
}
);
CAF_MESSAGE("received all messages");
}
// expect 10 {'ok', value} messages
{
std::vector<int> values;
int i = 0;
self->receive_for(i, 10) (
[&](ok_atom, int value) {
values.push_back(value);
}
);
std::vector<int> expected{9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
CAF_CHECK_EQUAL(join(values, ","), join(expected, ","));
}
// terminate st
self->send_exit(st, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}
await_all_actors_done();
shutdown();
}
...@@ -20,10 +20,10 @@ ...@@ -20,10 +20,10 @@
#define CAF_SUITE intrusive_ptr #define CAF_SUITE intrusive_ptr
#include "caf/test/unit_test.hpp" #include "caf/test/unit_test.hpp"
// this test dosn't test thread-safety of intrusive_ptr // this test dosn't verify thread-safety of intrusive_ptr
// however, it is thread safe since it uses atomic operations only // however, it is thread safe since it uses atomic operations only
#include <list> #include <vector>
#include <cstddef> #include <cstddef>
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
...@@ -92,73 +92,64 @@ class0ptr get_test_ptr() { ...@@ -92,73 +92,64 @@ class0ptr get_test_ptr() {
return get_test_rc(); return get_test_rc();
} }
struct fixture {
~fixture() {
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 0);
}
};
} // namespace <anonymous> } // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(atom_tests, fixture)
CAF_TEST(make_counted) { CAF_TEST(make_counted) {
{ auto p = make_counted<class0>();
auto p = make_counted<class0>(); CAF_CHECK_EQUAL(class0_instances, 1);
CAF_CHECK_EQUAL(class0_instances, 1); CAF_CHECK(p->unique());
CAF_CHECK(p->unique());
}
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 0);
} }
CAF_TEST(reset) { CAF_TEST(reset) {
{ class0ptr p;
class0ptr p; p.reset(new class0, false);
p.reset(new class0, false); CAF_CHECK_EQUAL(class0_instances, 1);
CAF_CHECK_EQUAL(class0_instances, 1); CAF_CHECK(p->unique());
CAF_CHECK(p->unique());
}
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 0);
} }
CAF_TEST(get_test_rc) { CAF_TEST(get_test_rc) {
{ class0ptr p1;
class0ptr p1; p1 = get_test_rc();
p1 = get_test_rc(); class0ptr p2 = p1;
class0ptr p2 = p1; CAF_CHECK_EQUAL(class0_instances, 1);
CAF_CHECK_EQUAL(class0_instances, 1); CAF_CHECK_EQUAL(p1->unique(), false);
CAF_CHECK_EQUAL(p1->unique(), false);
}
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 0);
} }
CAF_TEST(list) { CAF_TEST(list) {
{ std::vector<class0ptr> pl;
std::list<class0ptr> pl; pl.push_back(get_test_ptr());
pl.push_back(get_test_ptr()); pl.push_back(get_test_rc());
pl.push_back(get_test_rc()); pl.push_back(pl.front()->create());
pl.push_back(pl.front()->create()); CAF_CHECK(pl.front()->unique());
CAF_CHECK(pl.front()->unique()); CAF_CHECK_EQUAL(class0_instances, 3);
CAF_CHECK_EQUAL(class0_instances, 3);
}
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 0);
} }
CAF_TEST(full_test) { CAF_TEST(full_test) {
{ auto p1 = make_counted<class0>();
auto p1 = make_counted<class0>(); CAF_CHECK_EQUAL(p1->is_subtype(), false);
CAF_CHECK_EQUAL(p1->is_subtype(), false); CAF_CHECK_EQUAL(p1->unique(), true);
CAF_CHECK_EQUAL(p1->unique(), true); CAF_CHECK_EQUAL(class0_instances, 1);
CAF_CHECK_EQUAL(class0_instances, 1);
CAF_CHECK_EQUAL(class1_instances, 0);
p1.reset(new class1, false);
CAF_CHECK_EQUAL(p1->is_subtype(), true);
CAF_CHECK_EQUAL(p1->unique(), true);
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 1);
auto p2 = make_counted<class1>();
p1 = p2;
CAF_CHECK_EQUAL(p1->unique(), false);
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 1);
CAF_CHECK(p1 == p2);
}
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 0); CAF_CHECK_EQUAL(class1_instances, 0);
p1.reset(new class1, false);
CAF_CHECK_EQUAL(p1->is_subtype(), true);
CAF_CHECK_EQUAL(p1->unique(), true);
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 1);
auto p2 = make_counted<class1>();
p1 = p2;
CAF_CHECK_EQUAL(p1->unique(), false);
CAF_CHECK_EQUAL(class0_instances, 0);
CAF_CHECK_EQUAL(class1_instances, 1);
CAF_CHECK(p1 == p2);
} }
CAF_TEST_FIXTURE_SCOPE_END()
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#define CAF_SUITE fixed_vector #define CAF_SUITE limited_vector
#include "caf/test/unit_test.hpp" #include "caf/test/unit_test.hpp"
#include <algorithm> #include <algorithm>
...@@ -29,7 +29,7 @@ using std::endl; ...@@ -29,7 +29,7 @@ using std::endl;
using std::equal; using std::equal;
using caf::detail::limited_vector; using caf::detail::limited_vector;
CAF_TEST(limited_vector) { CAF_TEST(basics) {
int arr1[] {1, 2, 3, 4}; int arr1[] {1, 2, 3, 4};
limited_vector<int, 4> vec1 {1, 2, 3, 4}; limited_vector<int, 4> vec1 {1, 2, 3, 4};
limited_vector<int, 5> vec2 {4, 3, 2, 1}; limited_vector<int, 5> vec2 {4, 3, 2, 1};
......
...@@ -36,7 +36,6 @@ using ho_atom = atom_constant<atom("ho")>; ...@@ -36,7 +36,6 @@ using ho_atom = atom_constant<atom("ho")>;
function<optional<string>(const string&)> starts_with(const string& s) { function<optional<string>(const string&)> starts_with(const string& s) {
return [=](const string& str) -> optional<string> { return [=](const string& str) -> optional<string> {
CAF_MESSAGE("starts with guard called");
if (str.size() > s.size() && str.compare(0, s.size(), s) == 0) { if (str.size() > s.size() && str.compare(0, s.size(), s) == 0) {
auto res = str.substr(s.size()); auto res = str.substr(s.size());
return res; return res;
...@@ -104,7 +103,7 @@ function<void()> f(int idx) { ...@@ -104,7 +103,7 @@ function<void()> f(int idx) {
}; };
} }
CAF_TEST(test_atoms) { CAF_TEST(atom_constants) {
auto expr = on(hi_atom::value) >> f(0); auto expr = on(hi_atom::value) >> f(0);
CAF_CHECK_EQUAL(invoked(expr, hi_atom::value), 0); CAF_CHECK_EQUAL(invoked(expr, hi_atom::value), 0);
CAF_CHECK_EQUAL(invoked(expr, ho_atom::value), -1); CAF_CHECK_EQUAL(invoked(expr, ho_atom::value), -1);
...@@ -122,44 +121,41 @@ CAF_TEST(test_atoms) { ...@@ -122,44 +121,41 @@ CAF_TEST(test_atoms) {
CAF_CHECK_EQUAL(invoked(expr2, ho_atom::value), 1); CAF_CHECK_EQUAL(invoked(expr2, ho_atom::value), 1);
} }
CAF_TEST(test_custom_projections) { CAF_TEST(guards_called) {
// check whether projection is called bool guard_called = false;
{ auto guard = [&](int arg) -> optional<int> {
bool guard_called = false; guard_called = true;
auto guard = [&](int arg) -> optional<int> { return arg;
guard_called = true; };
return arg; auto expr = on(guard) >> f(0);
}; CAF_CHECK_EQUAL(invoked(expr, 42), 0);
auto expr = on(guard) >> f(0); CAF_CHECK_EQUAL(guard_called, true);
CAF_CHECK_EQUAL(invoked(expr, 42), 0); }
CAF_CHECK_EQUAL(guard_called, true);
} CAF_TEST(forwarding_optionals) {
// check forwarding optional<const string&> from guard auto expr = (
{ on(starts_with("--")) >> [](const string& str) {
auto expr = ( CAF_CHECK_EQUAL(str, "help");
on(starts_with("--")) >> [](const string& str) { s_invoked[0] = true;
CAF_CHECK_EQUAL(str, "help"); }
s_invoked[0] = true; );
} CAF_CHECK_EQUAL(invoked(expr, "--help"), 0);
); CAF_CHECK_EQUAL(invoked(expr, "-help"), -1);
CAF_CHECK_EQUAL(invoked(expr, "--help"), 0); CAF_CHECK_EQUAL(invoked(expr, "--help", "--help"), -1);
CAF_CHECK_EQUAL(invoked(expr, "-help"), -1); CAF_CHECK_EQUAL(invoked(expr, 42), -1);
CAF_CHECK_EQUAL(invoked(expr, "--help", "--help"), -1); }
CAF_CHECK_EQUAL(invoked(expr, 42), -1);
} CAF_TEST(projections) {
// check projection auto expr = (
{ on(toint) >> [](int i) {
auto expr = ( CAF_CHECK_EQUAL(i, 42);
on(toint) >> [](int i) { s_invoked[0] = true;
CAF_CHECK_EQUAL(i, 42); }
s_invoked[0] = true; );
} CAF_CHECK_EQUAL(invoked(expr, "42"), 0);
); CAF_CHECK_EQUAL(invoked(expr, "42f"), -1);
CAF_CHECK_EQUAL(invoked(expr, "42"), 0); CAF_CHECK_EQUAL(invoked(expr, "42", "42"), -1);
CAF_CHECK_EQUAL(invoked(expr, "42f"), -1); CAF_CHECK_EQUAL(invoked(expr, 42), -1);
CAF_CHECK_EQUAL(invoked(expr, "42", "42"), -1);
CAF_CHECK_EQUAL(invoked(expr, 42), -1);
}
} }
struct wrapped_int { struct wrapped_int {
...@@ -170,7 +166,7 @@ inline bool operator==(const wrapped_int& lhs, const wrapped_int& rhs) { ...@@ -170,7 +166,7 @@ inline bool operator==(const wrapped_int& lhs, const wrapped_int& rhs) {
return lhs.value == rhs.value; return lhs.value == rhs.value;
} }
CAF_TEST(test_arg_match) { CAF_TEST(arg_match_pattern) {
announce<wrapped_int>("wrapped_int", &wrapped_int::value); announce<wrapped_int>("wrapped_int", &wrapped_int::value);
auto expr = on(42, arg_match) >> [](int i) { auto expr = on(42, arg_match) >> [](int i) {
s_invoked[0] = true; s_invoked[0] = true;
...@@ -196,5 +192,4 @@ CAF_TEST(test_arg_match) { ...@@ -196,5 +192,4 @@ CAF_TEST(test_arg_match) {
CAF_CHECK_EQUAL(invoked(expr3, wrapped_int{1}, wrapped_int{42}), -1); CAF_CHECK_EQUAL(invoked(expr3, wrapped_int{1}, wrapped_int{42}), -1);
CAF_CHECK_EQUAL(invoked(expr3, 42, 1), -1); CAF_CHECK_EQUAL(invoked(expr3, 42, 1), -1);
CAF_CHECK_EQUAL(invoked(expr3, wrapped_int{42}, wrapped_int{1}), 0); CAF_CHECK_EQUAL(invoked(expr3, wrapped_int{42}, wrapped_int{1}), 0);
shutdown();
} }
...@@ -27,7 +27,7 @@ using std::cout; ...@@ -27,7 +27,7 @@ using std::cout;
using std::endl; using std::endl;
using namespace caf; using namespace caf;
CAF_TEST(test_drop) { CAF_TEST(drop) {
auto m1 = make_message(1, 2, 3, 4, 5); auto m1 = make_message(1, 2, 3, 4, 5);
std::vector<message> messages{ std::vector<message> messages{
m1, m1,
...@@ -42,13 +42,13 @@ CAF_TEST(test_drop) { ...@@ -42,13 +42,13 @@ CAF_TEST(test_drop) {
} }
} }
CAF_TEST(test_slice) { CAF_TEST(slice) {
auto m1 = make_message(1, 2, 3, 4, 5); auto m1 = make_message(1, 2, 3, 4, 5);
auto m2 = m1.slice(2, 2); auto m2 = m1.slice(2, 2);
CAF_CHECK_EQUAL(to_string(m2), to_string(make_message(3, 4))); CAF_CHECK_EQUAL(to_string(m2), to_string(make_message(3, 4)));
} }
CAF_TEST(test_extract1) { CAF_TEST(extract1) {
auto f = [](int lhs1, int lhs2, int lhs3, int rhs1, int rhs2, int val) { auto f = [](int lhs1, int lhs2, int lhs3, int rhs1, int rhs2, int val) {
auto m1 = make_message(lhs1, lhs2, lhs3); auto m1 = make_message(lhs1, lhs2, lhs3);
auto m2 = make_message(rhs1, rhs2); auto m2 = make_message(rhs1, rhs2);
...@@ -60,7 +60,7 @@ CAF_TEST(test_extract1) { ...@@ -60,7 +60,7 @@ CAF_TEST(test_extract1) {
f(1, 2, 3, 1, 2, 3); f(1, 2, 3, 1, 2, 3);
} }
CAF_TEST(test_extract2) { CAF_TEST(extract2) {
auto m1 = make_message(1.0, 2.0, 3.0); auto m1 = make_message(1.0, 2.0, 3.0);
auto m2 = make_message(1, 2, 1.0, 2.0, 3.0); auto m2 = make_message(1, 2, 1.0, 2.0, 3.0);
auto m3 = make_message(1.0, 1, 2, 2.0, 3.0); auto m3 = make_message(1.0, 1, 2, 2.0, 3.0);
...@@ -80,7 +80,7 @@ CAF_TEST(test_extract2) { ...@@ -80,7 +80,7 @@ CAF_TEST(test_extract2) {
CAF_CHECK_EQUAL(to_string(m7.extract(f)), to_string(m1)); CAF_CHECK_EQUAL(to_string(m7.extract(f)), to_string(m1));
} }
CAF_TEST(test_extract3) { CAF_TEST(extract3) {
auto m1 = make_message(1); auto m1 = make_message(1);
CAF_CHECK_EQUAL(to_string(m1.extract([](int) {})), to_string(message{})); CAF_CHECK_EQUAL(to_string(m1.extract([](int) {})), to_string(message{}));
auto m2 = make_message(1.0, 2, 3, 4.0); auto m2 = make_message(1.0, 2, 3, 4.0);
...@@ -92,7 +92,7 @@ CAF_TEST(test_extract3) { ...@@ -92,7 +92,7 @@ CAF_TEST(test_extract3) {
CAF_CHECK_EQUAL(to_string(m3), to_string(make_message(1.0, 4.0))); CAF_CHECK_EQUAL(to_string(m3), to_string(make_message(1.0, 4.0)));
} }
CAF_TEST(test_extract_opts) { CAF_TEST(extract_opts) {
auto f = [](std::vector<std::string> xs) { auto f = [](std::vector<std::string> xs) {
std::string filename; std::string filename;
auto res = message_builder(xs.begin(), xs.end()).extract_opts({ auto res = message_builder(xs.begin(), xs.end()).extract_opts({
...@@ -108,12 +108,12 @@ CAF_TEST(test_extract_opts) { ...@@ -108,12 +108,12 @@ CAF_TEST(test_extract_opts) {
f({"-f", "hello.txt"}); f({"-f", "hello.txt"});
} }
CAF_TEST(test_type_token) { CAF_TEST(type_token) {
auto m1 = make_message(get_atom::value); auto m1 = make_message(get_atom::value);
CAF_CHECK_EQUAL(m1.type_token(), detail::make_type_token<get_atom>()); CAF_CHECK_EQUAL(m1.type_token(), detail::make_type_token<get_atom>());
} }
CAF_TEST(test_concat) { CAF_TEST(concat) {
auto m1 = make_message(get_atom::value); auto m1 = make_message(get_atom::value);
auto m2 = make_message(uint32_t{1}); auto m2 = make_message(uint32_t{1});
auto m3 = message::concat(m1, m2); auto m3 = message::concat(m1, m2);
......
...@@ -31,13 +31,6 @@ using namespace caf; ...@@ -31,13 +31,6 @@ using namespace caf;
namespace { namespace {
struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
}
};
class testee : public event_based_actor { class testee : public event_based_actor {
public: public:
testee(); testee();
...@@ -111,6 +104,13 @@ void test_message_lifetime() { ...@@ -111,6 +104,13 @@ void test_message_lifetime() {
} }
} }
struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
}
};
} // namespace <anonymous> } // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(message_lifetime_tests, fixture) CAF_TEST_FIXTURE_SCOPE(message_lifetime_tests, fixture)
......
...@@ -45,7 +45,7 @@ struct is_int : std::false_type {}; ...@@ -45,7 +45,7 @@ struct is_int : std::false_type {};
template <> template <>
struct is_int<int> : std::true_type {}; struct is_int<int> : std::true_type {};
CAF_TEST(test_metaprogramming) { CAF_TEST(metaprogramming) {
using if1 = type_list<replies_to<int, double>::with<void>, using if1 = type_list<replies_to<int, double>::with<void>,
replies_to<int>::with<int>>; replies_to<int>::with<int>>;
using if2 = type_list<replies_to<int>::with<int>, using if2 = type_list<replies_to<int>::with<int>,
...@@ -93,5 +93,4 @@ CAF_TEST(test_metaprogramming) { ...@@ -93,5 +93,4 @@ CAF_TEST(test_metaprogramming) {
CAF_CHECK((tl_is_strict_subset<list_a, list_a>::value)); CAF_CHECK((tl_is_strict_subset<list_a, list_a>::value));
CAF_CHECK((tl_is_strict_subset<list_b, list_b>::value)); CAF_CHECK((tl_is_strict_subset<list_b, list_b>::value));
} }
shutdown();
} }
...@@ -27,46 +27,57 @@ ...@@ -27,46 +27,57 @@
using namespace std; using namespace std;
using namespace caf; using namespace caf;
CAF_TEST(test_optional) { CAF_TEST(empties) {
{ optional<int> i;
optional<int> i,j; optional<int> j;
CAF_CHECK(i == j); CAF_CHECK(i == j);
CAF_CHECK(!(i != j)); CAF_CHECK(!(i != j));
} }
{
optional<int> i = 5; CAF_TEST(unequal) {
optional<int> j = 6; optional<int> i = 5;
CAF_CHECK(!(i == j)); optional<int> j = 6;
CAF_CHECK(i != j); CAF_CHECK(!(i == j));
} CAF_CHECK(i != j);
{ }
optional<int> i;
optional<double> j; CAF_TEST(distinct_types) {
CAF_CHECK(i == j); optional<int> i;
CAF_CHECK(!(i != j)); optional<double> j;
} CAF_CHECK(i == j);
{ CAF_CHECK(!(i != j));
struct qwertz { }
qwertz(int i, int j) : m_i(i), m_j(j) {
CAF_MESSAGE("called ctor of `qwertz`"); struct qwertz {
} qwertz(int i, int j) : m_i(i), m_j(j) {
int m_i; // nop
int m_j;
};
{
optional<qwertz> i;
CAF_CHECK(i.empty());
}
{
qwertz obj (1,2);
optional<qwertz> j(obj);
CAF_CHECK(!j.empty());
}
{
optional<qwertz> i = qwertz(1,2);
CAF_CHECK(!i.empty());
optional<qwertz> j = { { 1, 2 } };
CAF_CHECK(!j.empty());
}
} }
int m_i;
int m_j;
};
inline bool operator==(const qwertz& lhs, const qwertz& rhs) {
return lhs.m_i == rhs.m_i && lhs.m_j == rhs.m_j;
}
CAF_TEST(custom_type_none) {
optional<qwertz> i;
CAF_CHECK(i == none);
}
CAF_TEST(custom_type_engaged) {
qwertz obj{1, 2};
optional<qwertz> j = obj;
CAF_CHECK(j != none);
CAF_CHECK(obj == j);
CAF_CHECK(j == obj );
CAF_CHECK(obj == *j);
CAF_CHECK(*j == obj);
}
CAF_TEST(test_optional) {
optional<qwertz> i = qwertz(1,2);
CAF_CHECK(!i.empty());
optional<qwertz> j = { { 1, 2 } };
CAF_CHECK(!j.empty());
} }
...@@ -24,52 +24,69 @@ ...@@ -24,52 +24,69 @@
using namespace caf; using namespace caf;
CAF_TEST(test_or_else) { namespace {
{
scoped_actor self;
message_handler handle_a {
on("a") >> [] { return 1; }
};
message_handler handle_b {
on("b") >> [] { return 2; }
};
message_handler handle_c {
on("c") >> [] { return 3; }
};
auto run_testee([&](actor testee) {
self->sync_send(testee, "a").await([](int i) {
CAF_CHECK_EQUAL(i, 1);
});
self->sync_send(testee, "b").await([](int i) {
CAF_CHECK_EQUAL(i, 2);
});
self->sync_send(testee, "c").await([](int i) {
CAF_CHECK_EQUAL(i, 3);
});
self->send_exit(testee, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}); message_handler handle_a() {
CAF_MESSAGE("run_testee: handle_a.or_else(handle_b).or_else(handle_c)"); return on("a") >> [] { return 1; };
run_testee( }
spawn([=] {
return handle_a.or_else(handle_b).or_else(handle_c); message_handler handle_b() {
}) return on("b") >> [] { return 2; };
); }
CAF_MESSAGE("run_testee: handle_a.or_else(handle_b), on(\"c\") ...");
run_testee( message_handler handle_c() {
spawn([=] { return on("c") >> [] { return 3; };
return handle_a.or_else(handle_b).or_else(on("c") >> [] { return 3; }); }
})
); void run_testee(actor testee) {
CAF_MESSAGE("run_testee: on(\"a\") ..., handle_b.or_else(handle_c)"); scoped_actor self;
run_testee( self->sync_send(testee, "a").await([](int i) {
spawn([=] { CAF_CHECK_EQUAL(i, 1);
return message_handler{on("a") >> [] { return 1; }}. });
or_else(handle_b).or_else(handle_c); self->sync_send(testee, "b").await([](int i) {
}) CAF_CHECK_EQUAL(i, 2);
); });
self->sync_send(testee, "c").await([](int i) {
CAF_CHECK_EQUAL(i, 3);
});
self->send_exit(testee, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}
struct fixture {
~fixture() {
await_all_actors_done();
shutdown();
} }
await_all_actors_done(); };
shutdown();
} // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(atom_tests, fixture)
CAF_TEST(composition1) {
run_testee(
spawn([=] {
return handle_a().or_else(handle_b()).or_else(handle_c());
})
);
}
CAF_TEST(composition2) {
run_testee(
spawn([=] {
return handle_a().or_else(handle_b()).or_else(on("c") >> [] { return 3; });
})
);
}
CAF_TEST(composition3) {
run_testee(
spawn([=] {
return message_handler{on("a") >> [] { return 1; }}.
or_else(handle_b()).or_else(handle_c());
})
);
} }
CAF_TEST_FIXTURE_SCOPE_END()
...@@ -44,7 +44,7 @@ std::string str_hash(const std::string& what) { ...@@ -44,7 +44,7 @@ std::string str_hash(const std::string& what) {
// verify ripemd implementation with example hash results from // verify ripemd implementation with example hash results from
// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html // http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
CAF_TEST(test_ripemd_160) { CAF_TEST(hash_results) {
CAF_CHECK_EQUAL("9c1185a5c5e9fc54612808977ee8f548b2258d31", str_hash("")); CAF_CHECK_EQUAL("9c1185a5c5e9fc54612808977ee8f548b2258d31", str_hash(""));
CAF_CHECK_EQUAL("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", str_hash("a")); CAF_CHECK_EQUAL("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", str_hash("a"));
CAF_CHECK_EQUAL("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", str_hash("abc")); CAF_CHECK_EQUAL("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", str_hash("abc"));
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
using namespace caf; using namespace caf;
CAF_TEST(test_simple_reply_response) { CAF_TEST(simple_reply_response) {
auto s = spawn([](event_based_actor* self) -> behavior { auto s = spawn([](event_based_actor* self) -> behavior {
return ( return (
others >> [=]() -> message { others >> [=]() -> message {
......
This diff is collapsed.
This diff is collapsed.
...@@ -244,18 +244,28 @@ behavior foo2(event_based_actor* self) { ...@@ -244,18 +244,28 @@ behavior foo2(event_based_actor* self) {
}; };
} }
struct fixture {
fixture() {
announce<get_state_msg>("get_state_msg");
announce<int_actor>("int_actor");
announce<my_request>("my_request", &my_request::a, &my_request::b);
}
~fixture() {
await_all_actors_done();
shutdown();
}
};
} // namespace <anonymous> } // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(typed_spawn_tests, fixture)
/****************************************************************************** /******************************************************************************
* put it all together * * put it all together *
******************************************************************************/ ******************************************************************************/
CAF_TEST(test_typed_spawns) { CAF_TEST(typed_spawns) {
// announce stuff
announce<get_state_msg>("get_state_msg");
announce<int_actor>("int_actor");
announce<my_request>("my_request", &my_request::a, &my_request::b);
// run test series with typed_server(1|2) // run test series with typed_server(1|2)
test_typed_spawn(spawn_typed(typed_server1)); test_typed_spawn(spawn_typed(typed_server1));
await_all_actors_done(); await_all_actors_done();
...@@ -271,88 +281,75 @@ CAF_TEST(test_typed_spawns) { ...@@ -271,88 +281,75 @@ CAF_TEST(test_typed_spawns) {
CAF_MESSAGE("received \"hi there\""); CAF_MESSAGE("received \"hi there\"");
}); });
} }
await_all_actors_done();
CAF_MESSAGE("finished test series with `typed_server3`");
} }
CAF_TEST(test_event_testee) { CAF_TEST(test_event_testee) {
// run test series with event_testee // run test series with event_testee
{ scoped_actor self;
scoped_actor self; auto et = self->spawn_typed<event_testee>();
auto et = self->spawn_typed<event_testee>(); string result;
string result; self->send(et, 1);
self->send(et, 1); self->send(et, 2);
self->send(et, 2); self->send(et, 3);
self->send(et, 3); self->send(et, .1f);
self->send(et, .1f); self->send(et, "hello event testee!");
self->send(et, "hello event testee!"); self->send(et, .2f);
self->send(et, .2f); self->send(et, .3f);
self->send(et, .3f); self->send(et, "hello again event testee!");
self->send(et, "hello again event testee!"); self->send(et, "goodbye event testee!");
self->send(et, "goodbye event testee!"); typed_actor<replies_to<get_state_msg>::with<string>> sub_et = et;
typed_actor<replies_to<get_state_msg>::with<string>> sub_et = et; // $:: is the anonymous namespace
// $:: is the anonymous namespace set<string> iface{"caf::replies_to<get_state_msg>::with<@str>",
set<string> iface{"caf::replies_to<get_state_msg>::with<@str>", "caf::replies_to<@str>::with<void>",
"caf::replies_to<@str>::with<void>", "caf::replies_to<float>::with<void>",
"caf::replies_to<float>::with<void>", "caf::replies_to<@i32>::with<@i32>"};
"caf::replies_to<@i32>::with<@i32>"}; CAF_CHECK_EQUAL(join(sub_et->message_types(), ","), join(iface, ","));
CAF_CHECK_EQUAL(join(sub_et->message_types(), ","), join(iface, ",")); self->send(sub_et, get_state_msg{});
self->send(sub_et, get_state_msg{}); // we expect three 42s
// we expect three 42s int i = 0;
int i = 0; self->receive_for(i, 3)([](int value) { CAF_CHECK_EQUAL(value, 42); });
self->receive_for(i, 3)([](int value) { CAF_CHECK_EQUAL(value, 42); }); self->receive(
self->receive( [&](const string& str) {
[&](const string& str) { result = str;
result = str; },
}, after(chrono::minutes(1)) >> [&] {
after(chrono::minutes(1)) >> [&] { CAF_TEST_ERROR("event_testee does not reply");
CAF_TEST_ERROR("event_testee does not reply"); throw runtime_error("event_testee does not reply");
throw runtime_error("event_testee does not reply"); }
} );
); self->send_exit(et, exit_reason::user_shutdown);
self->send_exit(et, exit_reason::user_shutdown); self->await_all_other_actors_done();
self->await_all_other_actors_done(); CAF_CHECK_EQUAL(result, "wait4int");
CAF_CHECK_EQUAL(result, "wait4int");
self->await_all_other_actors_done();
}
} }
CAF_TEST(test_simple_string_reverter) { CAF_TEST(test_simple_string_reverter) {
// run test series with string reverter // run test series with string reverter
{ scoped_actor self;
scoped_actor self; // actor-under-test
// actor-under-test auto aut = self->spawn_typed<monitored>(simple_relay,
auto aut = self->spawn_typed<monitored>(simple_relay, spawn_typed(simple_string_reverter),
spawn_typed(simple_string_reverter), true);
true); set<string> iface{"caf::replies_to<@str>::with<@str>"};
set<string> iface{"caf::replies_to<@str>::with<@str>"}; CAF_CHECK(aut->message_types() == iface);
CAF_CHECK(aut->message_types() == iface); self->sync_send(aut, "Hello World!").await([](const string& answer) {
self->sync_send(aut, "Hello World!").await([](const string& answer) { CAF_CHECK_EQUAL(answer, "!dlroW olleH");
CAF_CHECK_EQUAL(answer, "!dlroW olleH"); });
}); anon_send_exit(aut, exit_reason::user_shutdown);
anon_send_exit(aut, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}
} }
CAF_TEST(test_sending_typed_actors) { CAF_TEST(test_sending_typed_actors) {
{ scoped_actor self;
scoped_actor self; auto aut = spawn_typed(int_fun);
auto aut = spawn_typed(int_fun); self->send(spawn(foo), 10, aut);
self->send(spawn(foo), 10, aut); self->receive(on_arg_match >> [](int i) { CAF_CHECK_EQUAL(i, 100); });
self->receive(on_arg_match >> [](int i) { CAF_CHECK_EQUAL(i, 100); }); self->send_exit(aut, exit_reason::user_shutdown);
self->send_exit(aut, exit_reason::user_shutdown);
self->await_all_other_actors_done();
}
} }
CAF_TEST(test_sending_typed_actors_and_down_msg) { CAF_TEST(test_sending_typed_actors_and_down_msg) {
{ scoped_actor self;
scoped_actor self; auto aut = spawn_typed(int_fun2);
auto aut = spawn_typed(int_fun2); self->send(spawn(foo2), 10, aut);
self->send(spawn(foo2), 10, aut); self->receive([](int i) { CAF_CHECK_EQUAL(i, 100); });
self->receive([](int i) { CAF_CHECK_EQUAL(i, 100); });
self->await_all_other_actors_done();
}
shutdown();
} }
CAF_TEST_FIXTURE_SCOPE_END()
...@@ -34,12 +34,12 @@ struct tostring_visitor : static_visitor<string> { ...@@ -34,12 +34,12 @@ struct tostring_visitor : static_visitor<string> {
} }
}; };
CAF_TEST(variant) { CAF_TEST(string_convertible) {
tostring_visitor tv; tostring_visitor tv;
// test never-empty guarantee, i.e., expect default-constucted first arg // test never-empty guarantee, i.e., expect default-constucted first arg
variant<int,float> v1; variant<int, float> v1;
CAF_CHECK_EQUAL(apply_visitor(tv, v1), "0"); CAF_CHECK_EQUAL(apply_visitor(tv, v1), "0");
variant<int,float> v2 = 42; variant<int, float> v2 = 42;
CAF_CHECK_EQUAL(apply_visitor(tv, v2), "42"); CAF_CHECK_EQUAL(apply_visitor(tv, v2), "42");
v2 = 0.2f; v2 = 0.2f;
CAF_CHECK_EQUAL(apply_visitor(tv, v2), to_string(0.2f)); CAF_CHECK_EQUAL(apply_visitor(tv, v2), to_string(0.2f));
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <iostream>
#include "ping_pong.hpp"
#include "caf/all.hpp"
#include "caf/detail/logging.hpp"
#include "caf/test/unit_test.hpp"
using std::cout;
using std::endl;
using namespace caf;
using namespace caf;
namespace {
size_t s_pongs = 0;
behavior ping_behavior(local_actor* self, size_t num_pings) {
return {
on(atom("pong"), arg_match) >> [=](int value)->message {
if (!self->current_sender()) {
CAF_TEST_ERROR("current_sender() invalid!");
}
CAF_TEST_INFO("received {'pong', " << value << "}");
// cout << to_string(self->current_message()) << endl;
if (++s_pongs >= num_pings) {
CAF_TEST_INFO("reached maximum, send {'EXIT', user_defined} "
<< "to last sender and quit with normal reason");
self->send_exit(self->current_sender(),
exit_reason::user_shutdown);
self->quit();
}
return make_message(atom("ping"), value);
},
others() >> [=] {
self->quit(exit_reason::user_shutdown);
}
};
}
behavior pong_behavior(local_actor* self) {
return {
on(atom("ping"), arg_match) >> [](int value)->message {
return make_message(atom("pong"), value + 1);
},
others() >> [=] {
self->quit(exit_reason::user_shutdown);
}
};
}
} // namespace <anonymous>
size_t pongs() { return s_pongs; }
void ping(blocking_actor* self, size_t num_pings) {
s_pongs = 0;
self->receive_loop(ping_behavior(self, num_pings));
}
void event_based_ping(event_based_actor* self, size_t num_pings) {
s_pongs = 0;
self->become(ping_behavior(self, num_pings));
}
void pong(blocking_actor* self, actor ping_actor) {
self->send(ping_actor, atom("pong"), 0); // kickoff
self->receive_loop(pong_behavior(self));
}
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef PING_PONG_HPP
#define PING_PONG_HPP
//#include "caf/actor.hpp"
#include <cstddef>
#include "caf/fwd.hpp"
void ping(caf::blocking_actor*, size_t num_pings);
void event_based_ping(caf::event_based_actor*, size_t num_pings);
void pong(caf::blocking_actor*, caf::actor ping_actor);
// returns the number of messages ping received
size_t pongs();
#endif // PING_PONG_HPP
...@@ -34,8 +34,6 @@ ...@@ -34,8 +34,6 @@
#include "caf/detail/singletons.hpp" #include "caf/detail/singletons.hpp"
#include "caf/detail/run_program.hpp" #include "caf/detail/run_program.hpp"
#include "../libcaf_io/test/ping_pong.hpp"
using namespace std; using namespace std;
using namespace caf; using namespace caf;
...@@ -56,6 +54,56 @@ atomic<long> s_on_exit_called; ...@@ -56,6 +54,56 @@ atomic<long> s_on_exit_called;
constexpr size_t num_pings = 10; constexpr size_t num_pings = 10;
size_t s_pongs = 0;
behavior ping_behavior(local_actor* self, size_t num_pings) {
return {
on(atom("pong"), arg_match) >> [=](int value)->message {
if (!self->current_sender()) {
CAF_TEST_ERROR("current_sender() invalid!");
}
CAF_TEST_INFO("received {'pong', " << value << "}");
// cout << to_string(self->current_message()) << endl;
if (++s_pongs >= num_pings) {
CAF_TEST_INFO("reached maximum, send {'EXIT', user_defined} "
<< "to last sender and quit with normal reason");
self->send_exit(self->current_sender(),
exit_reason::user_shutdown);
self->quit();
}
return make_message(atom("ping"), value);
},
others() >> [=] {
self->quit(exit_reason::user_shutdown);
}
};
}
behavior pong_behavior(local_actor* self) {
return {
on(atom("ping"), arg_match) >> [](int value)->message {
return make_message(atom("pong"), value + 1);
},
others() >> [=] {
self->quit(exit_reason::user_shutdown);
}
};
}
size_t pongs() {
return s_pongs;
}
void event_based_ping(event_based_actor* self, size_t num_pings) {
s_pongs = 0;
self->become(ping_behavior(self, num_pings));
}
void pong(blocking_actor* self, actor ping_actor) {
self->send(ping_actor, atom("pong"), 0); // kickoff
self->receive_loop(pong_behavior(self));
}
using string_pair = std::pair<std::string, std::string>; using string_pair = std::pair<std::string, std::string>;
using actor_vector = vector<actor>; using actor_vector = vector<actor>;
......
...@@ -55,25 +55,24 @@ void test_invalid_unpublish(const actor& published, uint16_t port) { ...@@ -55,25 +55,24 @@ void test_invalid_unpublish(const actor& published, uint16_t port) {
anon_send_exit(d, exit_reason::user_shutdown); anon_send_exit(d, exit_reason::user_shutdown);
} }
CAF_TEST(test_unpublish) { CAF_TEST(unpublishing) {
auto d = spawn<dummy>(); { // scope for local variables
auto port = io::publish(d, 0); auto d = spawn<dummy>();
CAF_MESSAGE("published actor on port " << port); auto port = io::publish(d, 0);
test_invalid_unpublish(d, port); CAF_MESSAGE("published actor on port " << port);
CAF_MESSAGE("finished `invalid_unpublish`"); test_invalid_unpublish(d, port);
io::unpublish(d, port); CAF_MESSAGE("finished `invalid_unpublish`");
// must fail now io::unpublish(d, port);
try { // must fail now
CAF_MESSAGE("expect exception..."); try {
io::remote_actor("127.0.0.1", port); CAF_MESSAGE("expect exception...");
CAF_TEST_ERROR("unexpected: remote actor succeeded!"); io::remote_actor("127.0.0.1", port);
} catch (network_error&) { CAF_TEST_ERROR("unexpected: remote actor succeeded!");
CAF_MESSAGE("unpublish succeeded"); } catch (network_error&) {
CAF_MESSAGE("unpublish succeeded");
}
anon_send_exit(d, exit_reason::user_shutdown);
} }
anon_send_exit(d, exit_reason::user_shutdown);
}
CAF_TEST(test_dtor_called) {
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
CAF_CHECK_EQUAL(s_dtor_called.load(), 2); CAF_CHECK_EQUAL(s_dtor_called.load(), 2);
......
...@@ -36,14 +36,6 @@ namespace caf { ...@@ -36,14 +36,6 @@ namespace caf {
class message; class message;
namespace test { namespace test {
/**
* A sequence of *checks*.
*/
class check_sequence {
virtual ~check_sequence();
virtual void run() = 0;
};
/** /**
* A sequence of *checks*. * A sequence of *checks*.
*/ */
...@@ -69,9 +61,7 @@ class test { ...@@ -69,9 +61,7 @@ class test {
return m_bad; return m_bad;
} }
void run(); virtual void run() = 0;
virtual std::unique_ptr<check_sequence> make_sequence() = 0;
private: private:
size_t m_expected_failures; size_t m_expected_failures;
...@@ -82,6 +72,19 @@ class test { ...@@ -82,6 +72,19 @@ class test {
struct dummy_fixture { }; struct dummy_fixture { };
template <class T>
class test_impl : public test {
public:
test_impl(std::string name) : test(std::move(name)) {
// nop
}
virtual void run() override {
T impl;
impl.run();
}
};
namespace detail { namespace detail {
// thrown when a required check fails // thrown when a required check fails
...@@ -311,8 +314,8 @@ namespace detail { ...@@ -311,8 +314,8 @@ namespace detail {
template <class T> template <class T>
struct adder { struct adder {
adder(char const* name) { adder(const char* suite_name, const char* test_name) {
engine::add(name, [] { return std::unique_ptr<T>{new T}; }); engine::add(suite_name, std::unique_ptr<T>{new T(test_name)});
} }
}; };
...@@ -606,13 +609,11 @@ using caf_test_case_auto_fixture = caf::test::dummy_fixture; ...@@ -606,13 +609,11 @@ using caf_test_case_auto_fixture = caf::test::dummy_fixture;
#define CAF_TEST(name) \ #define CAF_TEST(name) \
namespace { \ namespace { \
struct CAF_UNIQUE(test) : public ::caf::test::test { \ struct CAF_UNIQUE(test) : caf_test_case_auto_fixture { \
CAF_UNIQUE(test)() : test{CAF_XSTR(name)} { } \ void run(); \
void run() final; \
}; \
::caf::test::detail::adder<CAF_UNIQUE(test)> CAF_UNIQUE(a) { \
CAF_XSTR(CAF_SUITE) \
}; \ }; \
::caf::test::detail::adder<::caf::test::test_impl<CAF_UNIQUE(test)>> \
CAF_UNIQUE(a) {CAF_XSTR(CAF_SUITE), CAF_XSTR(name)}; \
} /* namespace <anonymous> */ \ } /* namespace <anonymous> */ \
void CAF_UNIQUE(test)::run() void CAF_UNIQUE(test)::run()
...@@ -620,7 +621,7 @@ using caf_test_case_auto_fixture = caf::test::dummy_fixture; ...@@ -620,7 +621,7 @@ using caf_test_case_auto_fixture = caf::test::dummy_fixture;
namespace scope_name { using caf_test_case_auto_fixture = fixture_name ; namespace scope_name { using caf_test_case_auto_fixture = fixture_name ;
#define CAF_TEST_FIXTURE_SCOPE_END() \ #define CAF_TEST_FIXTURE_SCOPE_END() \
} // close namespace } // namespace <scope_name>
// Boost Test compatibility macro // Boost Test compatibility macro
#define CAF_CHECK_EQUAL(x, y) CAF_CHECK(x == y) #define CAF_CHECK_EQUAL(x, y) CAF_CHECK(x == y)
......
...@@ -81,10 +81,6 @@ void watchdog::stop() { ...@@ -81,10 +81,6 @@ void watchdog::stop() {
delete s_watchdog; delete s_watchdog;
} }
check_sequence::~check_sequence() {
// nop
}
test::test(std::string test_name) test::test(std::string test_name)
: m_expected_failures(0), : m_expected_failures(0),
m_name(std::move(test_name)), m_name(std::move(test_name)),
...@@ -118,11 +114,6 @@ const std::string& test::name() const { ...@@ -118,11 +114,6 @@ const std::string& test::name() const {
return m_name; return m_name;
} }
void test::run() {
auto runner = make_sequence();
runner->run();
}
namespace detail { namespace detail {
require_error::require_error(const std::string& msg) : std::logic_error(msg) { require_error::require_error(const std::string& msg) : std::logic_error(msg) {
...@@ -359,8 +350,7 @@ bool engine::run(bool colorize, ...@@ -359,8 +350,7 @@ bool engine::run(bool colorize,
auto pad = std::string((bar.size() - suite_name.size()) / 2, ' '); auto pad = std::string((bar.size() - suite_name.size()) / 2, ' ');
bool displayed_header = false; bool displayed_header = false;
size_t tests_ran = 0; size_t tests_ran = 0;
for (auto& generator : p.second) { for (auto& t : p.second) {
auto t = generator();
if (!enabled(tests, not_tests, t->name())) { if (!enabled(tests, not_tests, t->name())) {
continue; continue;
} }
......
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