| 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 |