/src/libzmq/tests/testutil_unity.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | #include "testutil_unity.hpp" |
3 | | |
4 | | #include <stdlib.h> |
5 | | #include <string.h> |
6 | | |
7 | | #ifdef _WIN32 |
8 | | #include <direct.h> |
9 | | #else |
10 | | #include <unistd.h> |
11 | | #endif |
12 | | |
13 | | int test_assert_success_message_errno_helper (int rc_, |
14 | | const char *msg_, |
15 | | const char *expr_, |
16 | | int line_) |
17 | 6.34k | { |
18 | 6.34k | if (rc_ == -1) { |
19 | 0 | char buffer[512]; |
20 | 0 | buffer[sizeof (buffer) - 1] = |
21 | 0 | 0; // to ensure defined behavior with VC++ <= 2013 |
22 | 0 | snprintf (buffer, sizeof (buffer) - 1, |
23 | 0 | "%s failed%s%s%s, errno = %i (%s)", expr_, |
24 | 0 | msg_ ? " (additional info: " : "", msg_ ? msg_ : "", |
25 | 0 | msg_ ? ")" : "", zmq_errno (), zmq_strerror (zmq_errno ())); |
26 | 0 | UNITY_TEST_FAIL (line_, buffer); |
27 | 0 | } |
28 | 6.34k | return rc_; |
29 | 6.34k | } |
30 | | |
31 | | int test_assert_success_message_raw_errno_helper ( |
32 | | int rc_, const char *msg_, const char *expr_, int line_, bool zero) |
33 | 0 | { |
34 | 0 | if (rc_ == -1 || (zero && rc_ != 0)) { |
35 | | #if defined ZMQ_HAVE_WINDOWS |
36 | | int current_errno = WSAGetLastError (); |
37 | | #else |
38 | 0 | int current_errno = errno; |
39 | 0 | #endif |
40 | |
|
41 | 0 | char buffer[512]; |
42 | 0 | buffer[sizeof (buffer) - 1] = |
43 | 0 | 0; // to ensure defined behavior with VC++ <= 2013 |
44 | 0 | snprintf ( |
45 | 0 | buffer, sizeof (buffer) - 1, "%s failed%s%s%s with %d, errno = %i/%s", |
46 | 0 | expr_, msg_ ? " (additional info: " : "", msg_ ? msg_ : "", |
47 | 0 | msg_ ? ")" : "", rc_, current_errno, strerror (current_errno)); |
48 | 0 | UNITY_TEST_FAIL (line_, buffer); |
49 | 0 | } |
50 | 0 | return rc_; |
51 | 0 | } |
52 | | |
53 | | int test_assert_success_message_raw_zero_errno_helper (int rc_, |
54 | | const char *msg_, |
55 | | const char *expr_, |
56 | | int line_) |
57 | 0 | { |
58 | 0 | return test_assert_success_message_raw_errno_helper (rc_, msg_, expr_, |
59 | 0 | line_, true); |
60 | 0 | } |
61 | | |
62 | | int test_assert_failure_message_raw_errno_helper ( |
63 | | int rc_, int expected_errno_, const char *msg_, const char *expr_, int line_) |
64 | 0 | { |
65 | 0 | char buffer[512]; |
66 | 0 | buffer[sizeof (buffer) - 1] = |
67 | 0 | 0; // to ensure defined behavior with VC++ <= 2013 |
68 | 0 | if (rc_ != -1) { |
69 | 0 | snprintf (buffer, sizeof (buffer) - 1, |
70 | 0 | "%s was unexpectedly successful%s%s%s, expected " |
71 | 0 | "errno = %i, actual return value = %i", |
72 | 0 | expr_, msg_ ? " (additional info: " : "", msg_ ? msg_ : "", |
73 | 0 | msg_ ? ")" : "", expected_errno_, rc_); |
74 | 0 | UNITY_TEST_FAIL (line_, buffer); |
75 | 0 | } else { |
76 | | #if defined ZMQ_HAVE_WINDOWS |
77 | | int current_errno = WSAGetLastError (); |
78 | | #else |
79 | 0 | int current_errno = errno; |
80 | 0 | #endif |
81 | 0 | if (current_errno != expected_errno_) { |
82 | 0 | snprintf (buffer, sizeof (buffer) - 1, |
83 | 0 | "%s failed with an unexpected error%s%s%s, expected " |
84 | 0 | "errno = %i, actual errno = %i", |
85 | 0 | expr_, msg_ ? " (additional info: " : "", |
86 | 0 | msg_ ? msg_ : "", msg_ ? ")" : "", expected_errno_, |
87 | 0 | current_errno); |
88 | 0 | UNITY_TEST_FAIL (line_, buffer); |
89 | 0 | } |
90 | 0 | } |
91 | 0 | return rc_; |
92 | 0 | } |
93 | | |
94 | | void send_string_expect_success (void *socket_, const char *str_, int flags_) |
95 | 0 | { |
96 | 0 | const size_t len = str_ ? strlen (str_) : 0; |
97 | 0 | const int rc = zmq_send (socket_, str_, len, flags_); |
98 | 0 | TEST_ASSERT_EQUAL_INT ((int) len, rc); |
99 | 0 | } |
100 | | |
101 | | void recv_string_expect_success (void *socket_, const char *str_, int flags_) |
102 | 0 | { |
103 | 0 | const size_t len = str_ ? strlen (str_) : 0; |
104 | 0 | char buffer[255]; |
105 | 0 | TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (sizeof (buffer), len, |
106 | 0 | "recv_string_expect_success cannot be " |
107 | 0 | "used for strings longer than 255 " |
108 | 0 | "characters"); |
109 | |
|
110 | 0 | const int rc = TEST_ASSERT_SUCCESS_ERRNO ( |
111 | 0 | zmq_recv (socket_, buffer, sizeof (buffer), flags_)); |
112 | 0 | TEST_ASSERT_EQUAL_INT ((int) len, rc); |
113 | 0 | if (str_) |
114 | 0 | TEST_ASSERT_EQUAL_STRING_LEN (str_, buffer, len); |
115 | 0 | } |
116 | | |
117 | | static void *internal_manage_test_context (bool init_, bool clear_) |
118 | 6.34k | { |
119 | 6.34k | static void *test_context = NULL; |
120 | 6.34k | if (clear_) { |
121 | 1.58k | TEST_ASSERT_NOT_NULL (test_context); |
122 | 1.58k | TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_term (test_context)); |
123 | 1.58k | test_context = NULL; |
124 | 4.75k | } else { |
125 | 4.75k | if (init_) { |
126 | 1.58k | TEST_ASSERT_NULL (test_context); |
127 | 1.58k | test_context = zmq_ctx_new (); |
128 | 1.58k | TEST_ASSERT_NOT_NULL (test_context); |
129 | 1.58k | } |
130 | 4.75k | } |
131 | 6.34k | return test_context; |
132 | 6.34k | } |
133 | | |
134 | | static void internal_manage_test_sockets (void *socket_, bool add_) |
135 | 4.75k | { |
136 | 4.75k | static void *test_sockets[MAX_TEST_SOCKETS]; |
137 | 4.75k | static size_t test_socket_count = 0; |
138 | 4.75k | if (!socket_) { |
139 | 1.58k | TEST_ASSERT_FALSE (add_); |
140 | | |
141 | | // force-close all sockets |
142 | 1.58k | if (test_socket_count) { |
143 | 0 | for (size_t i = 0; i < test_socket_count; ++i) { |
144 | 0 | close_zero_linger (test_sockets[i]); |
145 | 0 | } |
146 | 0 | fprintf (stderr, |
147 | 0 | "WARNING: Forced closure of %i sockets, this is an " |
148 | 0 | "implementation error unless the test case failed\n", |
149 | 0 | static_cast<int> (test_socket_count)); |
150 | 0 | test_socket_count = 0; |
151 | 0 | } |
152 | 3.17k | } else { |
153 | 3.17k | if (add_) { |
154 | 1.58k | ++test_socket_count; |
155 | 1.58k | TEST_ASSERT_LESS_THAN_MESSAGE (MAX_TEST_SOCKETS, test_socket_count, |
156 | 1.58k | "MAX_TEST_SOCKETS must be " |
157 | 1.58k | "increased, or you cannot use the " |
158 | 1.58k | "test context"); |
159 | 1.58k | test_sockets[test_socket_count - 1] = socket_; |
160 | 1.58k | } else { |
161 | 1.58k | bool found = false; |
162 | 3.17k | for (size_t i = 0; i < test_socket_count; ++i) { |
163 | 1.58k | if (test_sockets[i] == socket_) { |
164 | 1.58k | found = true; |
165 | 1.58k | } |
166 | 1.58k | if (found) { |
167 | 1.58k | if (i < test_socket_count) |
168 | 1.58k | test_sockets[i] = test_sockets[i + 1]; |
169 | 1.58k | } |
170 | 1.58k | } |
171 | 1.58k | TEST_ASSERT_TRUE_MESSAGE (found, |
172 | 1.58k | "Attempted to close a socket that was " |
173 | 1.58k | "not created by test_context_socket"); |
174 | 1.58k | --test_socket_count; |
175 | 1.58k | } |
176 | 3.17k | } |
177 | 4.75k | } |
178 | | |
179 | | void setup_test_context () |
180 | 1.58k | { |
181 | 1.58k | internal_manage_test_context (true, false); |
182 | 1.58k | } |
183 | | |
184 | | void *get_test_context () |
185 | 3.17k | { |
186 | 3.17k | return internal_manage_test_context (false, false); |
187 | 3.17k | } |
188 | | |
189 | | void teardown_test_context () |
190 | 1.58k | { |
191 | | // this condition allows an explicit call to teardown_test_context from a |
192 | | // test. if this is never used, it should probably be removed, to detect |
193 | | // misuses |
194 | 1.58k | if (get_test_context ()) { |
195 | 1.58k | internal_manage_test_sockets (NULL, false); |
196 | 1.58k | internal_manage_test_context (false, true); |
197 | 1.58k | } |
198 | 1.58k | } |
199 | | |
200 | | void *test_context_socket (int type_) |
201 | 1.58k | { |
202 | 1.58k | void *const socket = zmq_socket (get_test_context (), type_); |
203 | 1.58k | TEST_ASSERT_NOT_NULL (socket); |
204 | 1.58k | internal_manage_test_sockets (socket, true); |
205 | 1.58k | return socket; |
206 | 1.58k | } |
207 | | |
208 | | void *test_context_socket_close (void *socket_) |
209 | 1.58k | { |
210 | 1.58k | TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket_)); |
211 | 1.58k | internal_manage_test_sockets (socket_, false); |
212 | 1.58k | return socket_; |
213 | 1.58k | } |
214 | | |
215 | | void *test_context_socket_close_zero_linger (void *socket_) |
216 | 1.58k | { |
217 | 1.58k | const int linger = 0; |
218 | 1.58k | int rc = zmq_setsockopt (socket_, ZMQ_LINGER, &linger, sizeof (linger)); |
219 | 1.58k | TEST_ASSERT_TRUE (rc == 0 || zmq_errno () == ETERM); |
220 | 1.58k | return test_context_socket_close (socket_); |
221 | 1.58k | } |
222 | | |
223 | | void test_bind (void *socket_, |
224 | | const char *bind_address_, |
225 | | char *my_endpoint_, |
226 | | size_t len_) |
227 | 0 | { |
228 | 0 | TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket_, bind_address_)); |
229 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
230 | 0 | zmq_getsockopt (socket_, ZMQ_LAST_ENDPOINT, my_endpoint_, &len_)); |
231 | 0 | } |
232 | | |
233 | | void bind_loopback (void *socket_, int ipv6_, char *my_endpoint_, size_t len_) |
234 | 0 | { |
235 | 0 | if (ipv6_ && !is_ipv6_available ()) { |
236 | 0 | TEST_IGNORE_MESSAGE ("ipv6 is not available"); |
237 | 0 | } |
238 | |
|
239 | 0 | TEST_ASSERT_SUCCESS_ERRNO ( |
240 | 0 | zmq_setsockopt (socket_, ZMQ_IPV6, &ipv6_, sizeof (int))); |
241 | |
|
242 | 0 | test_bind (socket_, ipv6_ ? "tcp://[::1]:*" : "tcp://127.0.0.1:*", |
243 | 0 | my_endpoint_, len_); |
244 | 0 | } |
245 | | |
246 | | void bind_loopback_ipv4 (void *socket_, char *my_endpoint_, size_t len_) |
247 | 0 | { |
248 | 0 | bind_loopback (socket_, false, my_endpoint_, len_); |
249 | 0 | } |
250 | | |
251 | | void bind_loopback_ipv6 (void *socket_, char *my_endpoint_, size_t len_) |
252 | 0 | { |
253 | 0 | bind_loopback (socket_, true, my_endpoint_, len_); |
254 | 0 | } |
255 | | |
256 | | void bind_loopback_ipc (void *socket_, char *my_endpoint_, size_t len_) |
257 | 0 | { |
258 | 0 | if (!zmq_has ("ipc")) { |
259 | 0 | TEST_IGNORE_MESSAGE ("ipc is not available"); |
260 | 0 | } |
261 | |
|
262 | 0 | test_bind (socket_, "ipc://*", my_endpoint_, len_); |
263 | 0 | } |
264 | | |
265 | | void bind_loopback_tipc (void *socket_, char *my_endpoint_, size_t len_) |
266 | 0 | { |
267 | 0 | if (!is_tipc_available ()) { |
268 | 0 | TEST_IGNORE_MESSAGE ("tipc is not available"); |
269 | 0 | } |
270 | |
|
271 | 0 | test_bind (socket_, "tipc://<*>", my_endpoint_, len_); |
272 | 0 | } |
273 | | |
274 | | #if defined(ZMQ_HAVE_IPC) |
275 | | void make_random_ipc_endpoint (char *out_endpoint_) |
276 | 0 | { |
277 | | #ifdef ZMQ_HAVE_WINDOWS |
278 | | char random_file[MAX_PATH]; |
279 | | |
280 | | { |
281 | | const errno_t rc = tmpnam_s (random_file); |
282 | | TEST_ASSERT_EQUAL (0, rc); |
283 | | } |
284 | | |
285 | | // TODO or use CreateDirectoryA and specify permissions? |
286 | | const int rc = _mkdir (random_file); |
287 | | TEST_ASSERT_EQUAL (0, rc); |
288 | | |
289 | | strcat (random_file, "/ipc"); |
290 | | |
291 | | #else |
292 | 0 | char random_file[16]; |
293 | 0 | strcpy (random_file, "tmpXXXXXX"); |
294 | |
|
295 | 0 | #ifdef HAVE_MKDTEMP |
296 | 0 | TEST_ASSERT_TRUE (mkdtemp (random_file)); |
297 | 0 | strcat (random_file, "/ipc"); |
298 | | #else |
299 | | int fd = mkstemp (random_file); |
300 | | TEST_ASSERT_TRUE (fd != -1); |
301 | | close (fd); |
302 | | #endif |
303 | 0 | #endif |
304 | |
|
305 | 0 | strcpy (out_endpoint_, "ipc://"); |
306 | 0 | strcat (out_endpoint_, random_file); |
307 | 0 | } |
308 | | #endif |