Source
tests/purrc/socket_cr_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
// Compile-run unit tests for the `socket` module: one test per function. Each4
// writes a tiny .purr that calls a single socket function, compiles it with5
// purrc, runs it under the cheatah runtime, and asserts the exact stdout.6
// Complements the in-process unit tests (stdlib/tests/socket_test.cpp) and the7
// per-module system-level test (StdlibE2E.Socket).8
//9
// Real networking has no fixed output, so each program asserts DETERMINISTIC10
// PROPERTIES as booleans (io.print emits "True"/"False"): bind to 127.0.0.111
// port 0 (OS-assigned) so nothing depends on a fixed port or external network,12
// connect to port 1 (nothing listens there) for the refusal paths, and use a13
// bad fd (-1) for the error paths. Functions that block waiting on a peer are14
// exercised only through their non-blocking bad-fd error path.15
#include "e2e_harness.hpp"17
// tcp_listen: binding a listener on 127.0.0.1:0 yields a valid (>= 0) fd.18
TEST(SocketCompileRun, TcpListen) {19
e2e::expect_e2e("socket_tcp_listen", R"PURR(import io20
import socket21
let fd = socket.tcp_listen("127.0.0.1", 0, 1)22
io.print(fd >= 0)23
socket.close(fd)24
)PURR", "True\n");25
}27
// local_port: after binding to port 0 the OS assigns a real (> 0) port.28
TEST(SocketCompileRun, LocalPort) {29
e2e::expect_e2e("socket_local_port", R"PURR(import io30
import socket31
let fd = socket.tcp_listen("127.0.0.1", 0, 1)32
io.print(socket.local_port(fd) > 0)33
socket.close(fd)34
)PURR", "True\n");35
}37
// tcp_connect: connecting to port 1 (nothing listening) is refused -> < 0.38
TEST(SocketCompileRun, TcpConnect) {39
e2e::expect_e2e("socket_tcp_connect", R"PURR(import io40
import socket41
io.print(socket.tcp_connect("127.0.0.1", 1) < 0)42
)PURR", "True\n");43
}45
// close: closing a live fd returns 0; closing a bad fd returns < 0.46
TEST(SocketCompileRun, Close) {47
e2e::expect_e2e("socket_close", R"PURR(import io48
import socket49
let fd = socket.tcp_listen("127.0.0.1", 0, 1)50
io.print(socket.close(fd) == 0, socket.close(-1) < 0)51
)PURR", "True True\n");52
}54
// socket: creating a raw IPv4 TCP socket yields a valid (>= 0) fd.55
TEST(SocketCompileRun, Socket) {56
e2e::expect_e2e("socket_socket", R"PURR(import io57
import socket58
let fd = socket.socket()59
io.print(fd >= 0)60
socket.close(fd)61
)PURR", "True\n");62
}64
// set_reuseaddr: enabling SO_REUSEADDR on a fresh socket succeeds (returns 0).65
TEST(SocketCompileRun, SetReuseaddr) {66
e2e::expect_e2e("socket_set_reuseaddr", R"PURR(import io67
import socket68
let fd = socket.socket()69
io.print(socket.set_reuseaddr(fd) == 0)70
socket.close(fd)71
)PURR", "True\n");72
}74
// bind: binding a socket to 127.0.0.1:0 succeeds (returns 0).75
TEST(SocketCompileRun, Bind) {76
e2e::expect_e2e("socket_bind", R"PURR(import io77
import socket78
let fd = socket.socket()79
io.print(socket.bind(fd, "127.0.0.1", 0) == 0)80
socket.close(fd)81
)PURR", "True\n");82
}84
// listen: marking a bound socket passive returns 0; listen on a bad fd < 0.85
TEST(SocketCompileRun, Listen) {86
e2e::expect_e2e("socket_listen", R"PURR(import io87
import socket88
let fd = socket.socket()89
socket.bind(fd, "127.0.0.1", 0)90
io.print(socket.listen(fd, 1) == 0, socket.listen(-1, 1) < 0)91
socket.close(fd)92
)PURR", "True True\n");93
}95
// connect: connecting to port 1 (nothing listening) is refused -> < 0.96
TEST(SocketCompileRun, Connect) {97
e2e::expect_e2e("socket_connect", R"PURR(import io98
import socket99
let fd = socket.socket()100
io.print(socket.connect(fd, "127.0.0.1", 1) < 0)101
socket.close(fd)102
)PURR", "True\n");103
}105
// last_error: after a failed call, last_error() reports a non-empty message.106
TEST(SocketCompileRun, LastError) {107
e2e::expect_e2e("socket_last_error", R"PURR(import io108
import socket109
let r = socket.connect(-1, "127.0.0.1", 1)110
io.print(r < 0, socket.last_error() != "")111
)PURR", "True True\n");112
}114
// send: a single send() on a bad fd returns < 0 (error path).115
TEST(SocketCompileRun, Send) {116
e2e::expect_e2e("socket_send", R"PURR(import io117
import socket118
io.print(socket.send(-1, "x") < 0)119
)PURR", "True\n");120
}122
// sendall: looping send on a bad fd returns < 0 (error path).123
TEST(SocketCompileRun, Sendall) {124
e2e::expect_e2e("socket_sendall", R"PURR(import io125
import socket126
io.print(socket.sendall(-1, "x") < 0)127
)PURR", "True\n");128
}130
// recv: a real recv() blocks until a peer sends, so it can't be made131
// deterministic standalone. Exercise only the non-blocking error paths: a bad132
// fd and a non-positive bufsize both return "" without touching the socket.133
TEST(SocketCompileRun, Recv) {134
e2e::expect_e2e("socket_recv", R"PURR(import io135
import socket136
io.print(socket.recv(-1, 64) == "", socket.recv(5, 0) == "")137
)PURR", "True True\n");138
}140
// accept: a real accept() blocks until a client connects, so it can't be made141
// deterministic standalone. Exercise only the non-blocking error path: accept142
// on a bad fd returns < 0 without blocking.143
TEST(SocketCompileRun, Accept) {144
e2e::expect_e2e("socket_accept", R"PURR(import io145
import socket146
io.print(socket.accept(-1) < 0)147
)PURR", "True\n");148
}