Commit 95554bc0 authored by Dominik Charousset's avatar Dominik Charousset

Fix disallow in the testing DSL

parent 4dda7d9a
...@@ -152,16 +152,21 @@ private: ...@@ -152,16 +152,21 @@ private:
// -- unified access to all actor handles in CAF ------------------------------- // -- unified access to all actor handles in CAF -------------------------------
/// Reduces any of CAF's handle types to an `abstract_actor` pointer. /// Reduces any of CAF's handle types to an `abstract_actor` pointer.
class caf_handle { class caf_handle : caf::detail::comparable<caf_handle>,
caf::detail::comparable<caf_handle, std::nullptr_t> {
public: public:
using pointer = caf::abstract_actor*; using pointer = caf::abstract_actor*;
constexpr caf_handle() : ptr_(nullptr) {
// nop
}
template <class T> template <class T>
caf_handle(const T& x) { caf_handle(const T& x) {
*this = x; *this = x;
} }
caf_handle& operator=(caf::abstract_actor* x) { inline caf_handle& operator=(caf::abstract_actor* x) {
ptr_ = x; ptr_ = x;
return *this; return *this;
} }
...@@ -175,15 +180,20 @@ public: ...@@ -175,15 +180,20 @@ public:
caf_handle& operator=(const caf_handle&) = default; caf_handle& operator=(const caf_handle&) = default;
pointer get() const { inline pointer get() const {
return ptr_; return ptr_;
} }
private: inline ptrdiff_t compare(const caf_handle& other) const {
caf_handle() : ptr_(nullptr) { return reinterpret_cast<ptrdiff_t>(ptr_)
// nop - reinterpret_cast<ptrdiff_t>(other.ptr_);
}
inline ptrdiff_t compare(std::nullptr_t) const {
return reinterpret_cast<ptrdiff_t>(ptr_);
} }
private:
caf::abstract_actor* ptr_; caf::abstract_actor* ptr_;
}; };
...@@ -192,7 +202,7 @@ private: ...@@ -192,7 +202,7 @@ private:
/// Returns a pointer to the next element in an actor's mailbox without taking /// Returns a pointer to the next element in an actor's mailbox without taking
/// it out of the mailbox. /// it out of the mailbox.
/// @pre `ptr` is alive and either a `scheduled_actor` or `blocking_actor` /// @pre `ptr` is alive and either a `scheduled_actor` or `blocking_actor`
caf::mailbox_element* next_mailbox_element(caf_handle x) { inline caf::mailbox_element* next_mailbox_element(caf_handle x) {
CAF_ASSERT(x.get() != nullptr); CAF_ASSERT(x.get() != nullptr);
auto sptr = dynamic_cast<caf::scheduled_actor*>(x.get()); auto sptr = dynamic_cast<caf::scheduled_actor*>(x.get());
if (sptr != nullptr) if (sptr != nullptr)
...@@ -227,26 +237,33 @@ caf::optional<std::tuple<T>> unboxing_extract(caf_handle x) { ...@@ -227,26 +237,33 @@ caf::optional<std::tuple<T>> unboxing_extract(caf_handle x) {
/// `default_extract`. /// `default_extract`.
/// @private /// @private
template <class T, bool HasOuterType, class... Ts> template <class T, bool HasOuterType, class... Ts>
struct extract_impl { struct try_extract_impl {
caf::optional<std::tuple<T, Ts...>> operator()(caf_handle x) { caf::optional<std::tuple<T, Ts...>> operator()(caf_handle x) {
return default_extract<T, Ts...>(x); return default_extract<T, Ts...>(x);
} }
}; };
template <class T> template <class T>
struct extract_impl<T, true> { struct try_extract_impl<T, true> {
caf::optional<std::tuple<T>> operator()(caf_handle x) { caf::optional<std::tuple<T>> operator()(caf_handle x) {
return unboxing_extract<T>(x); return unboxing_extract<T>(x);
} }
}; };
/// Returns the content of the next mailbox element as `tuple<T, Ts...>` on a
/// match. Returns `none` otherwise.
template <class T, class... Ts>
caf::optional<std::tuple<T, Ts...>> try_extract(caf_handle x) {
try_extract_impl<T, has_outer_type<T>::value, Ts...> f;
return f(x);
}
/// Returns the content of the next mailbox element without taking it out of /// Returns the content of the next mailbox element without taking it out of
/// the mailbox. Fails on an empty mailbox or if the content of the next /// the mailbox. Fails on an empty mailbox or if the content of the next
/// element does not match `<T, Ts...>`. /// element does not match `<T, Ts...>`.
template <class T, class... Ts> template <class T, class... Ts>
std::tuple<T, Ts...> extract(caf_handle x) { std::tuple<T, Ts...> extract(caf_handle x) {
extract_impl<T, has_outer_type<T>::value, Ts...> f; auto result = try_extract<T, Ts...>(x);
auto result = f(x);
if (result == caf::none) { if (result == caf::none) {
auto ptr = next_mailbox_element(x); auto ptr = next_mailbox_element(x);
if (ptr == nullptr) if (ptr == nullptr)
...@@ -259,11 +276,9 @@ std::tuple<T, Ts...> extract(caf_handle x) { ...@@ -259,11 +276,9 @@ std::tuple<T, Ts...> extract(caf_handle x) {
template <class T, class... Ts> template <class T, class... Ts>
bool received(caf_handle x) { bool received(caf_handle x) {
extract_impl<T, has_outer_type<T>::value, Ts...> f; return try_extract<T, Ts...>(x) != caf::none;
return f(x) != caf::none;
} }
template <class... Ts> template <class... Ts>
class expect_clause { class expect_clause {
public: public:
...@@ -340,149 +355,69 @@ protected: ...@@ -340,149 +355,69 @@ protected:
std::function<void ()> peek_; std::function<void ()> peek_;
}; };
template <class Derived> template <class... Ts>
class disallow_clause_base { class disallow_clause {
public: public:
disallow_clause_base(caf::scheduler::test_coordinator& sched) disallow_clause() {
: sched_(sched), check_ = [=] {
dest_(nullptr) { auto ptr = next_mailbox_element(dest_);
// nop if (ptr == nullptr)
} return;
if (src_ != nullptr && ptr->sender != src_)
disallow_clause_base(disallow_clause_base&& other) return;
: sched_(other.sched_), auto res = try_extract<Ts...>(dest_);
src_(std::move(other.src_)) { if (res != caf::none)
// nop CAF_FAIL("received disallowed message: " << CAF_ARG(*res));
} };
Derived& from(const wildcard&) {
return dref();
}
template <class Handle>
Derived& from(const Handle& whom) {
src_ = caf::actor_cast<caf::strong_actor_ptr>(whom);
return dref();
} }
template <class Handle> disallow_clause(disallow_clause&& other) = default;
Derived& to(const Handle& whom) {
// not setting dest_ causes the content checking to succeed immediately
if (sched_.prioritize(whom)) {
dest_ = &sched_.next_job<caf::scheduled_actor>();
}
return dref();
}
Derived& to(const wildcard& whom) { ~disallow_clause() {
if (sched_.prioritize(whom)) if (check_ != nullptr)
dest_ = &sched_.next_job<caf::scheduled_actor>(); check_();
} }
Derived& to(const caf::scoped_actor& whom) { disallow_clause& from(const wildcard&) {
dest_ = whom.ptr(); return *this;
return dref();
}
template <class... Ts>
caf::optional<std::tuple<const Ts&...>> peek() {
CAF_REQUIRE(dest_ != nullptr);
auto ptr = peek(dest_);
if (!ptr->content().template match_elements<Ts...>())
return caf::none;
return ptr->content().template get_as_tuple<Ts...>();
} }
protected: disallow_clause& from(caf_handle x) {
Derived& dref() { src_ = x;
return *static_cast<Derived*>(this); return *this;
} }
caf::scheduler::test_coordinator& sched_; disallow_clause& to(caf_handle x) {
caf::strong_actor_ptr src_; dest_ = x;
caf::local_actor* dest_; return *this;
};
template <class... Ts>
class disallow_clause : public disallow_clause_base<disallow_clause<Ts...>> {
public:
template <class... Us>
disallow_clause(Us&&... xs)
: disallow_clause_base<disallow_clause<Ts...>>(std::forward<Us>(xs)...) {
// nop
} }
template <class... Us> template <class... Us>
void with(Us&&... xs) { void with(Us&&... xs) {
// succeed immediately if dest_ is empty // TODO: move tmp into lambda when switching to C++14
if (this->dest_ == nullptr)
return;
auto tmp = std::make_tuple(std::forward<Us>(xs)...); auto tmp = std::make_tuple(std::forward<Us>(xs)...);
elementwise_compare_inspector<decltype(tmp)> inspector{tmp}; check_ = [=] {
auto ys = this->template peek<Ts...>(); auto ptr = next_mailbox_element(dest_);
if (ys && inspector(get<0>(*ys))) if (ptr == nullptr)
CAF_FAIL("disallowed message found: " << caf::deep_to_string(ys));
}
};
/// The single-argument disallow-clause allows to automagically unwrap T
/// if it's a variant-like wrapper.
template <class T>
class disallow_clause<T> : public disallow_clause_base<disallow_clause<T>> {
public:
template <class... Us>
disallow_clause(Us&&... xs)
: disallow_clause_base<disallow_clause<T>>(std::forward<Us>(xs)...) {
// nop
}
template <class... Us>
void with(Us&&... xs) {
if (this->dest_ == nullptr)
return; return;
std::integral_constant<bool, has_outer_type<T>::value> token; if (src_ != nullptr && ptr->sender != src_)
auto tmp = std::make_tuple(std::forward<Us>(xs)...);
with_content(token, tmp);
}
private:
template <class U>
void with_content(std::integral_constant<bool, false>, const U& x) {
elementwise_compare_inspector<U> inspector{x};
auto xs = this->template peek<T>();
if (xs && inspector(get<0>(*xs)))
CAF_FAIL("disallowed message found: " << caf::deep_to_string(*xs));
}
template <class U>
void with_content(std::integral_constant<bool, true>, const U& x) {
elementwise_compare_inspector<U> inspector{x};
auto xs = this->template peek<typename T::outer_type>();
if (!xs)
return; return;
auto& x0 = get<0>(*xs); auto res = try_extract<Ts...>(dest_);
if (is<T>(x0) && inspect(inspector, const_cast<T&>(get<T>(x0)))) if (res != caf::none) {
CAF_FAIL("disallowed message found: " << caf::deep_to_string(x0)); using namespace caf::detail;
elementwise_compare_inspector<decltype(tmp)> inspector{tmp};
auto& ys = *res;
auto ys_indices = get_indices(ys);
if (apply_args(inspector, ys_indices, ys))
CAF_FAIL("received disallowed message: " << CAF_ARG(*res));
} }
};
};
template <>
class disallow_clause<void>
: public disallow_clause_base<disallow_clause<void>> {
public:
template <class... Us>
disallow_clause(Us&&... xs)
: disallow_clause_base<disallow_clause<void>>(std::forward<Us>(xs)...) {
// nop
} }
void with() { protected:
if (dest_ == nullptr) caf_handle src_;
return; caf_handle dest_;
auto ptr = next_mailbox_element(dest_); std::function<void ()> check_;
CAF_REQUIRE(!ptr->content().empty());
}
}; };
template <class Config = caf::actor_system_config> template <class Config = caf::actor_system_config>
...@@ -547,4 +482,4 @@ struct test_coordinator_fixture { ...@@ -547,4 +482,4 @@ struct test_coordinator_fixture {
#define disallow(types, fields) \ #define disallow(types, fields) \
CAF_MESSAGE("disallow" << #types << "." << #fields); \ CAF_MESSAGE("disallow" << #types << "." << #fields); \
disallow_clause< CAF_EXPAND(CAF_DSL_LIST types) >{sched} . fields disallow_clause< CAF_EXPAND(CAF_DSL_LIST types) >{} . fields
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