Skip to content

Problem: insufficient tests for poller_t, bad usability since caller of add must store function object #201

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 69 additions & 13 deletions tests/poller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,62 @@
TEST(poller, create_destroy)
{
zmq::poller_t poller;
ASSERT_EQ(0u, poller.size ());
}

TEST(poller, move_contruct)
static_assert(!std::is_copy_constructible<zmq::poller_t>::value, "poller_t should not be copy-constructible");
static_assert(!std::is_copy_assignable<zmq::poller_t>::value, "poller_t should not be copy-assignable");

TEST(poller, move_construct_empty)
{
zmq::poller_t poller;
zmq::poller_t poller_move {std::move (poller)};
std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
zmq::poller_t b = std::move(*a);

ASSERT_EQ(0u, a->size ());
a.reset ();
ASSERT_EQ(0u, b.size ());
}

TEST(poller, move_assign)
TEST(poller, move_assign_empty)
{
zmq::poller_t poller;
zmq::poller_t poller_assign;
poller_assign = std::move (poller);
std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
zmq::poller_t b;

b = std::move(*a);

ASSERT_EQ(0u, a->size ());
a.reset ();
ASSERT_EQ(0u, b.size ());
}

TEST(poller, move_construct_non_empty)
{
zmq::context_t context;
zmq::socket_t socket{context, zmq::socket_type::router};

std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
a->add(socket, ZMQ_POLLIN, [](short) {});
zmq::poller_t b = std::move(*a);

ASSERT_EQ(0u, a->size ());
a.reset ();
ASSERT_EQ(1u, b.size ());
}

TEST(poller, move_assign_non_empty)
{
zmq::context_t context;
zmq::socket_t socket{context, zmq::socket_type::router};

std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
a->add(socket, ZMQ_POLLIN, [](short) {});
zmq::poller_t b;

b = std::move(*a);

ASSERT_EQ(0u, a->size ());
a.reset ();
ASSERT_EQ(1u, b.size ());
}

TEST(poller, add_handler)
Expand Down Expand Up @@ -49,12 +92,14 @@ TEST(poller, add_handler_twice_throws)
zmq::poller_t poller;
zmq::poller_t::handler_t handler;
poller.add(socket, ZMQ_POLLIN, handler);
/// \todo the actual error code should be checked
ASSERT_THROW(poller.add(socket, ZMQ_POLLIN, handler), zmq::error_t);
}

TEST(poller, wait_with_no_handlers_throws)
{
zmq::poller_t poller;
/// \todo the actual error code should be checked
ASSERT_THROW(poller.wait(std::chrono::milliseconds{10}), zmq::error_t);
}

Expand All @@ -63,16 +108,26 @@ TEST(poller, remove_unregistered_throws)
zmq::context_t context;
zmq::socket_t socket{context, zmq::socket_type::router};
zmq::poller_t poller;
/// \todo the actual error code should be checked
ASSERT_THROW(poller.remove(socket), zmq::error_t);
}

TEST(poller, remove_registered)
/// \todo this should lead to an exception instead
TEST(poller, remove_registered_empty)
{
zmq::context_t context;
zmq::socket_t socket{context, zmq::socket_type::router};
zmq::poller_t poller;
zmq::poller_t::handler_t handler;
poller.add(socket, ZMQ_POLLIN, handler);
poller.add(socket, ZMQ_POLLIN, zmq::poller_t::handler_t{});
ASSERT_NO_THROW(poller.remove(socket));
}

TEST(poller, remove_registered_non_empty)
{
zmq::context_t context;
zmq::socket_t socket{context, zmq::socket_type::router};
zmq::poller_t poller;
poller.add(socket, ZMQ_POLLIN, [](short) {});
ASSERT_NO_THROW(poller.remove(socket));
}

Expand All @@ -85,7 +140,7 @@ class loopback_ip4_binder
std::string endpoint() { return endpoint_; }
private:
// Helper function used in constructor
// as Gtest allows only void returning functions
// as Gtest allows ASSERT_* only in void returning functions
// and constructor/destructor are not.
void bind(zmq::socket_t &socket)
{
Expand All @@ -112,7 +167,7 @@ TEST(poller, poll_basic)
zmq::socket_t sink{context, zmq::socket_type::pull};
ASSERT_NO_THROW(sink.connect(endpoint));

std::string message = "H";
const std::string message = "H";

// TODO: send overload for string would be handy.
ASSERT_NO_THROW(vent.send(std::begin(message), std::end(message)));
Expand All @@ -128,10 +183,11 @@ TEST(poller, poll_basic)
ASSERT_TRUE(message_received);
}

/// \todo this contains multiple test cases that should be split up
TEST(poller, client_server)
{
zmq::context_t context;
std::string send_msg = "Hi";
const std::string send_msg = "Hi";

// Setup server
zmq::socket_t server{context, zmq::socket_type::router};
Expand Down
36 changes: 33 additions & 3 deletions zmq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__

#if (__cplusplus >= 201402L)
#define ZMQ_DEPRECATED(msg) [[deprecated(msg)]]
#elif defined(_MSC_VER)
#define ZMQ_DEPRECATED(msg) __declspec(deprecated(msg))
#elif defined(__GNUC__)
#define ZMQ_DEPRECATED(msg) __attribute__((deprecated(msg)))
#endif

#if (__cplusplus >= 201103L)
#define ZMQ_CPP11
#define ZMQ_NOTHROW noexcept
Expand Down Expand Up @@ -1022,9 +1030,21 @@ namespace zmq

using handler_t = std::function<void(short)>;

void add (zmq::socket_t &socket, short events, handler_t &handler)
ZMQ_DEPRECATED("from 4.3.0, use overload accepting handler_t instead")
void add (zmq::socket_t &socket, short events, std::function<void(void)> &handler)
{
add (socket, events, [&handler](short) { handler(); });
}

void add (zmq::socket_t &socket, short events, handler_t handler)
{
if (0 == zmq_poller_add (poller_ptr, socket.ptr, handler ? &handler : NULL, events)) {
handler_t *handler_ptr = nullptr;
/// \todo is it sensible to allow handler to be empty? doesn't this lead to an error when the event is signalled? (perhaps it should already lead to an error in zmq_poller_add then)
if (handler) {
auto emplace_res = handlers.emplace(&socket, std::move(handler));
handler_ptr = &emplace_res.first->second;
}
if (0 == zmq_poller_add (poller_ptr, socket.ptr, handler_ptr, events)) {
poller_events.emplace_back (zmq_poller_event_t ());
return;
}
Expand All @@ -1034,7 +1054,11 @@ namespace zmq
void remove (zmq::socket_t &socket)
{
if (0 == zmq_poller_remove (poller_ptr, socket.ptr)) {
poller_events.pop_back ();
auto it = handlers.find (&socket);
if (it != handlers.end ()) { /// \todo this may only be false if handler was empty on add
handlers.erase (it);
}
poller_events.pop_back ();
return;
}
throw error_t ();
Expand All @@ -1060,10 +1084,16 @@ namespace zmq

throw error_t ();
}

size_t size ()
{
return poller_events.size();
}

private:
void *poller_ptr;
std::vector<zmq_poller_event_t> poller_events;
std::map<socket_t*, handler_t> handlers;
}; // class poller_t
#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)

Expand Down