GCC Code Coverage Report


Directory: include/tts/
File: include/tts/sinks/tap.hpp
Date: 2026-10-14 16:28:14
Exec Total Coverage
Lines: 20 23 87.0%
Functions: 6 7 85.7%
Branches: 6 6 100.0%

Line Branch Exec Source
1 //======================================================================================================================
2 //! @file
3 /*
4 TTS - Tiny Test System
5 Copyright : TTS Contributors & Maintainers
6 SPDX-License-Identifier: BSL-1.0
7 */
8 //======================================================================================================================
9 #pragma once
10
11 #include <tts/tools/output.hpp>
12
13 namespace tts
14 {
15 //====================================================================================================================
16 /**
17 @ingroup tools-sinks
18 @public
19 @brief output_sink rendering the run as [TAP](https://testanything.org/) (Test Anything
20 Protocol).
21
22 Built from @ref output_sink's structured `test_finished` hook rather than by parsing the
23 human-readable text @ref tts::stdout_sink prints, so it reports one "ok N - name" / "not ok
24 N - name" line per @ref TTS_CASE regardless of `-v`/`-q`, followed by a trailing "1..N" plan
25 line once dump()ed - or automatically, via `finish()`, to the target given at construction
26 (`tts::output_handler::default_sink()` by default). It does not (currently) reflect
27 @ref TTS_CASE_TPL's per-type breakdown or @ref TTS_WHEN / @ref TTS_AND_THEN sub-scenarios,
28 since those don't have their own hook - only the enclosing @ref TTS_CASE does.
29
30 @groupheader{Example}
31 @code
32 tts::tap_sink tap;
33 tts::output().sink(tap);
34
35 // ... run the test suite ...
36
37 tap.dump(); // stream the TAP-formatted report to stdout
38 @endcode
39 **/
40 //====================================================================================================================
41 struct tap_sink : output_sink
42 {
43 100 explicit tap_sink(output_sink& target = output_handler::default_sink())
44 100 : target_(&target)
45 {
46 100 }
47
48 10 void write(text const&) override
49 {
50 // Intentionally empty: TAP output is built entirely from test_finished() below.
51 10 }
52
53 2 void test_finished(text const& name,
54 bool passed,
55 [[maybe_unused]] bool invalid,
56 [[maybe_unused]] nanoseconds duration_ns) override
57 {
58 2 ++count_;
59
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
5 body_ += passed ? text {"ok %zu - %s\n", count_, name.data()}
60
1/1
✓ Branch 2 taken 2 times.
3 : text {"not ok %zu - %s\n", count_, name.data()};
61 2 }
62
63 /// Renders everything gathered so far as TAP-formatted text.
64 1 text render() const
65 {
66
1/1
✓ Branch 2 taken 1 times.
2 return text {"1..%zu\n", count_} + body_;
67 }
68
69 /// Forwards the TAP-rendered report to target, then clears the gathered results.
70 1 void dump(output_sink& target)
71 {
72
2/2
✓ Branch 1 taken 1 times.
✓ Branch 4 taken 1 times.
1 target.write(render());
73 1 clear();
74 1 }
75
76 /// Streams the TAP-rendered report to `stdout`, then clears the gathered results.
77 void dump()
78 {
79 stdout_sink target;
80 dump(target);
81 }
82
83 /// Discards everything gathered so far.
84 1 void clear()
85 {
86 1 body_ = text {};
87 1 count_ = 0;
88 1 }
89
90 /// Dumps the TAP-rendered report to the target given at construction.
91 ✗ void finish() override
92 {
93 ✗ dump(*target_);
94 ✗ }
95
96 private:
97 output_sink* target_;
98 text body_;
99 std::size_t count_ = 0;
100 };
101 }
102