Files
voice-cat/tests/test_tcp_loopback.cpp
Talon bcb7ae8ccb build(cmake): clean up presets, add release/apple presets, cross-platform triplets
Rationalize the preset set to match the project's actual state (past M5):
- Rename dev->skeleton (no-deps stub smoke), m1-dev->dev (default dev preset)
- Drop m2-dev (cache-identical to m1-dev)
- Add release preset (optimized + tests on, symbols kept)
- Strip server-release binaries (-s linker flag)
- Add apple-dev/apple-ios/apple-ios-sim scaffolding presets for XCFramework

Add cmake/voicecat-toolchain.cmake wrapper that auto-resolves the vcpkg
triplet from the host platform (x64-mingw-static/x64-linux/arm64-osx) so
the main presets work on Windows/Linux/macOS without per-OS variants.

Update all docs (building.md, CLAUDE.md, README.md, AGENTS.md, deployment.md,
tech-stack.md, client READMEs) and stale preset-name references in code
comments. No C++ behavior changes — the core was already portable.
2026-06-18 03:16:01 +02:00

106 lines
3.5 KiB
C++

/*
* test_tcp_loopback — in-process TCP acceptor + client, sends 10 frames.
* Runs only under dev (requires Asio).
*/
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstdio>
#include <mutex>
#include <thread>
#include <vector>
#include "net/transport.h"
using namespace voicecat::net;
static int g_failures = 0;
#define CHECK(cond) \
do { \
if (!(cond)) { \
std::printf("FAIL [%s:%d]: %s\n", __FILE__, __LINE__, #cond); \
++g_failures; \
} \
} while (0)
int main() {
constexpr int kFrameCount = 10;
constexpr uint16_t kPort = 19850;
std::mutex mtx;
std::condition_variable cv;
std::vector<std::vector<uint8_t>> received;
std::atomic<bool> server_connected{false};
// Server io_context + acceptor.
asio::io_context server_io;
auto work = asio::make_work_guard(server_io);
std::thread server_thread([&] { server_io.run(); });
TcpAcceptor acceptor(server_io, kPort, [&](asio::ip::tcp::socket sock) {
TcpChannelCallbacks cbs;
cbs.on_frame = [&](std::vector<uint8_t> frame) {
std::lock_guard<std::mutex> lk(mtx);
received.push_back(std::move(frame));
cv.notify_all();
};
cbs.on_connected = [&] { server_connected.store(true); };
auto conn = std::make_shared<TcpServerConn>(std::move(sock), std::move(cbs));
return conn;
});
acceptor.start();
// Client.
std::atomic<bool> client_connected{false};
TcpChannelCallbacks client_cbs;
client_cbs.on_connected = [&] { client_connected.store(true); };
client_cbs.on_connect_error = [](std::error_code ec) {
std::printf("connect error: %s\n", ec.message().c_str());
};
TcpControlChannel client(std::move(client_cbs));
client.async_connect("127.0.0.1", kPort);
// Wait for connection.
auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5);
while (!client_connected.load() &&
std::chrono::steady_clock::now() < deadline) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
CHECK(client_connected.load());
// Send kFrameCount distinct frames.
for (int i = 0; i < kFrameCount; ++i) {
std::vector<uint8_t> payload = {static_cast<uint8_t>(i), 0xAB, 0xCD};
client.send_frame(payload);
}
// Wait for all frames to arrive on the server side.
{
std::unique_lock<std::mutex> lk(mtx);
bool ok = cv.wait_for(lk, std::chrono::seconds(5),
[&] { return static_cast<int>(received.size()) >= kFrameCount; });
CHECK(ok);
}
CHECK(static_cast<int>(received.size()) == kFrameCount);
for (int i = 0; i < kFrameCount && i < static_cast<int>(received.size()); ++i) {
CHECK(received[i].size() == 3);
if (!received[i].empty()) CHECK(received[i][0] == static_cast<uint8_t>(i));
}
// Clean up.
client.close();
acceptor.stop();
work.reset();
server_io.stop();
server_thread.join();
if (g_failures == 0) {
std::printf("tcp_loopback: all checks passed\n");
return 0;
}
std::printf("tcp_loopback: %d failure(s)\n", g_failures);
return 1;
}