Testing

Real I/O is a poor foundation for unit tests. Network operations are slow, non-deterministic, and do not fail on demand — so error-handling paths go untested until production breaks them. Capy ships a self-contained toolkit that replaces the transport with in-memory mocks, drives coroutines to completion on the calling thread, and injects failures at every maybe_fail() site so that every error branch is exercised automatically. Because each mock satisfies the same concept as its production counterpart, test code reads the same as production code — the only difference is the type of the stream or source you pass in.

What This Section Covers

  • Driving Tests — run_blocking drives a coroutine to completion on the calling thread without a real executor; fuse runs the test body repeatedly, injecting an error at each maybe_fail() site in turn until every failure path has been covered; and the thread_name header’s set_current_thread_name function labels worker threads so that failures in multi-threaded tests are easier to attribute.

  • Mock Streams — read_stream, write_stream, and stream (a connected pair) implement the partial-I/O concepts from Streams. Use them to test protocol logic that calls read_some and write_some without touching a socket.

  • Mock Sources and Sinks — read_source and write_sink implement the complete-I/O concepts from Sources and Sinks. Unlike the stream mocks, they loop internally until the buffer is fully filled or drained, and write_sink accepts an explicit EOF signal.

  • Mock Buffer Sources and Sinks — buffer_source and buffer_sink implement the buffer concepts from Buffer Sources and Sinks. buffer_source exposes staged bytes via a pull interface; buffer_sink provides callee-owned storage that the algorithm writes into directly.

  • Buffer Inspection — bufgrind iterates every split point of a buffer sequence, exercising every chunk-boundary condition; buffer_to_string concatenates buffer sequences into a std::string for easy assertion.

How the Pieces Fit

A typical test constructs one or more mocks, arms a fuse, and hands the mocks to the code under test inside a run_blocking call. The fuse repeats the test body automatically — once for each failure site and once in exception mode — while run_blocking keeps the whole thing on the calling thread. Buffer utilities such as bufgrind and buffer_to_string wrap the mock data for assertions, letting you verify that every split of an input buffer produces the same correct output.

Continue to Driving Tests to begin.