Coverage Report

Created: 2026-10-24 08:16

/work/testing/support/doubles/fake_sockets_test.cc
Line
Count
Source
1
#include "fake_sockets.hh"
2
3
#include <gtest/gtest.h>
4
5
#include "network_universe.hh"
6
7
namespace tox::test {
8
namespace {
9
10
    class FakeTcpSocketTest : public ::testing::Test {
11
    public:
12
        ~FakeTcpSocketTest() override;
13
14
    protected:
15
        NetworkUniverse universe;
16
        FakeTcpSocket server{universe};
17
        FakeTcpSocket client{universe};
18
    };
19
20
5
    FakeTcpSocketTest::~FakeTcpSocketTest() = default;
21
22
    TEST_F(FakeTcpSocketTest, ConnectAndAccept)
23
1
    {
24
1
        IP_Port server_addr;
25
1
        ip_init(&server_addr.ip, false);
26
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
27
1
        server_addr.port = net_htons(8080);
28
29
1
        ASSERT_EQ(server.bind(&server_addr), 0);
30
1
        ASSERT_EQ(server.listen(5), 0);
31
32
        // Client connects
33
1
        ASSERT_EQ(client.connect(&server_addr), -1);
34
1
        ASSERT_EQ(errno, EINPROGRESS);
35
36
        // Process events (Client SYN -> Server)
37
1
        universe.process_events(0);
38
39
        // Server accepts (SYN-ACK -> Client)
40
1
        universe.process_events(0);
41
42
        // Client receives SYN-ACK, sends ACK (ACK -> Server)
43
1
        universe.process_events(0);
44
45
        // Server receives ACK, connection established
46
1
        IP_Port client_addr;
47
1
        auto accepted = server.accept(&client_addr);
48
1
        ASSERT_NE(accepted, nullptr);
49
1
        auto *accepted_tcp = static_cast<FakeTcpSocket *>(accepted.get());
50
1
        EXPECT_EQ(accepted_tcp->state(), FakeTcpSocket::ESTABLISHED);
51
52
1
        EXPECT_EQ(client.state(), FakeTcpSocket::ESTABLISHED);
53
1
    }
54
55
    TEST_F(FakeTcpSocketTest, DataTransfer)
56
1
    {
57
1
        IP_Port server_addr;
58
1
        ip_init(&server_addr.ip, false);
59
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
60
1
        server_addr.port = net_htons(8081);
61
62
1
        server.bind(&server_addr);
63
1
        server.listen(5);
64
1
        client.connect(&server_addr);
65
66
        // Handshake
67
1
        universe.process_events(0);  // SYN
68
1
        universe.process_events(0);  // SYN-ACK
69
1
        universe.process_events(0);  // ACK
70
71
1
        auto accepted = server.accept(nullptr);
72
1
        ASSERT_NE(accepted, nullptr);
73
74
        // Send data Client -> Server
75
1
        uint8_t send_buf[] = "Hello";
76
1
        ASSERT_EQ(client.send(send_buf, 5), 5);
77
78
1
        universe.process_events(0);  // Data packet
79
80
1
        uint8_t recv_buf[10];
81
1
        ASSERT_EQ(accepted->recv(recv_buf, 10), 5);
82
1
        EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), 5), "Hello");
83
1
    }
84
85
    TEST_F(FakeTcpSocketTest, RecvBuffering)
86
1
    {
87
1
        IP_Port server_addr;
88
1
        ip_init(&server_addr.ip, false);
89
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
90
1
        server_addr.port = net_htons(8082);
91
92
1
        server.bind(&server_addr);
93
1
        server.listen(5);
94
1
        client.connect(&server_addr);
95
96
1
        universe.process_events(0);  // SYN
97
1
        universe.process_events(0);  // SYN-ACK
98
1
        universe.process_events(0);  // ACK
99
100
1
        auto accepted = server.accept(nullptr);
101
1
        ASSERT_NE(accepted, nullptr);
102
103
1
        uint8_t msg1[] = "Part1";
104
1
        uint8_t msg2[] = "Part2";
105
1
        client.send(msg1, 5);
106
1
        client.send(msg2, 5);
107
108
1
        universe.process_events(0);  // Deliver Part1
109
1
        universe.process_events(0);  // Deliver Part2
110
111
1
        EXPECT_EQ(accepted->recv_buffer_size(), 10);
112
113
1
        uint8_t recv_buf[20];
114
        // Read partial
115
1
        ASSERT_EQ(accepted->recv(recv_buf, 3), 3);
116
1
        EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), 3), "Par");
117
1
        EXPECT_EQ(accepted->recv_buffer_size(), 7);
118
119
        // Read rest
120
1
        ASSERT_EQ(accepted->recv(recv_buf, 7), 7);
121
1
        EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), 7), "t1Part2");
122
1
        EXPECT_EQ(accepted->recv_buffer_size(), 0);
123
1
    }
124
125
    class FakeUdpSocketTest : public ::testing::Test {
126
    public:
127
        ~FakeUdpSocketTest() override;
128
129
    protected:
130
        NetworkUniverse universe;
131
        FakeUdpSocket server{universe};
132
        FakeUdpSocket client{universe};
133
    };
134
135
3
    FakeUdpSocketTest::~FakeUdpSocketTest() = default;
136
137
    TEST_F(FakeUdpSocketTest, BindAndSendTo)
138
1
    {
139
1
        IP_Port server_addr;
140
1
        ip_init(&server_addr.ip, false);
141
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
142
1
        server_addr.port = net_htons(9000);
143
144
1
        ASSERT_EQ(server.bind(&server_addr), 0);
145
146
1
        const char *message = "UDP Packet";
147
1
        ASSERT_EQ(client.sendto(
148
1
                      reinterpret_cast<const uint8_t *>(message), strlen(message), &server_addr),
149
1
            strlen(message));
150
151
1
        universe.process_events(0);
152
153
1
        IP_Port sender_addr;
154
1
        uint8_t recv_buf[100];
155
1
        int len = server.recvfrom(recv_buf, sizeof(recv_buf), &sender_addr);
156
157
1
        ASSERT_GT(len, 0);
158
1
        EXPECT_EQ(std::string(reinterpret_cast<char *>(recv_buf), len), message);
159
1
        EXPECT_EQ(sender_addr.port, net_htons(client.local_port()));
160
1
    }
161
162
    TEST_F(FakeUdpSocketTest, RecvBuffering)
163
1
    {
164
1
        IP_Port server_addr;
165
1
        ip_init(&server_addr.ip, false);
166
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
167
1
        server_addr.port = net_htons(9001);
168
169
1
        server.bind(&server_addr);
170
171
1
        const char *msg1 = "Msg1";
172
1
        const char *msg2 = "Msg2";
173
174
1
        client.sendto(reinterpret_cast<const uint8_t *>(msg1), strlen(msg1), &server_addr);
175
1
        client.sendto(reinterpret_cast<const uint8_t *>(msg2), strlen(msg2), &server_addr);
176
177
1
        universe.process_events(0);  // Deliver msg1
178
1
        universe.process_events(0);  // Deliver msg2
179
180
1
        EXPECT_EQ(server.recv_buffer_size(), 2);
181
182
1
        IP_Port sender;
183
1
        uint8_t buf[10];
184
185
1
        int len = server.recvfrom(buf, sizeof(buf), &sender);
186
1
        ASSERT_EQ(len, 4);
187
1
        EXPECT_EQ(std::string(reinterpret_cast<char *>(buf), len), "Msg1");
188
1
        EXPECT_EQ(server.recv_buffer_size(), 1);
189
190
1
        len = server.recvfrom(buf, sizeof(buf), &sender);
191
1
        ASSERT_EQ(len, 4);
192
1
        EXPECT_EQ(std::string(reinterpret_cast<char *>(buf), len), "Msg2");
193
1
        EXPECT_EQ(server.recv_buffer_size(), 0);
194
1
    }
195
196
    TEST_F(FakeUdpSocketTest, QueueLimit)
197
1
    {
198
1
        IP_Port server_addr;
199
1
        ip_init(&server_addr.ip, false);
200
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
201
1
        server_addr.port = net_htons(9002);
202
203
1
        ASSERT_EQ(server.bind(&server_addr), 0);
204
205
        // Fill the queue
206
1.02k
        for (std::size_t i = 0; i < FakeUdpSocket::kMaxQueueSize; ++i) {
207
1.02k
            uint8_t data = static_cast<uint8_t>(i % 256);
208
1.02k
            ASSERT_EQ(client.sendto(&data, 1, &server_addr), 1);
209
1.02k
        }
210
211
1
        universe.process_events(0);
212
213
        // This packet should be dropped
214
1
        uint8_t dropped_data = 0xFF;
215
1
        ASSERT_EQ(client.sendto(&dropped_data, 1, &server_addr), 1);
216
1
        universe.process_events(0);
217
218
        // Verify we can read MaxQueueSize packets
219
1.02k
        for (std::size_t i = 0; i < FakeUdpSocket::kMaxQueueSize; ++i) {
220
1.02k
            uint8_t recv_buf[1];
221
1.02k
            IP_Port from;
222
1.02k
            ASSERT_EQ(server.recvfrom(recv_buf, 1, &from), 1);
223
1.02k
        }
224
225
        // The queue should now be empty
226
1
        uint8_t dummy[1];
227
1
        IP_Port from;
228
1
        EXPECT_EQ(server.recvfrom(dummy, 1, &from), -1);
229
1
        EXPECT_EQ(errno, EWOULDBLOCK);
230
1
    }
231
232
    TEST_F(FakeTcpSocketTest, BacklogLimit)
233
1
    {
234
1
        IP_Port server_addr;
235
1
        ip_init(&server_addr.ip, false);
236
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
237
1
        server_addr.port = net_htons(8082);
238
239
1
        ASSERT_EQ(server.bind(&server_addr), 0);
240
        // Small backlog for testing
241
1
        ASSERT_EQ(server.listen(2), 0);
242
243
        // Client 1
244
1
        FakeTcpSocket client1{universe};
245
1
        client1.connect(&server_addr);
246
        // Client 2
247
1
        FakeTcpSocket client2{universe};
248
1
        client2.connect(&server_addr);
249
        // Client 3 (Should be dropped)
250
1
        FakeTcpSocket client3{universe};
251
1
        client3.connect(&server_addr);
252
253
1
        universe.process_events(0);  // Deliver SYNs
254
1
        universe.process_events(0);  // Deliver SYN-ACKs
255
1
        universe.process_events(0);  // Deliver ACKs
256
257
        // Accept first two
258
1
        ASSERT_NE(server.accept(nullptr), nullptr);
259
1
        ASSERT_NE(server.accept(nullptr), nullptr);
260
261
        // Third should not be there
262
1
        EXPECT_EQ(server.accept(nullptr), nullptr);
263
1
        EXPECT_EQ(errno, EWOULDBLOCK);
264
1
    }
265
266
    TEST_F(FakeTcpSocketTest, BufferLimit)
267
1
    {
268
1
        IP_Port server_addr;
269
1
        ip_init(&server_addr.ip, false);
270
1
        server_addr.ip.ip.v4.uint32 = net_htonl(0x7F000001);
271
1
        server_addr.port = net_htons(8083);
272
273
1
        server.bind(&server_addr);
274
1
        server.listen(5);
275
1
        client.connect(&server_addr);
276
277
        // Handshake
278
1
        universe.process_events(0);  // SYN
279
1
        universe.process_events(0);  // SYN-ACK
280
1
        universe.process_events(0);  // ACK
281
282
1
        auto accepted = server.accept(nullptr);
283
1
        ASSERT_NE(accepted, nullptr);
284
285
        // Fill buffer to just below limit
286
1
        std::vector<uint8_t> large_data(FakeTcpSocket::kMaxBufferSize - 10, 'A');
287
1
        ASSERT_EQ(client.send(large_data.data(), large_data.size()), large_data.size());
288
1
        universe.process_events(0);
289
290
1
        EXPECT_EQ(accepted->recv_buffer_size(), FakeTcpSocket::kMaxBufferSize - 10);
291
292
        // Send 20 more bytes, total would exceed limit
293
1
        uint8_t extra_data[20];
294
1
        ASSERT_EQ(client.send(extra_data, 20), 20);
295
1
        universe.process_events(0);
296
297
        // Size should remain the same
298
1
        EXPECT_EQ(accepted->recv_buffer_size(), FakeTcpSocket::kMaxBufferSize - 10);
299
1
    }
300
301
}  // namespace
302
}  // namespace tox::test
303
304
// end of file