GCC Code Coverage Report


Directory: include/tts/
File: include/tts/test/sequence.hpp
Date: 2026-10-14 16:28:14
Exec Total Coverage
Lines: 6 6 100.0%
Functions: 35 35 100.0%
Branches: 0 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/engine/logger.hpp>
12 #include <tts/engine/info.hpp>
13 #include <tts/tools/preprocessor.hpp>
14 #include <tts/tools/precision.hpp>
15 #include <tts/tools/text.hpp>
16
17 namespace tts::_
18 {
19 356 template<typename T> constexpr auto size(T const& c) noexcept
20 {
21 356 if constexpr(requires { c.size(); }) return c.size();
22 else if constexpr(requires { size(c); }) return size(c);
23 else
24 {
25 static_assert(
26 requires { c.size(); } || requires { size(c); },
27 "[TTS] Container type must support .size() or ADL size()");
28 }
29 }
30
31 356 template<typename T> constexpr auto begin(T const& c) noexcept
32 {
33 356 if constexpr(requires { c.begin(); }) return c.begin();
34 else if constexpr(requires { begin(c); }) return begin(c);
35 else
36 {
37 static_assert(
38 requires { c.begin(); } || requires { begin(c); },
39 "[TTS] Container type must support .begin() or ADL begin()");
40 }
41 }
42
43 149 template<typename T> constexpr auto end(T const& c) noexcept
44 {
45 149 if constexpr(requires { c.end(); }) return c.end();
46 else if constexpr(requires { end(c); }) return end(c);
47 else
48 {
49 static_assert(
50 requires { c.end(); } || requires { end(c); },
51 "[TTS] Container type must support .end() or ADL end()");
52 }
53 }
54
55 template<typename T, typename U> struct failure
56 {
57 std::size_t index;
58 T original;
59 U other;
60 };
61 }
62
63 #define TTS_ALL_IMPL(SEQ1, SEQ2, OP, N, UNIT, FAILURE) \
64 [](auto const& local_tts_a, auto const& local_tts_b) \
65 { \
66 if(tts::_::size(local_tts_b) != tts::_::size(local_tts_a)) \
67 { \
68 FAILURE("Expected: %s == %s but found %s elements instead of %s.", \
69 TTS_STRING(SEQ1), \
70 TTS_STRING(SEQ2), \
71 ::tts::as_text(::tts::_::size(local_tts_a)).data(), \
72 ::tts::as_text(::tts::_::size(local_tts_b)).data()); \
73 return ::tts::_::logger {}; \
74 } \
75 \
76 auto local_tts_ba = tts::_::begin(local_tts_a); \
77 auto local_tts_bb = tts::_::begin(local_tts_b); \
78 auto local_tts_ea = tts::_::end(local_tts_a); \
79 \
80 std::size_t local_tts_i = 0; \
81 ::tts::text local_tts_failures(""); \
82 \
83 while(local_tts_ba != local_tts_ea) \
84 { \
85 auto local_tts_err = OP(*local_tts_ba, *local_tts_bb); \
86 if(local_tts_err > N) \
87 { \
88 local_tts_failures += ::tts::text(" @[%ld] : %s and %s differs by %s %s.\n", \
89 local_tts_i++, \
90 ::tts::as_text(*local_tts_ba).data(), \
91 ::tts::as_text(*local_tts_bb).data(), \
92 ::tts::as_text(local_tts_err).data(), \
93 UNIT); \
94 } \
95 local_tts_ba++; \
96 local_tts_bb++; \
97 } \
98 \
99 if(!local_tts_failures.is_empty()) \
100 { \
101 FAILURE("Expected: %s == %s but found the following errors:\n%s", \
102 TTS_STRING(SEQ1), \
103 TTS_STRING(SEQ2), \
104 local_tts_failures.data()); \
105 return ::tts::_::logger {}; \
106 } \
107 \
108 ::tts::global_runtime.pass(); \
109 return ::tts::_::logger {false}; \
110 }(SEQ1, SEQ2) /**/
111
112 #define TTS_ALL(L, R, F, N, U, ...) TTS_ALL_##__VA_ARGS__(L, R, F, N, U)
113 #define TTS_ALL_(L, R, F, N, U) TTS_ALL_IMPL(L, R, F, N, U, TTS_FAIL)
114 #define TTS_ALL_REQUIRED(L, R, F, N, U) TTS_ALL_IMPL(L, R, F, N, U, TTS_FATAL)
115
116 //======================================================================================================================
117 /**
118 @defgroup test-sequence Sequence Tests Macros
119 @brief Macros for performing sequence-wide checks.
120 @{
121 **/
122 //======================================================================================================================
123
124 //======================================================================================================================
125 /**
126 @def TTS_ALL_ABSOLUTE_EQUAL
127 @brief Checks if all elements of two sequences are within a given absolute distance and that
128 their sizes are equal.
129
130 This comparison is performed by using the proper tts::absolute_check overload.
131
132 @param L, R Sequences to compare.
133 @param N Maximum absolute distance accepted between `L` and `R`.
134 @param ... Optional tag. If equals to `REQUIRED`, this test will stop the program if it fails.
135
136 @groupheader{Example}
137 @snippet doc/all_absolute.cpp snippet
138 **/
139 //======================================================================================================================
140 #if defined(TTS_DOXYGEN_INVOKED)
141 #define TTS_ALL_ABSOLUTE_EQUAL(L, R, N, ...)
142 #else
143 #define TTS_ALL_ABSOLUTE_EQUAL(L, R, N, ...) \
144 TTS_ALL(L, R, ::tts::absolute_check, N, "unit", __VA_ARGS__)
145 #endif
146
147 //======================================================================================================================
148 /**
149 @def TTS_ALL_RELATIVE_EQUAL
150 @brief Checks if all elements of two sequences are within a given relative distance and that
151 their sizes are equal.
152
153 This comparison is performed by using the proper tts::relative_check overload.
154
155 @param L, R Sequences to compare.
156 @param N Maximum relative distance accepted between `L` and `R`, as a ratio: `0.005` is
157 half a percent. `abs(L-R) / max(abs(L), abs(R), 1)` is what gets compared to it.
158 @param ... Optional tag. If equals to `REQUIRED`, this test will stop the program if it fails.
159
160 @groupheader{Example}
161 @snippet doc/all_relative.cpp snippet
162 **/
163 //======================================================================================================================
164 #if defined(TTS_DOXYGEN_INVOKED)
165 #define TTS_ALL_RELATIVE_EQUAL(L, R, N, ...)
166 #else
167 #define TTS_ALL_RELATIVE_EQUAL(L, R, N, ...) \
168 ( \
169 ::tts::_::reads_as_percent<decltype(*::tts::_::begin(L))>(N) \
170 ? TTS_PERCENT_TOLERANCE_##__VA_ARGS__(N) \
171 : TTS_ALL(L, R, ::tts::relative_check, N, "rel", __VA_ARGS__))
172 #endif
173
174 //======================================================================================================================
175 /**
176 @def TTS_ALL_ULP_EQUAL
177 @brief Checks if all elements of two sequences are within a given ULP distance and that their
178 sizes are equal.
179
180 This comparison is performed by using the proper tts::ulp_check overload.
181
182 @param L, R Sequences to compare.
183 @param N Maximum ULPs accepted between `L` and `R`.
184 @param ... Optional tag. If equals to `REQUIRED`, this test will stop the program if it fails.
185
186 @groupheader{Example}
187 @snippet doc/all_ulp.cpp snippet
188 **/
189 //======================================================================================================================
190 #if defined(TTS_DOXYGEN_INVOKED)
191 #define TTS_ALL_ULP_EQUAL(L, R, N, ...)
192 #else
193 #define TTS_ALL_ULP_EQUAL(L, R, N, ...) TTS_ALL(L, R, ::tts::ulp_check, N, "ULP", __VA_ARGS__)
194 #endif
195
196 //======================================================================================================================
197 /**
198 @def TTS_ALL_IEEE_EQUAL
199 @brief Checks if all elements of two sequences are within 0 ULP and that their sizes are equal.
200
201 This also allow for infinites and NaNs to be compared equal if both values are the
202 same infinites or are both $NaN$. This comparison is performed by using the proper tts::ulp_check
203 overload.
204
205 @param L, R Sequences to compare.
206 @param ... Optional tag. If equals to `REQUIRED`, this test will stop the program if it fails.
207
208 @groupheader{Example}
209 @snippet doc/all_ieee.cpp snippet
210 **/
211 //======================================================================================================================
212 #if defined(TTS_DOXYGEN_INVOKED)
213 #define TTS_ALL_IEEE_EQUAL(L, R, ...)
214 #else
215 #define TTS_ALL_IEEE_EQUAL(L, R, ...) TTS_ALL_ULP_EQUAL(L, R, 0, __VA_ARGS__)
216 #endif
217
218 //======================================================================================================================
219 /**
220 @def TTS_ALL_EQUAL
221 @brief Checks if all elements of two sequences are all equal and that their sizes are equal.
222
223 This comparison is performed by using the proper tts::absolute_check overload.
224
225 @param L, R Sequences to compare.
226 @param ... Optional tag. If equals to `REQUIRED`, this test will stop the program if it fails.
227
228 @groupheader{Example}
229 @snippet doc/all_equal.cpp snippet
230 **/
231 //======================================================================================================================
232 #if defined(TTS_DOXYGEN_INVOKED)
233 #define TTS_ALL_EQUAL(L, R, ...)
234 #else
235 #define TTS_ALL_EQUAL(L, R, ...) TTS_ALL_ABSOLUTE_EQUAL(L, R, 0, __VA_ARGS__)
236 #endif
237
238 //======================================================================================================================
239 /// @}
240 //======================================================================================================================
241