Skip to content

Commit 1043108

Browse files
authored
Problem: lack conversion message_t and multipart_t (#391)
Solution: add encode/decode methods to multipart_t giving a codec compatible with the CZMQ equivalent.
1 parent 2f1ab4c commit 1043108

File tree

4 files changed

+362
-2
lines changed

4 files changed

+362
-2
lines changed

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_executable(
2727
multipart.cpp
2828
recv_multipart.cpp
2929
send_multipart.cpp
30+
codec_multipart.cpp
3031
monitor.cpp
3132
utilities.cpp
3233
)

tests/codec_multipart.cpp

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#include <catch.hpp>
2+
#include <zmq_addon.hpp>
3+
4+
#ifdef ZMQ_CPP11
5+
6+
TEST_CASE("multipart codec empty", "[codec_multipart]")
7+
{
8+
using namespace zmq;
9+
10+
multipart_t mmsg;
11+
message_t msg = mmsg.encode();
12+
CHECK(msg.size() == 0);
13+
14+
multipart_t mmsg2;
15+
mmsg2.decode_append(msg);
16+
CHECK(mmsg2.size() == 0);
17+
18+
}
19+
20+
TEST_CASE("multipart codec small", "[codec_multipart]")
21+
{
22+
using namespace zmq;
23+
24+
multipart_t mmsg;
25+
mmsg.addstr("Hello World");
26+
message_t msg = mmsg.encode();
27+
CHECK(msg.size() == 1 + 11); // small size packing
28+
29+
mmsg.addstr("Second frame");
30+
msg = mmsg.encode();
31+
CHECK(msg.size() == 1 + 11 + 1 + 12);
32+
33+
multipart_t mmsg2;
34+
mmsg2.decode_append(msg);
35+
CHECK(mmsg2.size() == 2);
36+
std::string part0 = mmsg2[0].to_string();
37+
CHECK(part0 == "Hello World");
38+
CHECK(mmsg2[1].to_string() == "Second frame");
39+
}
40+
41+
TEST_CASE("multipart codec big", "[codec_multipart]")
42+
{
43+
using namespace zmq;
44+
45+
message_t big(495); // large size packing
46+
big.data<char>()[0] = 'X';
47+
48+
multipart_t mmsg;
49+
mmsg.pushmem(big.data(), big.size());
50+
message_t msg = mmsg.encode();
51+
CHECK(msg.size() == 5 + 495);
52+
CHECK(msg.data<unsigned char>()[0] == std::numeric_limits<uint8_t>::max());
53+
CHECK(msg.data<unsigned char>()[5] == 'X');
54+
55+
CHECK(mmsg.size() == 1);
56+
mmsg.decode_append(msg);
57+
CHECK(mmsg.size() == 2);
58+
CHECK(mmsg[0].data<char>()[0] == 'X');
59+
}
60+
61+
TEST_CASE("multipart codec decode bad data overflow", "[codec_multipart]")
62+
{
63+
using namespace zmq;
64+
65+
char bad_data[3] = {5, 'h', 'i'};
66+
message_t wrong_size(bad_data, 3);
67+
CHECK(wrong_size.size() == 3);
68+
CHECK(wrong_size.data<char>()[0] == 5);
69+
70+
CHECK_THROWS_AS(
71+
multipart_t::decode(wrong_size),
72+
std::out_of_range);
73+
}
74+
75+
TEST_CASE("multipart codec decode bad data extra data", "[codec_multipart]")
76+
{
77+
using namespace zmq;
78+
79+
char bad_data[3] = {1, 'h', 'i'};
80+
message_t wrong_size(bad_data, 3);
81+
CHECK(wrong_size.size() == 3);
82+
CHECK(wrong_size.data<char>()[0] == 1);
83+
84+
CHECK_THROWS_AS(
85+
multipart_t::decode(wrong_size),
86+
std::out_of_range);
87+
}
88+
89+
90+
// After exercising it, this test is disabled over concern of running
91+
// on hosts which lack enough free memory to allow the absurdly large
92+
// message part to be allocated.
93+
#if 0
94+
TEST_CASE("multipart codec encode too big", "[codec_multipart]")
95+
{
96+
using namespace zmq;
97+
98+
const size_t too_big_size = 1L + std::numeric_limits<uint32_t>::max();
99+
CHECK(too_big_size > std::numeric_limits<uint32_t>::max());
100+
char* too_big_data = new char[too_big_size];
101+
multipart_t mmsg(too_big_data, too_big_size);
102+
delete [] too_big_data;
103+
104+
CHECK(mmsg.size() == 1);
105+
CHECK(mmsg[0].size() > std::numeric_limits<uint32_t>::max());
106+
107+
CHECK_THROWS_AS(
108+
mmsg.encode(),
109+
std::range_error);
110+
}
111+
#endif
112+
113+
TEST_CASE("multipart codec free function with vector of message_t", "[codec_multipart]")
114+
{
115+
using namespace zmq;
116+
std::vector<message_t> parts;
117+
parts.emplace_back("Hello", 5);
118+
parts.emplace_back("World",5);
119+
auto msg = encode(parts);
120+
CHECK(msg.size() == 1 + 5 + 1 + 5 );
121+
CHECK(msg.data<unsigned char>()[0] == 5);
122+
CHECK(msg.data<unsigned char>()[1] == 'H');
123+
CHECK(msg.data<unsigned char>()[6] == 5);
124+
CHECK(msg.data<unsigned char>()[7] == 'W');
125+
126+
std::vector<message_t> parts2;
127+
decode(msg, std::back_inserter(parts2));
128+
CHECK(parts.size() == 2);
129+
CHECK(parts[0].size() == 5);
130+
CHECK(parts[1].size() == 5);
131+
}
132+
133+
TEST_CASE("multipart codec free function with vector of const_buffer", "[codec_multipart]")
134+
{
135+
using namespace zmq;
136+
std::vector<const_buffer> parts;
137+
parts.emplace_back("Hello", 5);
138+
parts.emplace_back("World",5);
139+
auto msg = encode(parts);
140+
CHECK(msg.size() == 1 + 5 + 1 + 5 );
141+
CHECK(msg.data<unsigned char>()[0] == 5);
142+
CHECK(msg.data<unsigned char>()[1] == 'H');
143+
CHECK(msg.data<unsigned char>()[6] == 5);
144+
CHECK(msg.data<unsigned char>()[7] == 'W');
145+
146+
std::vector<message_t> parts2;
147+
decode(msg, std::back_inserter(parts2));
148+
CHECK(parts.size() == 2);
149+
CHECK(parts[0].size() == 5);
150+
CHECK(parts[1].size() == 5);
151+
}
152+
153+
TEST_CASE("multipart codec free function with vector of mutable_buffer", "[codec_multipart]")
154+
{
155+
using namespace zmq;
156+
std::vector<mutable_buffer> parts;
157+
char hello[6] = "Hello";
158+
parts.emplace_back(hello, 5);
159+
char world[6] = "World";
160+
parts.emplace_back(world,5);
161+
auto msg = encode(parts);
162+
CHECK(msg.size() == 1 + 5 + 1 + 5 );
163+
CHECK(msg.data<unsigned char>()[0] == 5);
164+
CHECK(msg.data<unsigned char>()[1] == 'H');
165+
CHECK(msg.data<unsigned char>()[6] == 5);
166+
CHECK(msg.data<unsigned char>()[7] == 'W');
167+
168+
std::vector<message_t> parts2;
169+
decode(msg, std::back_inserter(parts2));
170+
CHECK(parts.size() == 2);
171+
CHECK(parts[0].size() == 5);
172+
CHECK(parts[1].size() == 5);
173+
}
174+
175+
TEST_CASE("multipart codec free function with multipart_t", "[codec_multipart]")
176+
{
177+
using namespace zmq;
178+
multipart_t mmsg;
179+
mmsg.addstr("Hello");
180+
mmsg.addstr("World");
181+
auto msg = encode(mmsg);
182+
CHECK(msg.size() == 1 + 5 + 1 + 5);
183+
CHECK(msg.data<unsigned char>()[0] == 5);
184+
CHECK(msg.data<unsigned char>()[1] == 'H');
185+
CHECK(msg.data<unsigned char>()[6] == 5);
186+
CHECK(msg.data<unsigned char>()[7] == 'W');
187+
188+
multipart_t mmsg2;
189+
decode(msg, std::back_inserter(mmsg2));
190+
CHECK(mmsg2.size() == 2);
191+
CHECK(mmsg2[0].size() == 5);
192+
CHECK(mmsg2[1].size() == 5);
193+
}
194+
195+
TEST_CASE("multipart codec static method decode to multipart_t", "[codec_multipart]")
196+
{
197+
using namespace zmq;
198+
multipart_t mmsg;
199+
mmsg.addstr("Hello");
200+
mmsg.addstr("World");
201+
auto msg = encode(mmsg);
202+
203+
auto mmsg2 = multipart_t::decode(msg);
204+
CHECK(mmsg2.size() == 2);
205+
CHECK(mmsg2[0].size() == 5);
206+
CHECK(mmsg2[1].size() == 5);
207+
}
208+
209+
210+
#endif

zmq.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
#ifndef __ZMQ_HPP_INCLUDED__
2727
#define __ZMQ_HPP_INCLUDED__
2828

29+
#ifdef _WIN32
30+
#ifndef NOMINMAX
31+
#define NOMINMAX
32+
#endif
33+
#endif
34+
2935
// macros defined if has a specific standard or greater
3036
#if (defined(__cplusplus) && __cplusplus >= 201103L) \
3137
|| (defined(_MSC_VER) && _MSC_VER >= 1900)

0 commit comments

Comments
 (0)