Skip to content

Commit 018e9d7

Browse files
committed
test: socket option round-trips on every backend
Add a dedicated test for the socket_option public header: get/set round-trips for boolean, integer, and linger options on tcp, udp, local stream, and local datagram sockets, bound-socket local_endpoint readback, the closed-socket logic_error guards, and an unsupported option reporting a system error.
1 parent a684c9b commit 018e9d7

1 file changed

Lines changed: 223 additions & 0 deletions

File tree

test/unit/socket_option.cpp

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
//
2+
// Copyright (c) 2026 Steve Gerbino
3+
//
4+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6+
//
7+
// Official repository: https://github.com/cppalliance/corosio
8+
//
9+
10+
// Test that header file is self-contained.
11+
#include <boost/corosio/socket_option.hpp>
12+
13+
#include <boost/corosio/io_context.hpp>
14+
#include <boost/corosio/tcp.hpp>
15+
#include <boost/corosio/tcp_socket.hpp>
16+
#include <boost/corosio/udp.hpp>
17+
#include <boost/corosio/udp_socket.hpp>
18+
19+
#include <boost/corosio/detail/platform.hpp>
20+
21+
#if BOOST_COROSIO_POSIX
22+
#include <boost/corosio/local_connect_pair.hpp>
23+
#include <boost/corosio/local_datagram_socket.hpp>
24+
#include <boost/corosio/local_stream_socket.hpp>
25+
#endif
26+
27+
#include <stdexcept>
28+
#include <system_error>
29+
30+
#include "context.hpp"
31+
#include "test_suite.hpp"
32+
33+
namespace boost::corosio {
34+
35+
// Option get/set round-trips on every socket type. The per-type I/O
36+
// tests set options incidentally; this suite pins down the option
37+
// plumbing itself (set_option/get_option virtuals on each backend's
38+
// socket implementation) and the closed-socket guards.
39+
40+
template<auto Backend>
41+
struct socket_option_test
42+
{
43+
void testTcpOptions()
44+
{
45+
io_context ioc(Backend);
46+
tcp_socket sock(ioc);
47+
sock.open();
48+
49+
sock.set_option(socket_option::no_delay(true));
50+
BOOST_TEST(sock.get_option<socket_option::no_delay>().value());
51+
sock.set_option(socket_option::no_delay(false));
52+
BOOST_TEST(!sock.get_option<socket_option::no_delay>().value());
53+
54+
sock.set_option(socket_option::keep_alive(true));
55+
BOOST_TEST(sock.get_option<socket_option::keep_alive>().value());
56+
57+
sock.set_option(socket_option::reuse_address(true));
58+
BOOST_TEST(sock.get_option<socket_option::reuse_address>().value());
59+
60+
// Kernels round buffer sizes (Linux doubles them); only require
61+
// that the readback is at least what was requested.
62+
sock.set_option(socket_option::receive_buffer_size(16384));
63+
BOOST_TEST_GE(
64+
sock.get_option<socket_option::receive_buffer_size>().value(),
65+
16384);
66+
sock.set_option(socket_option::send_buffer_size(16384));
67+
BOOST_TEST_GE(
68+
sock.get_option<socket_option::send_buffer_size>().value(),
69+
16384);
70+
71+
sock.set_option(socket_option::linger(true, 5));
72+
auto lg = sock.get_option<socket_option::linger>();
73+
BOOST_TEST(lg.enabled());
74+
BOOST_TEST_EQ(lg.timeout(), 5);
75+
76+
sock.close();
77+
}
78+
79+
// Bound-socket local_endpoint readback on every backend.
80+
void testTcpLocalEndpoint()
81+
{
82+
io_context ioc(Backend);
83+
tcp_socket sock(ioc);
84+
sock.open();
85+
86+
auto ec = sock.bind(endpoint(ipv4_address::loopback(), 0));
87+
BOOST_TEST(!ec);
88+
89+
auto ep = sock.local_endpoint();
90+
BOOST_TEST(ep.is_v4());
91+
BOOST_TEST(ep.v4_address() == ipv4_address::loopback());
92+
BOOST_TEST_GT(ep.port(), 0);
93+
94+
sock.close();
95+
}
96+
97+
void testUdpOptions()
98+
{
99+
io_context ioc(Backend);
100+
udp_socket sock(ioc);
101+
sock.open(udp::v4());
102+
103+
sock.set_option(socket_option::broadcast(true));
104+
BOOST_TEST(sock.get_option<socket_option::broadcast>().value());
105+
106+
sock.set_option(socket_option::reuse_address(true));
107+
BOOST_TEST(sock.get_option<socket_option::reuse_address>().value());
108+
109+
sock.set_option(socket_option::receive_buffer_size(16384));
110+
BOOST_TEST_GE(
111+
sock.get_option<socket_option::receive_buffer_size>().value(),
112+
16384);
113+
114+
sock.close();
115+
}
116+
117+
void testClosedSocketThrows()
118+
{
119+
io_context ioc(Backend);
120+
tcp_socket sock(ioc);
121+
122+
bool set_threw = false;
123+
try
124+
{
125+
sock.set_option(socket_option::no_delay(true));
126+
}
127+
catch (std::logic_error const&)
128+
{
129+
set_threw = true;
130+
}
131+
BOOST_TEST(set_threw);
132+
133+
bool get_threw = false;
134+
try
135+
{
136+
(void)sock.get_option<socket_option::no_delay>();
137+
}
138+
catch (std::logic_error const&)
139+
{
140+
get_threw = true;
141+
}
142+
BOOST_TEST(get_threw);
143+
}
144+
145+
// An option the protocol does not support reports a system error.
146+
void testInvalidOptionReportsError()
147+
{
148+
io_context ioc(Backend);
149+
udp_socket sock(ioc);
150+
sock.open(udp::v4());
151+
152+
bool threw = false;
153+
try
154+
{
155+
// TCP_NODELAY on a UDP socket.
156+
sock.set_option(socket_option::no_delay(true));
157+
}
158+
catch (std::system_error const&)
159+
{
160+
threw = true;
161+
}
162+
BOOST_TEST(threw);
163+
164+
sock.close();
165+
}
166+
167+
#if BOOST_COROSIO_POSIX
168+
169+
void testLocalStreamOptions()
170+
{
171+
io_context ioc(Backend);
172+
local_stream_socket s1(ioc), s2(ioc);
173+
if (auto ec = connect_pair(s1, s2))
174+
throw std::system_error(ec, "connect_pair");
175+
176+
s1.set_option(socket_option::receive_buffer_size(16384));
177+
BOOST_TEST_GE(
178+
s1.get_option<socket_option::receive_buffer_size>().value(),
179+
16384);
180+
181+
s1.set_option(socket_option::send_buffer_size(16384));
182+
BOOST_TEST_GE(
183+
s1.get_option<socket_option::send_buffer_size>().value(),
184+
16384);
185+
}
186+
187+
void testLocalDatagramOptions()
188+
{
189+
io_context ioc(Backend);
190+
local_datagram_socket s1(ioc), s2(ioc);
191+
if (auto ec = connect_pair(s1, s2))
192+
throw std::system_error(ec, "connect_pair");
193+
194+
s1.set_option(socket_option::receive_buffer_size(16384));
195+
BOOST_TEST_GE(
196+
s1.get_option<socket_option::receive_buffer_size>().value(),
197+
16384);
198+
199+
s1.set_option(socket_option::send_buffer_size(16384));
200+
BOOST_TEST_GE(
201+
s1.get_option<socket_option::send_buffer_size>().value(),
202+
16384);
203+
}
204+
205+
#endif // BOOST_COROSIO_POSIX
206+
207+
void run()
208+
{
209+
testTcpOptions();
210+
testTcpLocalEndpoint();
211+
testUdpOptions();
212+
testClosedSocketThrows();
213+
testInvalidOptionReportsError();
214+
#if BOOST_COROSIO_POSIX
215+
testLocalStreamOptions();
216+
testLocalDatagramOptions();
217+
#endif
218+
}
219+
};
220+
221+
COROSIO_BACKEND_TESTS(socket_option_test, "boost.corosio.socket_option")
222+
223+
} // namespace boost::corosio

0 commit comments

Comments
 (0)