Share a CTest report
CTest's designed sharing story is CDash: run the tests with -T Test and
-T Submit, and results appear on a dashboard server. That works, and it means
standing up and maintaining a CDash instance — a reasonable trade for LLVM or
VTK, and disproportionate for a team of six who want to send a colleague the
list of what broke.
The alternative most teams end up with is pasting the tail of ctest output
into a chat window:
The following tests FAILED:
14 - buffer_unaligned_read (Failed)
22 - net_timeout_retry (Timeout)
Errors while running CTest
Which names the failures and tells you nothing about them.
Emit JUnit XML
CMake 3.21 and later can write JUnit directly:
ctest --output-on-failure --output-junit results.xml
--output-on-failure is the important half — without it the XML records that a
test failed and not what it printed, and a C++ test's stdout is usually the
entire diagnosis.
On older CMake, use the CDash-format output and convert:
ctest -T Test --output-on-failure # → Testing/<tag>/Test.xml
Convert and publish
npx xunit-viewer --results=results.xml --output=report.html
# or
pip install junit2html && junit2html results.xml report.html
Drag report.html into the app, or POST it:
curl -fsS -X POST "https://commareports.com/api/v1/reports" \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile html report.html \
--arg t "CTest — libcore, $(git rev-parse --short HEAD)" \
'{title: $t, html: $html}')"
The generated page gives you the suite tree, durations per test, and the captured output expanded under each failure — which is the thing the console tail leaves out.
Timeouts deserve their own attention
CTest reports timeouts as failures, and they are the category most likely to be a flake and most likely to be misdiagnosed from a log tail. Set the timeout explicitly so the report distinguishes them:
set_tests_properties(net_timeout_retry PROPERTIES TIMEOUT 30)
Then a timeout in the published report is a test that exceeded a limit somebody chose, rather than one that hit CTest's default and might simply need longer on a slow runner.
From CI
ctest --output-on-failure --output-junit results.xml || TESTS_FAILED=1
npx xunit-viewer --results=results.xml --output=report.html
curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
-H "Authorization: Bearer $COMMA_API_TOKEN" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile html report.html \
--arg t "CTest — $PRESET @ $GITHUB_SHA" '{title: $t, html: $html}')"
exit "${TESTS_FAILED:-0}"
Publish before you exit, and run the step with if: always() (GitHub Actions),
when: always (GitLab, CircleCI) or post { always { … } } (Jenkins).
Use one report id per CMake preset or toolchain. A C++ project's interesting failures are usually configuration-specific — Debug-only, ASan-only, MSVC-only — and a per-configuration URL makes that visible instead of leaving someone to correlate build numbers.
What review adds
- Anchored threads on the failing test — see commenting on HTML.
- Revisions, so an intermittent timeout has a history.
- Access per report — private, team, domain-gated or named reviewers. See the sharing model.
Limits
- Entry HTML: 5 MB.
- 60 requests/minute per token.
Try it
Comma is free — unlimited reports, unlimited commenters, unlimited revision history.