GCC Code Coverage Report


Directory: include/tts/
File: include/tts/engine/test.hpp
Date: 2026-10-14 16:28:14
Exec Total Coverage
Lines: 17 28 60.7%
Functions: 6 9 66.7%
Branches: 3 9 33.3%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 TTS - Tiny Test System
4 Copyright : TTS Contributors & Maintainers
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 #include <tts/tools/buffer.hpp>
11 #include <tts/tools/clock.hpp>
12 #include <tts/tools/erased.hpp>
13 #include <tts/tools/text.hpp>
14
15 namespace tts
16 {
17 //====================================================================================================================
18 /**
19 @brief What a given @ref TTS_CASE is expected to produce.
20
21 Defaults to `pass` for a plain @ref TTS_CASE. Set to anything else by wrapping the case's ID in
22 @ref TTS_XFAIL, @ref TTS_MAYFAIL or @ref TTS_XINVALID.
23 **/
24 //====================================================================================================================
25 enum class expected_outcome
26 {
27 pass, ///< The case is expected to pass, like a plain untagged @ref TTS_CASE.
28 xfail, ///< The case is expected to fail - if it passes instead, that's reported.
29 may_fail, ///< The case may pass or fail, either is accepted - only an empty case is reported.
30 xinvalid ///< The case is expected to be empty (register no assertion at all).
31 };
32 }
33
34 namespace tts::_
35 {
36
37 inline char const* current_test = "";
38
39 // The abort path reads it to tell a crash nobody wanted from one a case was tagged for.
40 inline ::tts::expected_outcome current_tag = expected_outcome::pass; // NOSONAR - set per case
41
42 // Carries a TTS_XFAIL/TTS_MAYFAIL/TTS_XINVALID tag without changing TTS_CASE(ID)'s call shape.
43 struct tagged_id
44 {
45 char const* name;
46 ::tts::expected_outcome tag;
47 nanoseconds timeout_ns = 0;
48 bool timeout_set = false;
49 };
50
51 ✗ inline char const* tag_name(::tts::expected_outcome tag)
52 {
53 using enum ::tts::expected_outcome;
54 ✗ switch(tag)
55 {
56 ✗ case pass: return "PASS";
57 ✗ case xfail: return "XFAIL";
58 ✗ case may_fail: return "MAYFAIL";
59 ✗ case xinvalid: return "XINVALID";
60 }
61 ✗ return ""; // NOSONAR - unreachable, expected_outcome only ever holds one of the 4 cases above
62 }
63
64 struct test
65 {
66 282 void operator()()
67 {
68 282 current_test = name;
69 282 current_tag = tag;
70 282 behaviour();
71 280 }
72 static inline bool acknowledge(test&& f);
73
74 char const* name;
75 tts::_::callable behaviour;
76 tts::text types = {};
77 ::tts::expected_outcome tag = ::tts::expected_outcome::pass;
78 nanoseconds timeout_ns = 0;
79 bool timeout_set = false;
80 };
81
82 // Global tests suite
83 481 inline buffer<test>& suite()
84 {
85
3/4
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 385 times.
✓ Branch 3 taken 96 times.
✗ Branch 4 not taken.
481 static buffer<test> that = {};
86 481 return that;
87 }
88
89 277 bool inline test::acknowledge(test&& f)
90 {
91 277 suite().emplace_back(TTS_MOVE(f));
92 277 return true;
93 }
94 }
95
96 namespace tts
97 {
98 /// Tags a @ref TTS_CASE's ID as expected to fail - see @ref TTS_XFAIL.
99 4 inline _::tagged_id expect_fail(char const* id)
100 {
101 4 return {id, expected_outcome::xfail};
102 }
103
104 /// Tags an already tagged ID as expected to fail, keeping whatever deadline it carries.
105 ✗ inline _::tagged_id expect_fail(_::tagged_id const& id)
106 {
107 ✗ return {id.name, expected_outcome::xfail, id.timeout_ns, id.timeout_set};
108 }
109
110 /// Tags a @ref TTS_CASE's ID as allowed to pass or fail - see @ref TTS_MAYFAIL.
111 3 inline _::tagged_id may_fail(char const* id)
112 {
113 3 return {id, expected_outcome::may_fail};
114 }
115
116 /// Tags an already tagged ID as allowed to fail, keeping whatever deadline it carries.
117 inline _::tagged_id may_fail(_::tagged_id const& id)
118 {
119 return {id.name, expected_outcome::may_fail, id.timeout_ns, id.timeout_set};
120 }
121
122 /// Tags a @ref TTS_CASE's ID as expected to be empty - see @ref TTS_XINVALID.
123 3 inline _::tagged_id expect_invalid(char const* id)
124 {
125 3 return {id, expected_outcome::xinvalid};
126 }
127
128 /// Tags an already tagged ID as expected to be empty, keeping whatever deadline it carries.
129 inline _::tagged_id expect_invalid(_::tagged_id const& id)
130 {
131 return {id.name, expected_outcome::xinvalid, id.timeout_ns, id.timeout_set};
132 }
133
134 /// Gives a @ref TTS_CASE's ID a deadline in milliseconds - see @ref TTS_TIMEOUT.
135 ✗ inline _::tagged_id with_timeout(unsigned long long ms, char const* id)
136 {
137 ✗ return {id, expected_outcome::pass, ms * 1'000'000, true};
138 }
139
140 /// Gives an already tagged ID a deadline, keeping its tag - see @ref TTS_TIMEOUT.
141 inline _::tagged_id with_timeout(unsigned long long ms, _::tagged_id const& id)
142 {
143 return {id.name, id.tag, ms * 1'000'000, true};
144 }
145 }
146