Skip to content

Commit

Permalink
Problem: lack conversion message_t and multipart_t (zeromq#391)
Browse files Browse the repository at this point in the history
Solution: add encode/decode methods to multipart_t giving a codec compatible with the CZMQ equivalent.
  • Loading branch information
brettviren authored Mar 20, 2020
1 parent 2f1ab4c commit 1043108
Show file tree
Hide file tree
Showing 4 changed files with 362 additions and 2 deletions.
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_executable(
multipart.cpp
recv_multipart.cpp
send_multipart.cpp
codec_multipart.cpp
monitor.cpp
utilities.cpp
)
Expand Down
210 changes: 210 additions & 0 deletions tests/codec_multipart.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
#include <catch.hpp>
#include <zmq_addon.hpp>

#ifdef ZMQ_CPP11

TEST_CASE("multipart codec empty", "[codec_multipart]")
{
using namespace zmq;

multipart_t mmsg;
message_t msg = mmsg.encode();
CHECK(msg.size() == 0);

multipart_t mmsg2;
mmsg2.decode_append(msg);
CHECK(mmsg2.size() == 0);

}

TEST_CASE("multipart codec small", "[codec_multipart]")
{
using namespace zmq;

multipart_t mmsg;
mmsg.addstr("Hello World");
message_t msg = mmsg.encode();
CHECK(msg.size() == 1 + 11); // small size packing

mmsg.addstr("Second frame");
msg = mmsg.encode();
CHECK(msg.size() == 1 + 11 + 1 + 12);

multipart_t mmsg2;
mmsg2.decode_append(msg);
CHECK(mmsg2.size() == 2);
std::string part0 = mmsg2[0].to_string();
CHECK(part0 == "Hello World");
CHECK(mmsg2[1].to_string() == "Second frame");
}

TEST_CASE("multipart codec big", "[codec_multipart]")
{
using namespace zmq;

message_t big(495); // large size packing
big.data<char>()[0] = 'X';

multipart_t mmsg;
mmsg.pushmem(big.data(), big.size());
message_t msg = mmsg.encode();
CHECK(msg.size() == 5 + 495);
CHECK(msg.data<unsigned char>()[0] == std::numeric_limits<uint8_t>::max());
CHECK(msg.data<unsigned char>()[5] == 'X');

CHECK(mmsg.size() == 1);
mmsg.decode_append(msg);
CHECK(mmsg.size() == 2);
CHECK(mmsg[0].data<char>()[0] == 'X');
}

TEST_CASE("multipart codec decode bad data overflow", "[codec_multipart]")
{
using namespace zmq;

char bad_data[3] = {5, 'h', 'i'};
message_t wrong_size(bad_data, 3);
CHECK(wrong_size.size() == 3);
CHECK(wrong_size.data<char>()[0] == 5);

CHECK_THROWS_AS(
multipart_t::decode(wrong_size),
std::out_of_range);
}

TEST_CASE("multipart codec decode bad data extra data", "[codec_multipart]")
{
using namespace zmq;

char bad_data[3] = {1, 'h', 'i'};
message_t wrong_size(bad_data, 3);
CHECK(wrong_size.size() == 3);
CHECK(wrong_size.data<char>()[0] == 1);

CHECK_THROWS_AS(
multipart_t::decode(wrong_size),
std::out_of_range);
}


// After exercising it, this test is disabled over concern of running
// on hosts which lack enough free memory to allow the absurdly large
// message part to be allocated.
#if 0
TEST_CASE("multipart codec encode too big", "[codec_multipart]")
{
using namespace zmq;

const size_t too_big_size = 1L + std::numeric_limits<uint32_t>::max();
CHECK(too_big_size > std::numeric_limits<uint32_t>::max());
char* too_big_data = new char[too_big_size];
multipart_t mmsg(too_big_data, too_big_size);
delete [] too_big_data;

CHECK(mmsg.size() == 1);
CHECK(mmsg[0].size() > std::numeric_limits<uint32_t>::max());

CHECK_THROWS_AS(
mmsg.encode(),
std::range_error);
}
#endif

TEST_CASE("multipart codec free function with vector of message_t", "[codec_multipart]")
{
using namespace zmq;
std::vector<message_t> parts;
parts.emplace_back("Hello", 5);
parts.emplace_back("World",5);
auto msg = encode(parts);
CHECK(msg.size() == 1 + 5 + 1 + 5 );
CHECK(msg.data<unsigned char>()[0] == 5);
CHECK(msg.data<unsigned char>()[1] == 'H');
CHECK(msg.data<unsigned char>()[6] == 5);
CHECK(msg.data<unsigned char>()[7] == 'W');

std::vector<message_t> parts2;
decode(msg, std::back_inserter(parts2));
CHECK(parts.size() == 2);
CHECK(parts[0].size() == 5);
CHECK(parts[1].size() == 5);
}

TEST_CASE("multipart codec free function with vector of const_buffer", "[codec_multipart]")
{
using namespace zmq;
std::vector<const_buffer> parts;
parts.emplace_back("Hello", 5);
parts.emplace_back("World",5);
auto msg = encode(parts);
CHECK(msg.size() == 1 + 5 + 1 + 5 );
CHECK(msg.data<unsigned char>()[0] == 5);
CHECK(msg.data<unsigned char>()[1] == 'H');
CHECK(msg.data<unsigned char>()[6] == 5);
CHECK(msg.data<unsigned char>()[7] == 'W');

std::vector<message_t> parts2;
decode(msg, std::back_inserter(parts2));
CHECK(parts.size() == 2);
CHECK(parts[0].size() == 5);
CHECK(parts[1].size() == 5);
}

TEST_CASE("multipart codec free function with vector of mutable_buffer", "[codec_multipart]")
{
using namespace zmq;
std::vector<mutable_buffer> parts;
char hello[6] = "Hello";
parts.emplace_back(hello, 5);
char world[6] = "World";
parts.emplace_back(world,5);
auto msg = encode(parts);
CHECK(msg.size() == 1 + 5 + 1 + 5 );
CHECK(msg.data<unsigned char>()[0] == 5);
CHECK(msg.data<unsigned char>()[1] == 'H');
CHECK(msg.data<unsigned char>()[6] == 5);
CHECK(msg.data<unsigned char>()[7] == 'W');

std::vector<message_t> parts2;
decode(msg, std::back_inserter(parts2));
CHECK(parts.size() == 2);
CHECK(parts[0].size() == 5);
CHECK(parts[1].size() == 5);
}

TEST_CASE("multipart codec free function with multipart_t", "[codec_multipart]")
{
using namespace zmq;
multipart_t mmsg;
mmsg.addstr("Hello");
mmsg.addstr("World");
auto msg = encode(mmsg);
CHECK(msg.size() == 1 + 5 + 1 + 5);
CHECK(msg.data<unsigned char>()[0] == 5);
CHECK(msg.data<unsigned char>()[1] == 'H');
CHECK(msg.data<unsigned char>()[6] == 5);
CHECK(msg.data<unsigned char>()[7] == 'W');

multipart_t mmsg2;
decode(msg, std::back_inserter(mmsg2));
CHECK(mmsg2.size() == 2);
CHECK(mmsg2[0].size() == 5);
CHECK(mmsg2[1].size() == 5);
}

TEST_CASE("multipart codec static method decode to multipart_t", "[codec_multipart]")
{
using namespace zmq;
multipart_t mmsg;
mmsg.addstr("Hello");
mmsg.addstr("World");
auto msg = encode(mmsg);

auto mmsg2 = multipart_t::decode(msg);
CHECK(mmsg2.size() == 2);
CHECK(mmsg2[0].size() == 5);
CHECK(mmsg2[1].size() == 5);
}


#endif
6 changes: 6 additions & 0 deletions zmq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
#ifndef __ZMQ_HPP_INCLUDED__
#define __ZMQ_HPP_INCLUDED__

#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif

// macros defined if has a specific standard or greater
#if (defined(__cplusplus) && __cplusplus >= 201103L) \
|| (defined(_MSC_VER) && _MSC_VER >= 1900)
Expand Down
Loading

0 comments on commit 1043108

Please sign in to comment.