Coverage Report

Created: 2025-07-12 06:05

/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