cheatah
Source

tests/purrc/socket_sys_test.cpp

1// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).
2// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.
3// System-level test for the `socket` stdlib module: ONE cohesive program that
4// exercises EVERY purr-callable function in stdlib/socket/socket.hpp end to end
5// (purrc + the C++ backend + the runtime + the linked libcheatah_socket).
6//
7// Unlike the per-function compile-run probes (socket_cr_test.cpp), this stands up
8// real loopback TCP connections on 127.0.0.1 and does full round-trips inside a
9// SINGLE cheatah process, driving both the low-level BSD path and the high-level
10// convenience helpers:
11//
12// low-level : socket -> set_reuseaddr -> bind -> listen -> local_port
13// -> (client) socket -> connect -> accept
14// -> send / recv / sendall / recv -> close
15// high-level: tcp_listen -> local_port -> tcp_connect -> accept
16// -> sendall -> recv
17// error path: connect(-1, ...) deliberately fails -> last_error() is non-empty
18//
19// All 14 exported functions are called: tcp_listen, tcp_connect, accept, recv,
20// send, sendall, close, socket, set_reuseaddr, bind, listen, connect,
21// local_port, last_error.
22//
23// Why it doesn't deadlock in one process: for 127.0.0.1 the kernel completes the
24// TCP handshake on connect() and queues the connection on the listener's accept
25// backlog, so we connect() BEFORE accept() and accept() returns immediately. The
26// payloads are tiny (fit the send buffer), so send()/sendall() never block on a
27// reader. Ports are OS-assigned (bind to port 0) so nothing depends on a fixed
28// port or external network. Output is only booleans + fixed labels, so it is
29// fully deterministic and asserted byte-for-byte. The harness runs the program
30// under `timeout` so a regression that blocks fails fast instead of hanging.
32#include "e2e_harness.hpp"
35TEST(StdlibE2E, Socket) {
36 e2e::expect_e2e("socket_sys", R"PURR(import io
37import socket
39# ---- low-level BSD path: socket/set_reuseaddr/bind/listen/local_port ----
40let srv = socket.socket()
41let reuse = socket.set_reuseaddr(srv)
42let bound = socket.bind(srv, "127.0.0.1", 0)
43let lstn = socket.listen(srv, 8)
44let port = socket.local_port(srv)
46# client socket, connect BEFORE accept (kernel queues the loopback handshake)
47let cli = socket.socket()
48let conn = socket.connect(cli, "127.0.0.1", port)
49let peer = socket.accept(srv)
51# ---- per-connection I/O: send + sendall + recv ----
52let s1 = socket.send(cli, "AB")
53let got1 = socket.recv(peer, 16)
54let s2 = socket.sendall(peer, "PONG")
55let got2 = socket.recv(cli, 16)
57# ---- high-level convenience path: tcp_listen / tcp_connect ----
58let hl_srv = socket.tcp_listen("127.0.0.1", 0, 8)
59let hl_port = socket.local_port(hl_srv)
60let hl_cli = socket.tcp_connect("127.0.0.1", hl_port)
61let hl_peer = socket.accept(hl_srv)
62let hl_s = socket.sendall(hl_cli, "hi")
63let hl_got = socket.recv(hl_peer, 16)
65# ---- deliberate failure + last_error ----
66let fail = socket.connect(-1, "127.0.0.1", 1)
67let err = socket.last_error()
69# ---- verdicts (deterministic) ----
70io.print("socket_ok", srv >= 0)
71io.print("reuse_ok", reuse == 0)
72io.print("bind_ok", bound == 0)
73io.print("listen_ok", lstn == 0)
74io.print("port_ok", port > 0)
75io.print("connect_ok", conn == 0)
76io.print("accept_ok", peer >= 0)
77io.print("send_ok", s1 == 2)
78io.print("recv1_ok", got1 == "AB")
79io.print("sendall_ok", s2 == 0)
80io.print("recv2_ok", got2 == "PONG")
81io.print("tcp_listen_ok", hl_srv >= 0)
82io.print("tcp_connect_ok", hl_cli >= 0)
83io.print("hl_roundtrip_ok", hl_got == "hi")
84io.print("fail_ok", fail < 0)
85io.print("last_error_ok", err != "")
87let c1 = socket.close(peer)
88let c2 = socket.close(cli)
89let c3 = socket.close(srv)
90socket.close(hl_peer)
91socket.close(hl_cli)
92socket.close(hl_srv)
93io.print("close_ok", c1 == 0, c2 == 0, c3 == 0)
94)PURR",
95 "socket_ok True\n"
96 "reuse_ok True\n"
97 "bind_ok True\n"
98 "listen_ok True\n"
99 "port_ok True\n"
100 "connect_ok True\n"
101 "accept_ok True\n"
102 "send_ok True\n"
103 "recv1_ok True\n"
104 "sendall_ok True\n"
105 "recv2_ok True\n"
106 "tcp_listen_ok True\n"
107 "tcp_connect_ok True\n"
108 "hl_roundtrip_ok True\n"
109 "fail_ok True\n"
110 "last_error_ok True\n"
111 "close_ok True True True\n");