# Testing signals — curl/curl

> Canonical page: https://codevetter.com/unpack/curl/testing-signals

# Testing signals — curl/curl

Scanned commit c362f034692e05ecb4d33edb740ba64c63a20add (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

curl's testing is unusually broad and almost entirely in-tree. The centre of gravity is `tests/data/` — 2,119 XML-ish test-case files run by `tests/runtests.pl` against protocol servers curl itself ships (sws, socksd, tftpd, mqttd, rtspd, dnsd, plus Perl/Python FTP/TFTP/RTSP/DICT/telnet servers). Around that sit 80 C unit tests for library internals, 6 `tunit` tests for tool-only code, 273 `libtest` programs exercising the public API, and 31 pytest modules that test HTTP/2, HTTP/3, proxying, SSL and WebSockets against real nghttpx/caddy/vsftpd. Each run can be repeated in torture mode (fail every allocation in turn), under valgrind, or event-based. Coverage gaps are structural rather than accidental: platform-specific code (Windows/VMS/AmigaOS/MSDOS branches) and the rarer TLS/QUIC backend combinations can only be exercised by the matching CI job.
- The primary suite is 2,119 declarative test files in tests/data/, each an XML-like document with `<info><keywords>`, a `<reply>` server script, a `<client><command>` invocation, and a `<verify><protocol>` expectation — plus optional `<limits>` on allocation counts. — [tests/data/test1#L1-L54](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/data/test1#L1-L54) [tests/data/Makefile.am#L24-L40](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/data/Makefile.am#L24-L40)
- `tests/runtests.pl` is the harness; its documented flags cover torture testing (`-t`), valgrind control, event-based runs, and keyword/feature selection such as `FTPS` or `!feat:proxy`, with per-test result flags (s/r/p/d/u/P/o/e/m/v/E) reported per run. — [docs/runtests.md#L20-L80](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/docs/runtests.md#L20-L80) [docs/runtests.md#L120-L290](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/docs/runtests.md#L120-L290) [tests/runtests.pl](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/runtests.pl)
- Protocol servers are part of the repo, so tests need no external services: tests/server/ holds sws.c (HTTP), socksd.c, tftpd.c, mqttd.c, rtspd.c, dnsd.c and sockfilt.c, complemented by ftpserver.pl, http2-server.pl, http3-server.pl, sshserver.pl and dictserver.py. — [tests/server/sws.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/server/sws.c) [tests/server/socksd.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/server/socksd.c) [tests/ftpserver.pl](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/ftpserver.pl) [tests/http3-server.pl](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/http3-server.pl)
- 80 unit tests under tests/unit/ exercise library internals directly (llist, hash, splay, strparse, urlapi, cookie parsing …) using the `UNITTEST_BEGIN_SIMPLE` macro and a `test_unitNNNN(const char *arg)` entrypoint. — [tests/unit/unit1300.c#L26-L60](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/unit/unit1300.c#L26-L60) [tests/unit/Makefile.inc](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/unit/Makefile.inc)
- Tool-only code has its own unit directory, tests/tunit/, with 6 files named after the test number they back (tool1394, tool1604, tool1621, tool1622, tool1623, tool1720) — this is where `src/` helpers get direct coverage. — [tests/tunit/README.md](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/tunit/README.md) [tests/tunit/tool1621.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/tunit/tool1621.c)
- 273 `libtest/libNNNN.c` programs plus a set of `cli_*.c` drivers (cli_h2_pausing, cli_hx_download, cli_ws_pingpong, cli_tls_session_reuse, cli_ev_download) test the public easy/multi/WebSocket APIs as real linked programs. — [tests/libtest/lib1301.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/libtest/lib1301.c) [tests/libtest/cli_ws_pingpong.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/libtest/cli_ws_pingpong.c) [tests/libtest/first.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/libtest/first.c)
- The pytest suite in tests/http/ has 31 modules numbered by area — 01 basic, 02 download, 07 upload, 09 push, 10/13 proxy and proxy auth, 17 ssl use, 19 shutdown, 20 websockets, 22 HTTPSRR, 30-32 vsftpd, 40 socks, 50/51 scp+sftp, 60 h3 proxy — driven by `conftest.py` and a `testenv` package. — [tests/http/conftest.py](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/http/conftest.py) [tests/http/test_20_websockets.py](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/http/test_20_websockets.py) [tests/http/test_60_h3_proxy.py](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/http/test_60_h3_proxy.py) [tests/http/requirements.txt](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/http/requirements.txt)
- Make targets select the mode: `tests/Makefile.am` maps `test`/`quiet-test`/`am-test`/`ci-test`/`full-test`/`nonflaky-test`/`torture-test`/`event-test` onto `$(TEST)` with different flag sets, and `ci-pytest` runs `pytest -n auto -v $(srcdir)/http`. — [tests/Makefile.am#L144-L178](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/Makefile.am#L144-L178) [Makefile.am#L126-L158](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/Makefile.am#L126-L158)
- Memory-behaviour is a first-class test axis: debug builds honour `CURL_MEMDEBUG` (log file) and `CURL_MEMLIMIT` (fail the Nth allocation) set up in `memory_tracking_init()`, with tests/memanalyze.pl and tests/memanalyzer.pm analysing the logs and test cases asserting allocation ceilings. — [src/tool_main.c#L110-L138](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_main.c#L110-L138) [tests/memanalyze.pl](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/memanalyze.pl) [tests/data/test1#L48-L52](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/tests/data/test1#L48-L52)
- Debug builds expose test-only hooks the suite depends on: `CURL_FORBID_REUSE`, `global->test_duphandle` (perform on a `curl_easy_duphandle()` copy), `global->test_event_based` (`curl_easy_perform_ev()` / libuv-driven `parallel_event()`), and `CURL_UPLOAD_SIZE`. — [src/tool_operate.c#L2120-L2144](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_operate.c#L2120-L2144) [src/tool_operate.c#L1808-L1900](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_operate.c#L1808-L1900) [src/tool_operate.c#L301-L312](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/src/tool_operate.c#L301-L312)
- Source-level checks run as their own CI workflow: `scripts/checksrc-all.pl` enforces the style guide, and the same job runs spellcheck, `scripts/cmakeopts.sh`, REUSE licence checks and other linters with `permissions: {}` and pinned action SHAs. — [.github/workflows/checksrc.yml#L37-L60](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/.github/workflows/checksrc.yml#L37-L60) [scripts/checksrc.pl](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/scripts/checksrc.pl) [docs/internals/CHECKSRC.md#L7-L50](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/docs/internals/CHECKSRC.md#L7-L50)
- Documentation is tested too: `make check` includes `check-docs` (docs/libcurl) and `examples` (docs/examples, 129 compilable C programs), with dedicated checkdocs.yml and checkurls.yml workflows. — [Makefile.am#L113-L168](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/Makefile.am#L113-L168) [.github/workflows/checkdocs.yml](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/.github/workflows/checkdocs.yml) [docs/examples/simple.c](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/docs/examples/simple.c)
- The CI matrix is what covers the backend combinatorics: linux.yml pins and builds against AWS-LC, BoringSSL, LibreSSL, mbedTLS (current and previous), OpenSSL, Rustls, nghttp2, OpenLDAP and Fil-C, while http3-linux.yml, macos.yml, windows.yml, non-native.yml and linux-old.yml cover the rest. — [.github/workflows/linux.yml#L34-L60](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/.github/workflows/linux.yml#L34-L60) [.github/workflows/http3-linux.yml](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/.github/workflows/http3-linux.yml) [.github/workflows/non-native.yml](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/.github/workflows/non-native.yml)
- There is a coverage script (`scripts/coverage.sh`) and a CodeQL workflow, but coverage is not gated in the in-tree build targets — `make check` does not compute or threshold line coverage. (inferred) — [scripts/coverage.sh](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/scripts/coverage.sh) [.github/workflows/codeql.yml](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/.github/workflows/codeql.yml) [Makefile.am#L113](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/Makefile.am#L113)
- `configure-vs-cmake.yml` exists specifically to catch drift between the two build systems, which is the main risk of maintaining `configure.ac` (167KB) and `CMakeLists.txt` (93KB) in parallel. (inferred) — [.github/workflows/configure-vs-cmake.yml](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/.github/workflows/configure-vs-cmake.yml) [configure.ac](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/configure.ac) [CMakeLists.txt](https://github.com/curl/curl/blob/c362f034692e05ecb4d33edb740ba64c63a20add/CMakeLists.txt)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
