Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : *
3 : : * Copyright 2014 Red Hat, Inc.
4 : : * Copyright 2025 GNOME Foundation, Inc.
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General Public
19 : : * License along with this library; if not, see
20 : : * <http://www.gnu.org/licenses/>.
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <gio/gio.h>
26 : :
27 : : #ifdef HAVE_RTLD_NEXT
28 : : #include <dlfcn.h>
29 : : #include <sys/types.h>
30 : : #include <netinet/in.h>
31 : : #include <netinet/ip.h>
32 : : #include <stdint.h>
33 : : #include <sys/socket.h>
34 : : #endif
35 : :
36 : : /* Override the socket(), bind(), listen() and getsockopt() functions from libc
37 : : * so that we can mock results from them in the tests. The libc implementations
38 : : * are used by default (via `dlsym()`) unless a test sets a callback
39 : : * deliberately.
40 : : *
41 : : * These override functions are used simply because the linker will resolve them
42 : : * before it finds the symbols in libc. This is effectively like `LD_PRELOAD`,
43 : : * except without using an external library for them.
44 : : *
45 : : * This mechanism is intended to be generic and not to force tests in this file
46 : : * to be written in a certain way. Tests are free to override these functions
47 : : * with their own implementations, or leave them as default. Different tests may
48 : : * need to mock these socket functions differently.
49 : : *
50 : : * If a test overrides these functions, it *must* do so at the start of the test
51 : : * (before starting any threads), and *must* clear them to `NULL` at the end of
52 : : * the test. The overrides are not thread-safe and will not be automatically
53 : : * cleared at the end of a test.
54 : : */
55 : : /* FIXME: Not currently supported on macOS as its symbol lookup works
56 : : * differently to Linux. It will likely need something like DYLD_INTERPOSE()
57 : : * from getpwuid-preload.c here to work. At that point, this common code for
58 : : * mocking arbitrary syscalls using dlsym(RTLD_NEXT) should probably be factored
59 : : * out into a set of internal helpers, because various tests do it for various
60 : : * syscalls. */
61 : : #if defined(HAVE_RTLD_NEXT) && !defined(__APPLE__)
62 : : #define MOCK_SOCKET_SUPPORTED
63 : : #endif
64 : :
65 : : #ifdef MOCK_SOCKET_SUPPORTED
66 : : static int (*real_socket) (int, int, int);
67 : : static int (*real_bind) (int, const struct sockaddr *, socklen_t);
68 : : static int (*real_listen) (int, int);
69 : : static int (*real_getsockopt) (int, int, int, void *, socklen_t *);
70 : : static int (*mock_socket) (int, int, int);
71 : : static int (*mock_bind) (int, const struct sockaddr *, socklen_t);
72 : : static int (*mock_listen) (int, int);
73 : : static int (*mock_getsockopt) (int, int, int, void *, socklen_t *);
74 : :
75 : : int
76 : : socket (int domain,
77 : : int type,
78 : : int protocol)
79 : : {
80 : 31 : if (real_socket == NULL)
81 : 1 : real_socket = dlsym (RTLD_NEXT, "socket");
82 : :
83 : 31 : return ((mock_socket != NULL) ? mock_socket : real_socket) (domain, type, protocol);
84 : : }
85 : :
86 : : int
87 : : bind (int sockfd,
88 : : const struct sockaddr *addr,
89 : : socklen_t addrlen)
90 : : {
91 : 25 : if (real_bind == NULL)
92 : 1 : real_bind = dlsym (RTLD_NEXT, "bind");
93 : :
94 : 25 : return ((mock_bind != NULL) ? mock_bind : real_bind) (sockfd, addr, addrlen);
95 : : }
96 : :
97 : : int
98 : : listen (int sockfd,
99 : : int backlog)
100 : : {
101 : 21 : if (real_listen == NULL)
102 : 1 : real_listen = dlsym (RTLD_NEXT, "listen");
103 : :
104 : 21 : return ((mock_listen != NULL) ? mock_listen : real_listen) (sockfd, backlog);
105 : : }
106 : :
107 : : int
108 : : getsockopt (int sockfd,
109 : : int level,
110 : : int optname,
111 : : void *optval,
112 : : socklen_t *optlen)
113 : : {
114 : 11 : if (real_getsockopt == NULL)
115 : 1 : real_getsockopt = dlsym (RTLD_NEXT, "getsockopt");
116 : :
117 : 11 : return ((mock_getsockopt != NULL) ? mock_getsockopt : real_getsockopt) (sockfd, level, optname, optval, optlen);
118 : : }
119 : :
120 : : #endif /* MOCK_SOCKET_SUPPORTED */
121 : :
122 : : /* Test event signals. */
123 : : static void
124 : 4 : event_cb (GSocketListener *listener,
125 : : GSocketListenerEvent event,
126 : : GSocket *socket,
127 : : gpointer data)
128 : : {
129 : : static GSocketListenerEvent expected_event = G_SOCKET_LISTENER_BINDING;
130 : 4 : gboolean *success = (gboolean *)data;
131 : :
132 : 4 : g_assert (G_IS_SOCKET_LISTENER (listener));
133 : 4 : g_assert (G_IS_SOCKET (socket));
134 : 4 : g_assert (event == expected_event);
135 : :
136 : 4 : switch (event)
137 : : {
138 : 1 : case G_SOCKET_LISTENER_BINDING:
139 : 1 : expected_event = G_SOCKET_LISTENER_BOUND;
140 : 1 : break;
141 : 1 : case G_SOCKET_LISTENER_BOUND:
142 : 1 : expected_event = G_SOCKET_LISTENER_LISTENING;
143 : 1 : break;
144 : 1 : case G_SOCKET_LISTENER_LISTENING:
145 : 1 : expected_event = G_SOCKET_LISTENER_LISTENED;
146 : 1 : break;
147 : 1 : case G_SOCKET_LISTENER_LISTENED:
148 : 1 : *success = TRUE;
149 : 1 : break;
150 : : }
151 : 4 : }
152 : :
153 : : static void
154 : 1 : test_event_signal (void)
155 : : {
156 : 1 : gboolean success = FALSE;
157 : : GInetAddress *iaddr;
158 : : GSocketAddress *saddr;
159 : : GSocketListener *listener;
160 : 1 : GError *error = NULL;
161 : :
162 : 1 : iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
163 : 1 : saddr = g_inet_socket_address_new (iaddr, 0);
164 : 1 : g_object_unref (iaddr);
165 : :
166 : 1 : listener = g_socket_listener_new ();
167 : :
168 : 1 : g_signal_connect (listener, "event", G_CALLBACK (event_cb), &success);
169 : :
170 : 1 : g_socket_listener_add_address (listener,
171 : : saddr,
172 : : G_SOCKET_TYPE_STREAM,
173 : : G_SOCKET_PROTOCOL_TCP,
174 : : NULL,
175 : : NULL,
176 : : &error);
177 : 1 : g_assert_no_error (error);
178 : 1 : g_assert_true (success);
179 : :
180 : 1 : g_object_unref (saddr);
181 : 1 : g_object_unref (listener);
182 : 1 : }
183 : :
184 : : /* Provide a mock implementation of socket(), listen(), bind() and getsockopt()
185 : : * which use a simple fixed configuration to either force a call to fail with a
186 : : * given errno, or allow it to pass through to the system implementation (which
187 : : * is assumed to succeed). Results are differentiated by protocol (IPv4 or IPv6)
188 : : * but nothing more complex than that.
189 : : *
190 : : * This allows the `listen()` fallback code in
191 : : * `g_socket_listener_add_any_inet_port()` and
192 : : * `g_socket_listener_add_inet_port()` to be tested for different situations
193 : : * where IPv4 and/or IPv6 sockets don’t work. It doesn’t allow the port
194 : : * allocation retry logic to be tested (as it forces all IPv6 `bind()` calls to
195 : : * have the same result), but this means it doesn’t have to do more complex
196 : : * state tracking of fully mocked-up sockets.
197 : : *
198 : : * It also means that the test won’t work on systems which don’t support IPv6,
199 : : * or which have a configuration which causes the first test case (which passes
200 : : * all syscalls through to the system) to fail. On those systems, the test
201 : : * should be skipped rather than the mock made more complex.
202 : : */
203 : : #ifdef MOCK_SOCKET_SUPPORTED
204 : :
205 : : typedef struct {
206 : : gboolean ipv6_socket_supports_ipv4;
207 : : int ipv4_socket_errno; /* 0 for socket() to succeed on the IPv4 socket (i.e. IPv4 sockets are supported) */
208 : : int ipv6_socket_errno; /* similarly */
209 : : int ipv4_bind_errno; /* 0 for bind() to succeed on the IPv4 socket */
210 : : int ipv6_bind_errno; /* similarly */
211 : : int ipv4_listen_errno; /* 0 for listen() to succeed on the IPv4 socket */
212 : : int ipv6_listen_errno; /* similarly */
213 : : } ListenFailuresConfig;
214 : :
215 : : static struct {
216 : : /* Input: */
217 : : ListenFailuresConfig config;
218 : :
219 : : /* State (we only support tracking one socket of each type): */
220 : : int ipv4_socket_fd;
221 : : int ipv6_socket_fd;
222 : : } listen_failures_mock_state;
223 : :
224 : : static int
225 : 30 : listen_failures_socket (int domain,
226 : : int type,
227 : : int protocol)
228 : : {
229 : : int fd;
230 : :
231 : : /* Error out if told to */
232 : 30 : if (domain == AF_INET && listen_failures_mock_state.config.ipv4_socket_errno != 0)
233 : : {
234 : 2 : errno = listen_failures_mock_state.config.ipv4_socket_errno;
235 : 2 : return -1;
236 : : }
237 : 28 : else if (domain == AF_INET6 && listen_failures_mock_state.config.ipv6_socket_errno != 0)
238 : : {
239 : 4 : errno = listen_failures_mock_state.config.ipv6_socket_errno;
240 : 4 : return -1;
241 : : }
242 : 24 : else if (domain != AF_INET && domain != AF_INET6)
243 : : {
244 : : /* we don’t expect to support other socket types */
245 : : g_assert_not_reached ();
246 : : }
247 : :
248 : : /* Pass through to the system, which we require to succeed because we’re only
249 : : * mocking errors and not the full socket stack state */
250 : 24 : fd = real_socket (domain, type, protocol);
251 : 24 : g_assert_no_errno (fd);
252 : :
253 : : /* Track the returned FD for each socket type */
254 : 24 : if (domain == AF_INET)
255 : : {
256 : 6 : g_assert (listen_failures_mock_state.ipv4_socket_fd == 0);
257 : 6 : listen_failures_mock_state.ipv4_socket_fd = fd;
258 : : }
259 : 18 : else if (domain == AF_INET6)
260 : : {
261 : 18 : g_assert (listen_failures_mock_state.ipv6_socket_fd == 0);
262 : 18 : listen_failures_mock_state.ipv6_socket_fd = fd;
263 : : }
264 : :
265 : 24 : return fd;
266 : : }
267 : :
268 : : static int
269 : 24 : listen_failures_bind (int sockfd,
270 : : const struct sockaddr *addr,
271 : : socklen_t addrlen)
272 : : {
273 : : int retval;
274 : :
275 : : /* Error out if told to */
276 : 24 : if (listen_failures_mock_state.ipv4_socket_fd == sockfd &&
277 : 6 : listen_failures_mock_state.config.ipv4_bind_errno != 0)
278 : : {
279 : 0 : errno = listen_failures_mock_state.config.ipv4_bind_errno;
280 : 0 : return -1;
281 : : }
282 : 24 : else if (listen_failures_mock_state.ipv6_socket_fd == sockfd &&
283 : 18 : listen_failures_mock_state.config.ipv6_bind_errno != 0)
284 : : {
285 : 4 : errno = listen_failures_mock_state.config.ipv6_bind_errno;
286 : 4 : return -1;
287 : : }
288 : 20 : else if (listen_failures_mock_state.ipv4_socket_fd != sockfd &&
289 : 14 : listen_failures_mock_state.ipv6_socket_fd != sockfd)
290 : : {
291 : : g_assert_not_reached ();
292 : : }
293 : :
294 : : /* Pass through to the system, which we require to succeed because we’re only
295 : : * mocking errors and not the full socket stack state */
296 : 20 : retval = real_bind (sockfd, addr, addrlen);
297 : 20 : g_assert_no_errno (retval);
298 : :
299 : 20 : return retval;
300 : : }
301 : :
302 : : static int
303 : 20 : listen_failures_listen (int sockfd,
304 : : int backlog)
305 : : {
306 : : int retval;
307 : :
308 : : /* Error out if told to */
309 : 20 : if (listen_failures_mock_state.ipv4_socket_fd == sockfd &&
310 : 6 : listen_failures_mock_state.config.ipv4_listen_errno != 0)
311 : : {
312 : 1 : errno = listen_failures_mock_state.config.ipv4_listen_errno;
313 : 1 : return -1;
314 : : }
315 : 19 : else if (listen_failures_mock_state.ipv6_socket_fd == sockfd &&
316 : 14 : listen_failures_mock_state.config.ipv6_listen_errno != 0)
317 : : {
318 : 6 : errno = listen_failures_mock_state.config.ipv6_listen_errno;
319 : 6 : return -1;
320 : : }
321 : 13 : else if (listen_failures_mock_state.ipv4_socket_fd != sockfd &&
322 : 8 : listen_failures_mock_state.ipv6_socket_fd != sockfd)
323 : : {
324 : : g_assert_not_reached ();
325 : : }
326 : :
327 : : /* Pass through to the system, which we require to succeed because we’re only
328 : : * mocking errors and not the full socket stack state */
329 : 13 : retval = real_listen (sockfd, backlog);
330 : 13 : g_assert_no_errno (retval);
331 : :
332 : 13 : return retval;
333 : : }
334 : :
335 : : static int
336 : 11 : listen_failures_getsockopt (int sockfd,
337 : : int level,
338 : : int optname,
339 : : void *optval,
340 : : socklen_t *optlen)
341 : : {
342 : : /* Mock whether IPv6 sockets claim to support IPv4 */
343 : : #if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
344 : 11 : if (listen_failures_mock_state.ipv6_socket_fd == sockfd &&
345 : 11 : level == IPPROTO_IPV6 && optname == IPV6_V6ONLY)
346 : : {
347 : 11 : int *v6_only = optval;
348 : 11 : *v6_only = !listen_failures_mock_state.config.ipv6_socket_supports_ipv4;
349 : 11 : return 0;
350 : : }
351 : : #endif
352 : :
353 : : /* Don’t assert that the system getsockopt() succeeded, as it could be used
354 : : * in complex ways, and it’s incidental to what we’re actually trying to test. */
355 : 0 : return real_getsockopt (sockfd, level, optname, optval, optlen);
356 : : }
357 : :
358 : : #endif /* MOCK_SOCKET_SUPPORTED */
359 : :
360 : : static void
361 : 1 : test_add_any_inet_port_listen_failures (void)
362 : : {
363 : : #ifdef MOCK_SOCKET_SUPPORTED
364 : : const struct
365 : : {
366 : : ListenFailuresConfig config;
367 : : GQuark expected_error_domain; /* 0 if success is expected */
368 : : int expected_error_code; /* 0 if success is expected */
369 : : }
370 : 6 : test_matrix[] =
371 : : {
372 : : /* If everything works, it should all work: */
373 : : { { TRUE, 0, 0, 0, 0, 0, 0 }, 0, 0 },
374 : : /* If IPv4 sockets are not supported, IPv6 should be used: */
375 : : { { TRUE, EAFNOSUPPORT, 0, 0, 0, 0, 0 }, 0, 0 },
376 : : /* If IPv6 sockets are not supported, IPv4 should be used: */
377 : : { { TRUE, 0, EAFNOSUPPORT, 0, 0, 0, 0, }, 0, 0 },
378 : : /* If no sockets are supported, everything should fail: */
379 : : { { TRUE, EAFNOSUPPORT, EAFNOSUPPORT, 0, 0, 0, 0 },
380 : 1 : G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED },
381 : : /* If binding IPv4 fails, IPv6 should be used: */
382 : : { { TRUE, 0, 0, EADDRINUSE, 0, 0, 0 }, 0, 0 },
383 : : /* If binding IPv6 fails, fail overall (the algorithm is not symmetric): */
384 : : { { TRUE, 0, 0, 0, EADDRINUSE, 0, 0 },
385 : 1 : G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE },
386 : : /* If binding them both fails, fail overall: */
387 : : { { TRUE, 0, 0, EADDRINUSE, EADDRINUSE, 0, 0 },
388 : 1 : G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE },
389 : : /* If listening on IPv4 fails, IPv6 should be used: */
390 : : { { TRUE, 0, 0, 0, 0, EADDRINUSE, 0 }, 0, 0 },
391 : : /* If listening on IPv6 fails, IPv4 should be used:
392 : : * FIXME: If the IPv6 socket claims to support IPv4, this currently won’t
393 : : * retry with an IPv4-only socket; see https://gitlab.gnome.org/GNOME/glib/-/issues/3604 */
394 : : { { TRUE, 0, 0, 0, 0, 0, EADDRINUSE },
395 : 1 : G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE },
396 : : /* If listening on IPv6 fails (and the IPv6 socket doesn’t claim to
397 : : * support IPv4), IPv4 should be used: */
398 : : { { FALSE, 0, 0, 0, 0, 0, EADDRINUSE }, 0, 0 },
399 : : /* If listening on both fails, fail overall: */
400 : : { { TRUE, 0, 0, 0, 0, EADDRINUSE, EADDRINUSE },
401 : 1 : G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE },
402 : : };
403 : :
404 : : /* Override the socket(), bind(), listen() and getsockopt() functions */
405 : 1 : mock_socket = listen_failures_socket;
406 : 1 : mock_bind = listen_failures_bind;
407 : 1 : mock_listen = listen_failures_listen;
408 : 1 : mock_getsockopt = listen_failures_getsockopt;
409 : :
410 : 1 : g_test_summary ("Test that adding a listening port succeeds if either "
411 : : "listening on IPv4 or IPv6 succeeds");
412 : :
413 : 12 : for (size_t i = 0; i < G_N_ELEMENTS (test_matrix); i++)
414 : : {
415 : 11 : GSocketService *service = NULL;
416 : 11 : GError *local_error = NULL;
417 : : uint16_t port;
418 : :
419 : 11 : g_test_message ("Test %" G_GSIZE_FORMAT, i);
420 : :
421 : : /* Configure the mock socket behaviour. */
422 : 11 : memset (&listen_failures_mock_state, 0, sizeof (listen_failures_mock_state));
423 : 11 : listen_failures_mock_state.config = test_matrix[i].config;
424 : :
425 : : /* Create a GSocketService to test. */
426 : 11 : service = g_socket_service_new ();
427 : 11 : port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &local_error);
428 : :
429 : 11 : if (test_matrix[i].expected_error_domain == 0)
430 : : {
431 : 6 : g_assert_no_error (local_error);
432 : 6 : g_assert_cmpuint (port, !=, 0);
433 : : }
434 : : else
435 : : {
436 : 5 : g_assert_error (local_error, test_matrix[i].expected_error_domain,
437 : : test_matrix[i].expected_error_code);
438 : 5 : g_assert_cmpuint (port, ==, 0);
439 : : }
440 : :
441 : 11 : g_clear_error (&local_error);
442 : 11 : g_socket_listener_close (G_SOCKET_LISTENER (service));
443 : 11 : g_clear_object (&service);
444 : : }
445 : :
446 : : /* Tidy up. */
447 : 1 : mock_socket = NULL;
448 : 1 : mock_bind = NULL;
449 : 1 : mock_listen = NULL;
450 : 1 : mock_getsockopt = NULL;
451 : 1 : memset (&listen_failures_mock_state, 0, sizeof (listen_failures_mock_state));
452 : : #else /* if !MOCK_SOCKET_SUPPORTED */
453 : : g_test_skip ("Mock socket not supported");
454 : : #endif
455 : 1 : }
456 : :
457 : : static void
458 : 1 : test_add_inet_port_listen_failures (void)
459 : : {
460 : : #ifdef MOCK_SOCKET_SUPPORTED
461 : : const struct
462 : : {
463 : : ListenFailuresConfig config;
464 : : GQuark expected_error_domain; /* 0 if success is expected */
465 : : int expected_error_code; /* 0 if success is expected */
466 : : }
467 : 5 : test_matrix[] =
468 : : {
469 : : /* If everything works, it should all work: */
470 : : { { TRUE, 0, 0, 0, 0, 0, 0 }, 0, 0 },
471 : : /* If IPv4 sockets are not supported, IPv6 should be used: */
472 : : { { TRUE, EAFNOSUPPORT, 0, 0, 0, 0, 0 }, 0, 0 },
473 : : /* If IPv6 sockets are not supported, IPv4 should be used: */
474 : : { { TRUE, 0, EAFNOSUPPORT, 0, 0, 0, 0, }, 0, 0 },
475 : : /* If no sockets are supported, everything should fail: */
476 : : { { TRUE, EAFNOSUPPORT, EAFNOSUPPORT, 0, 0, 0, 0 },
477 : 1 : G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED },
478 : : /* If binding IPv4 fails, IPv6 should be used: */
479 : : { { TRUE, 0, 0, EADDRINUSE, 0, 0, 0 }, 0, 0 },
480 : : /* If binding IPv6 fails, fail overall (the algorithm is not symmetric): */
481 : : { { TRUE, 0, 0, 0, EADDRINUSE, 0, 0 },
482 : 1 : G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE },
483 : : /* If binding them both fails, fail overall: */
484 : : { { TRUE, 0, 0, EADDRINUSE, EADDRINUSE, 0, 0 },
485 : 1 : G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE },
486 : : /* If listening on IPv4 fails, IPv6 should be used: */
487 : : { { TRUE, 0, 0, 0, 0, EADDRINUSE, 0 }, 0, 0 },
488 : : /* If listening on IPv6 fails, IPv4 should be used: */
489 : : { { TRUE, 0, 0, 0, 0, 0, EADDRINUSE }, 0, 0 },
490 : : /* If listening on IPv6 fails (and the IPv6 socket doesn’t claim to
491 : : * support IPv4), IPv4 should be used: */
492 : : { { FALSE, 0, 0, 0, 0, 0, EADDRINUSE }, 0, 0 },
493 : : /* If listening on both fails, fail overall: */
494 : : { { TRUE, 0, 0, 0, 0, EADDRINUSE, EADDRINUSE },
495 : 1 : G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE },
496 : : };
497 : :
498 : : /* Override the socket(), bind(), listen() and getsockopt() functions */
499 : 1 : mock_socket = listen_failures_socket;
500 : 1 : mock_bind = listen_failures_bind;
501 : 1 : mock_listen = listen_failures_listen;
502 : 1 : mock_getsockopt = listen_failures_getsockopt;
503 : :
504 : 1 : g_test_summary ("Test that adding a listening port succeeds if either "
505 : : "listening on IPv4 or IPv6 succeeds");
506 : :
507 : 12 : for (size_t i = 0; i < G_N_ELEMENTS (test_matrix); i++)
508 : : {
509 : 11 : GSocketService *service = NULL;
510 : 11 : GError *local_error = NULL;
511 : : gboolean retval;
512 : :
513 : 11 : g_test_message ("Test %" G_GSIZE_FORMAT, i);
514 : :
515 : : /* Configure the mock socket behaviour. */
516 : 11 : memset (&listen_failures_mock_state, 0, sizeof (listen_failures_mock_state));
517 : 11 : listen_failures_mock_state.config = test_matrix[i].config;
518 : :
519 : : /* Create a GSocketService to test. */
520 : 11 : service = g_socket_service_new ();
521 : 11 : retval = g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service), 4321, NULL, &local_error);
522 : :
523 : 11 : if (test_matrix[i].expected_error_domain == 0)
524 : : {
525 : 7 : g_assert_no_error (local_error);
526 : 7 : g_assert_true (retval);
527 : : }
528 : : else
529 : : {
530 : 4 : g_assert_error (local_error, test_matrix[i].expected_error_domain,
531 : : test_matrix[i].expected_error_code);
532 : 4 : g_assert_false (retval);
533 : : }
534 : :
535 : 11 : g_clear_error (&local_error);
536 : :
537 : 11 : g_socket_listener_close (G_SOCKET_LISTENER (service));
538 : 11 : g_clear_object (&service);
539 : : }
540 : :
541 : : /* Tidy up. */
542 : 1 : mock_socket = NULL;
543 : 1 : mock_bind = NULL;
544 : 1 : mock_listen = NULL;
545 : 1 : mock_getsockopt = NULL;
546 : 1 : memset (&listen_failures_mock_state, 0, sizeof (listen_failures_mock_state));
547 : : #else /* if !MOCK_SOCKET_SUPPORTED */
548 : : g_test_skip ("Mock socket not supported");
549 : : #endif
550 : 1 : }
551 : :
552 : : int
553 : 1 : main (int argc,
554 : : char *argv[])
555 : : {
556 : 1 : g_test_init (&argc, &argv, NULL);
557 : :
558 : 1 : g_test_add_func ("/socket-listener/event-signal", test_event_signal);
559 : 1 : g_test_add_func ("/socket-listener/add-any-inet-port/listen-failures", test_add_any_inet_port_listen_failures);
560 : 1 : g_test_add_func ("/socket-listener/add-inet-port/listen-failures", test_add_inet_port_listen_failures);
561 : :
562 : 1 : return g_test_run();
563 : : }
|