@micro-os-plus/micro-test-plus 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +82 -0
- package/CMakeLists.txt +74 -24
- package/README.md +3 -2
- package/include/micro-os-plus/micro-test-plus/README.md +6 -0
- package/include/micro-os-plus/micro-test-plus/deferred-reporter.h +29 -54
- package/include/micro-os-plus/micro-test-plus/detail.h +166 -705
- package/include/micro-os-plus/micro-test-plus/exceptions.h +5 -6
- package/include/micro-os-plus/micro-test-plus/expression-formatter.h +669 -0
- package/include/micro-os-plus/micro-test-plus/function-comparators.h +5 -0
- package/include/micro-os-plus/micro-test-plus/inlines/deferred-reporter-inlines.h +25 -30
- package/include/micro-os-plus/micro-test-plus/inlines/detail-inlines.h +711 -0
- package/include/micro-os-plus/micro-test-plus/inlines/exceptions-inline.h +137 -0
- package/include/micro-os-plus/micro-test-plus/inlines/expression-formatter-inlines.h +510 -0
- package/include/micro-os-plus/micro-test-plus/inlines/function-comparators-inlines.h +17 -76
- package/include/micro-os-plus/micro-test-plus/inlines/literals-inlines.h +47 -25
- package/include/micro-os-plus/micro-test-plus/inlines/math-inlines.h +7 -7
- package/include/micro-os-plus/micro-test-plus/inlines/operators-inlines.h +275 -0
- package/include/micro-os-plus/micro-test-plus/inlines/reflection-inlines.h +4 -4
- package/include/micro-os-plus/micro-test-plus/inlines/reporter-inlines.h +53 -394
- package/include/micro-os-plus/micro-test-plus/inlines/runner-inlines.h +38 -0
- package/include/micro-os-plus/micro-test-plus/inlines/runner-totals-inlines.h +152 -0
- package/include/micro-os-plus/micro-test-plus/inlines/test-inlines.h +231 -45
- package/include/micro-os-plus/micro-test-plus/inlines/timings-inlines.h +120 -0
- package/include/micro-os-plus/micro-test-plus/inlines/type-traits-inlines.h +231 -0
- package/include/micro-os-plus/micro-test-plus/literals.h +8 -14
- package/include/micro-os-plus/micro-test-plus/math.h +5 -0
- package/include/micro-os-plus/micro-test-plus/operators.h +19 -169
- package/include/micro-os-plus/micro-test-plus/reflection.h +5 -12
- package/include/micro-os-plus/micro-test-plus/reporter-human.h +17 -11
- package/include/micro-os-plus/micro-test-plus/reporter-tap.h +14 -8
- package/include/micro-os-plus/micro-test-plus/reporter.h +101 -424
- package/include/micro-os-plus/micro-test-plus/runner-totals.h +162 -176
- package/include/micro-os-plus/micro-test-plus/runner.h +61 -42
- package/include/micro-os-plus/micro-test-plus/test.h +450 -506
- package/include/micro-os-plus/micro-test-plus/timings.h +259 -262
- package/include/micro-os-plus/micro-test-plus/type-traits.h +19 -67
- package/include/micro-os-plus/micro-test-plus/utility.h +5 -4
- package/include/micro-os-plus/micro-test-plus.h +33 -24
- package/meson.build +1 -0
- package/package.json +11 -3
- package/src/deferred-reporter.cpp +21 -2
- package/src/expression-formatter.cpp +289 -0
- package/src/reflection.cpp +3 -1
- package/src/reporter-human.cpp +31 -37
- package/src/reporter-tap.cpp +25 -35
- package/src/reporter.cpp +36 -231
- package/src/runner-totals.cpp +6 -3
- package/src/runner.cpp +131 -25
- package/src/test.cpp +120 -113
- package/src/timings.cpp +6 -5
- package/src/utility.cpp +1 -1
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the µOS++ project (https://micro-os-plus.github.io/).
|
|
3
|
+
* Copyright (c) 2021-2026 Liviu Ionescu. All rights reserved.
|
|
4
|
+
*
|
|
5
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
* purpose is hereby granted, under the terms of the MIT license.
|
|
7
|
+
*
|
|
8
|
+
* If a copy of the license was not distributed with this file, it can be
|
|
9
|
+
* obtained from https://opensource.org/licenses/mit.
|
|
10
|
+
*
|
|
11
|
+
* Major parts of the code are inspired from v1.1.8 of the Boost UT project,
|
|
12
|
+
* released under the terms of the Boost Version 1.0 Software License,
|
|
13
|
+
* which can be obtained from https://www.boost.org/LICENSE_1_0.txt.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// ----------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @file
|
|
20
|
+
* @brief C++ header file with inline implementations for the µTest++
|
|
21
|
+
* internal detail namespace.
|
|
22
|
+
*
|
|
23
|
+
* @details
|
|
24
|
+
* This header provides the out-of-line template and inline implementations
|
|
25
|
+
* for all types declared in `detail.h`. It defines the bodies of the
|
|
26
|
+
* generic getter, the unary and binary operator base class templates, all
|
|
27
|
+
* relational and logical comparator constructors, and the callable operator
|
|
28
|
+
* types (`throws_`, `nothrow_`).
|
|
29
|
+
*
|
|
30
|
+
* Separating the implementations from the declarations keeps `detail.h`
|
|
31
|
+
* concise and focused on the interface, whilst grouping the complex
|
|
32
|
+
* lambda-based constructor bodies here for maintainability.
|
|
33
|
+
*
|
|
34
|
+
* All definitions reside within the
|
|
35
|
+
* `micro_os_plus::micro_test_plus::detail` namespace, ensuring clear
|
|
36
|
+
* separation from user code and minimising the risk of naming conflicts.
|
|
37
|
+
*
|
|
38
|
+
* This file is intended solely for internal use within the framework and
|
|
39
|
+
* should not be included directly by user code.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
#ifndef MICRO_TEST_PLUS_DETAIL_INLINES_H_
|
|
43
|
+
#define MICRO_TEST_PLUS_DETAIL_INLINES_H_
|
|
44
|
+
|
|
45
|
+
// ----------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
#ifdef __cplusplus
|
|
48
|
+
|
|
49
|
+
// ----------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
#include <charconv>
|
|
52
|
+
|
|
53
|
+
// ----------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
#if defined(__GNUC__)
|
|
56
|
+
#pragma GCC diagnostic push
|
|
57
|
+
#pragma GCC diagnostic ignored "-Waggregate-return"
|
|
58
|
+
#if defined(__clang__)
|
|
59
|
+
#pragma clang diagnostic ignored "-Wc++98-compat"
|
|
60
|
+
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
|
61
|
+
#endif
|
|
62
|
+
#endif
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
|
|
66
|
+
namespace micro_os_plus::micro_test_plus
|
|
67
|
+
{
|
|
68
|
+
namespace detail
|
|
69
|
+
{
|
|
70
|
+
// ========================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @details
|
|
74
|
+
* If the type `T` provides a `get()` member function, it is invoked
|
|
75
|
+
* and its result returned. Otherwise the argument itself is returned
|
|
76
|
+
* unchanged. The selection is performed at compile time via
|
|
77
|
+
* `if constexpr` with an inline `requires` expression.
|
|
78
|
+
*/
|
|
79
|
+
template <class T>
|
|
80
|
+
constexpr auto
|
|
81
|
+
get (const T& t)
|
|
82
|
+
{
|
|
83
|
+
if constexpr (requires { t.get (); })
|
|
84
|
+
return t.get ();
|
|
85
|
+
else
|
|
86
|
+
return t;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @details
|
|
93
|
+
* Stores the operand and the pre-computed boolean result of the
|
|
94
|
+
* operation in the corresponding private members.
|
|
95
|
+
*/
|
|
96
|
+
template <class T>
|
|
97
|
+
constexpr unary_op_<T>::unary_op_ (const T& t, bool value)
|
|
98
|
+
: t_{ t }, value_{ value }
|
|
99
|
+
{
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @details
|
|
104
|
+
* Returns the pre-computed boolean result stored by the derived
|
|
105
|
+
* comparator's constructor.
|
|
106
|
+
*/
|
|
107
|
+
template <class T>
|
|
108
|
+
constexpr unary_op_<T>::
|
|
109
|
+
operator bool () const
|
|
110
|
+
{
|
|
111
|
+
return value_;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @details
|
|
116
|
+
* Returns the wrapped operand, applying the generic getter to ensure
|
|
117
|
+
* correct extraction for both custom and standard types.
|
|
118
|
+
*/
|
|
119
|
+
template <class T>
|
|
120
|
+
constexpr auto
|
|
121
|
+
unary_op_<T>::operand () const
|
|
122
|
+
{
|
|
123
|
+
return get (t_);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @details
|
|
130
|
+
* Stores the two operands and the pre-computed boolean result of the
|
|
131
|
+
* comparison in the corresponding private members.
|
|
132
|
+
*/
|
|
133
|
+
template <class Lhs_T, class Rhs_T>
|
|
134
|
+
constexpr binary_op_<Lhs_T, Rhs_T>::binary_op_ (const Lhs_T& lhs,
|
|
135
|
+
const Rhs_T& rhs,
|
|
136
|
+
bool value)
|
|
137
|
+
: lhs_{ lhs }, rhs_{ rhs }, value_{ value }
|
|
138
|
+
{
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @details
|
|
143
|
+
* Returns the pre-computed boolean result stored by the derived
|
|
144
|
+
* comparator's constructor.
|
|
145
|
+
*/
|
|
146
|
+
template <class Lhs_T, class Rhs_T>
|
|
147
|
+
constexpr binary_op_<Lhs_T, Rhs_T>::
|
|
148
|
+
operator bool () const
|
|
149
|
+
{
|
|
150
|
+
return value_;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @details
|
|
155
|
+
* Returns the value of the left-hand operand, applying the generic
|
|
156
|
+
* getter to ensure correct extraction for both custom and standard
|
|
157
|
+
* types.
|
|
158
|
+
*/
|
|
159
|
+
template <class Lhs_T, class Rhs_T>
|
|
160
|
+
constexpr auto
|
|
161
|
+
binary_op_<Lhs_T, Rhs_T>::lhs (void) const
|
|
162
|
+
{
|
|
163
|
+
return get (lhs_);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @details
|
|
168
|
+
* Returns the value of the right-hand operand, applying the generic
|
|
169
|
+
* getter to ensure correct extraction for both custom and standard
|
|
170
|
+
* types.
|
|
171
|
+
*/
|
|
172
|
+
template <class Lhs_T, class Rhs_T>
|
|
173
|
+
constexpr auto
|
|
174
|
+
binary_op_<Lhs_T, Rhs_T>::rhs (void) const
|
|
175
|
+
{
|
|
176
|
+
return get (rhs_);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @details
|
|
183
|
+
* Evaluates the equality of `lhs` and `rhs` inside an immediately
|
|
184
|
+
* invoked lambda and passes the boolean result to the `binary_op_`
|
|
185
|
+
* base class constructor. Supports types with static `value` members,
|
|
186
|
+
* types with an `epsilon` precision member, and generic types.
|
|
187
|
+
*/
|
|
188
|
+
template <class Lhs_T, class Rhs_T>
|
|
189
|
+
constexpr eq_<Lhs_T, Rhs_T>::eq_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
190
|
+
: binary_op_<Lhs_T, Rhs_T>{ lhs, rhs, [&]
|
|
191
|
+
{
|
|
192
|
+
// This lambda is called in the constructor to evaluate the
|
|
193
|
+
// comparison. Its result is implicitly converted to bool via
|
|
194
|
+
// the operator bool() of whatever type the branch returns.
|
|
195
|
+
// This is intentional: all result types (integral_constant,
|
|
196
|
+
// comparator objects, plain bool) define operator bool().
|
|
197
|
+
using std::operator==;
|
|
198
|
+
using std::operator<;
|
|
199
|
+
|
|
200
|
+
#if defined(__GNUC__)
|
|
201
|
+
#pragma GCC diagnostic push
|
|
202
|
+
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
|
203
|
+
#pragma GCC diagnostic ignored "-Wconversion"
|
|
204
|
+
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
205
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
206
|
+
#if defined(__clang__)
|
|
207
|
+
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
208
|
+
#pragma clang diagnostic ignored "-Wpedantic"
|
|
209
|
+
#endif
|
|
210
|
+
#endif
|
|
211
|
+
if constexpr (type_traits::has_value<Lhs_T>
|
|
212
|
+
and type_traits::has_value<Rhs_T>)
|
|
213
|
+
{
|
|
214
|
+
// If both types have values (like numeric constants),
|
|
215
|
+
// compare them directly.
|
|
216
|
+
return Lhs_T::value == Rhs_T::value;
|
|
217
|
+
}
|
|
218
|
+
else if constexpr (type_traits::has_epsilon<Lhs_T>
|
|
219
|
+
and type_traits::has_epsilon<Rhs_T>)
|
|
220
|
+
{
|
|
221
|
+
// If both values have precision, compare them using
|
|
222
|
+
// the smallest precision.
|
|
223
|
+
return math::abs (get (lhs) - get (rhs))
|
|
224
|
+
< math::min_value (lhs.epsilon, rhs.epsilon);
|
|
225
|
+
}
|
|
226
|
+
else if constexpr (type_traits::has_epsilon<Lhs_T>)
|
|
227
|
+
{
|
|
228
|
+
// If only the left operand has precision, use it.
|
|
229
|
+
return math::abs (get (lhs) - get (rhs)) < lhs.epsilon;
|
|
230
|
+
}
|
|
231
|
+
else if constexpr (type_traits::has_epsilon<Rhs_T>)
|
|
232
|
+
{
|
|
233
|
+
// If only the right operand has precision, use it.
|
|
234
|
+
return math::abs (get (lhs) - get (rhs)) < rhs.epsilon;
|
|
235
|
+
}
|
|
236
|
+
else
|
|
237
|
+
{
|
|
238
|
+
// Call the generic getters, which might
|
|
239
|
+
// either call the type get() or return the value.
|
|
240
|
+
return get (lhs) == get (rhs);
|
|
241
|
+
}
|
|
242
|
+
#if defined(__GNUC__)
|
|
243
|
+
#pragma GCC diagnostic pop
|
|
244
|
+
#endif
|
|
245
|
+
}() }
|
|
246
|
+
{
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ------------------------------------------------------------------------
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @details
|
|
253
|
+
* Evaluates the non-equality of `lhs` and `rhs` inside an immediately
|
|
254
|
+
* invoked lambda and passes the boolean result to the `binary_op_`
|
|
255
|
+
* base class constructor. Supports types with static `value` members,
|
|
256
|
+
* types with an `epsilon` precision member, and generic types.
|
|
257
|
+
*/
|
|
258
|
+
template <class Lhs_T, class Rhs_T>
|
|
259
|
+
constexpr ne_<Lhs_T, Rhs_T>::ne_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
260
|
+
: binary_op_<Lhs_T, Rhs_T>{ lhs, rhs, [&]
|
|
261
|
+
{
|
|
262
|
+
using std::operator==;
|
|
263
|
+
using std::operator!=;
|
|
264
|
+
using std::operator>;
|
|
265
|
+
|
|
266
|
+
#if defined(__GNUC__)
|
|
267
|
+
#pragma GCC diagnostic push
|
|
268
|
+
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
|
269
|
+
#pragma GCC diagnostic ignored "-Wconversion"
|
|
270
|
+
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
271
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
272
|
+
#if defined(__clang__)
|
|
273
|
+
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
274
|
+
#pragma clang diagnostic ignored "-Wpedantic"
|
|
275
|
+
#endif
|
|
276
|
+
#endif
|
|
277
|
+
if constexpr (type_traits::has_value<Lhs_T>
|
|
278
|
+
and type_traits::has_value<Rhs_T>)
|
|
279
|
+
{
|
|
280
|
+
return Lhs_T::value != Rhs_T::value;
|
|
281
|
+
}
|
|
282
|
+
else if constexpr (type_traits::has_epsilon<Lhs_T>
|
|
283
|
+
and type_traits::has_epsilon<Rhs_T>)
|
|
284
|
+
{
|
|
285
|
+
return math::abs (get (lhs) - get (rhs))
|
|
286
|
+
>= math::min_value (lhs.epsilon, rhs.epsilon);
|
|
287
|
+
}
|
|
288
|
+
else if constexpr (type_traits::has_epsilon<Lhs_T>)
|
|
289
|
+
{
|
|
290
|
+
return math::abs (get (lhs) - get (rhs)) >= lhs.epsilon;
|
|
291
|
+
}
|
|
292
|
+
else if constexpr (type_traits::has_epsilon<Rhs_T>)
|
|
293
|
+
{
|
|
294
|
+
return math::abs (get (lhs) - get (rhs)) >= rhs.epsilon;
|
|
295
|
+
}
|
|
296
|
+
else
|
|
297
|
+
{
|
|
298
|
+
return get (lhs) != get (rhs);
|
|
299
|
+
}
|
|
300
|
+
#if defined(__GNUC__)
|
|
301
|
+
#pragma GCC diagnostic pop
|
|
302
|
+
#endif
|
|
303
|
+
}() }
|
|
304
|
+
{
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ------------------------------------------------------------------------
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* @details
|
|
311
|
+
* Evaluates whether `lhs > rhs` inside an immediately invoked lambda
|
|
312
|
+
* and passes the boolean result to the `binary_op_` base class
|
|
313
|
+
* constructor. Supports types with static `value` members and generic
|
|
314
|
+
* types.
|
|
315
|
+
*/
|
|
316
|
+
template <class Lhs_T, class Rhs_T>
|
|
317
|
+
constexpr gt_<Lhs_T, Rhs_T>::gt_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
318
|
+
: binary_op_<Lhs_T, Rhs_T>{ lhs, rhs, [&]
|
|
319
|
+
{
|
|
320
|
+
using std::operator>;
|
|
321
|
+
|
|
322
|
+
#if defined(__GNUC__)
|
|
323
|
+
#pragma GCC diagnostic push
|
|
324
|
+
#pragma GCC diagnostic ignored "-Wconversion"
|
|
325
|
+
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
326
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
327
|
+
#if defined(__clang__)
|
|
328
|
+
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
329
|
+
#pragma clang diagnostic ignored "-Wpedantic"
|
|
330
|
+
#endif
|
|
331
|
+
#endif
|
|
332
|
+
if constexpr (type_traits::has_value<Lhs_T>
|
|
333
|
+
and type_traits::has_value<Rhs_T>)
|
|
334
|
+
{
|
|
335
|
+
return Lhs_T::value > Rhs_T::value;
|
|
336
|
+
}
|
|
337
|
+
else
|
|
338
|
+
{
|
|
339
|
+
return get (lhs) > get (rhs);
|
|
340
|
+
}
|
|
341
|
+
#if defined(__GNUC__)
|
|
342
|
+
#pragma GCC diagnostic pop
|
|
343
|
+
#endif
|
|
344
|
+
}() }
|
|
345
|
+
{
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// ------------------------------------------------------------------------
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* @details
|
|
352
|
+
* Evaluates whether `lhs >= rhs` inside an immediately invoked lambda
|
|
353
|
+
* and passes the boolean result to the `binary_op_` base class
|
|
354
|
+
* constructor. Supports types with static `value` members and generic
|
|
355
|
+
* types.
|
|
356
|
+
*/
|
|
357
|
+
template <class Lhs_T, class Rhs_T>
|
|
358
|
+
constexpr ge_<Lhs_T, Rhs_T>::ge_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
359
|
+
: binary_op_<Lhs_T, Rhs_T>{ lhs, rhs, [&]
|
|
360
|
+
{
|
|
361
|
+
using std::operator>=;
|
|
362
|
+
|
|
363
|
+
#if defined(__GNUC__)
|
|
364
|
+
#pragma GCC diagnostic push
|
|
365
|
+
#pragma GCC diagnostic ignored "-Wconversion"
|
|
366
|
+
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
367
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
368
|
+
#if defined(__clang__)
|
|
369
|
+
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
370
|
+
#pragma clang diagnostic ignored "-Wpedantic"
|
|
371
|
+
#endif
|
|
372
|
+
#endif
|
|
373
|
+
if constexpr (type_traits::has_value<Lhs_T>
|
|
374
|
+
and type_traits::has_value<Rhs_T>)
|
|
375
|
+
{
|
|
376
|
+
return Lhs_T::value >= Rhs_T::value;
|
|
377
|
+
}
|
|
378
|
+
else
|
|
379
|
+
{
|
|
380
|
+
return get (lhs) >= get (rhs);
|
|
381
|
+
}
|
|
382
|
+
#if defined(__GNUC__)
|
|
383
|
+
#pragma GCC diagnostic pop
|
|
384
|
+
#endif
|
|
385
|
+
}() }
|
|
386
|
+
{
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ------------------------------------------------------------------------
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* @details
|
|
393
|
+
* Evaluates whether `lhs < rhs` inside an immediately invoked lambda
|
|
394
|
+
* and passes the boolean result to the `binary_op_` base class
|
|
395
|
+
* constructor. Supports types with static `value` members and generic
|
|
396
|
+
* types.
|
|
397
|
+
*/
|
|
398
|
+
template <class Lhs_T, class Rhs_T>
|
|
399
|
+
constexpr lt_<Lhs_T, Rhs_T>::lt_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
400
|
+
: binary_op_<Lhs_T, Rhs_T>{ lhs, rhs, [&]
|
|
401
|
+
{
|
|
402
|
+
using std::operator<;
|
|
403
|
+
|
|
404
|
+
#if defined(__GNUC__)
|
|
405
|
+
#pragma GCC diagnostic push
|
|
406
|
+
#pragma GCC diagnostic ignored "-Wconversion"
|
|
407
|
+
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
408
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
409
|
+
#if defined(__clang__)
|
|
410
|
+
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
411
|
+
#pragma clang diagnostic ignored "-Wpedantic"
|
|
412
|
+
#endif
|
|
413
|
+
#endif
|
|
414
|
+
if constexpr (type_traits::has_value<Lhs_T>
|
|
415
|
+
and type_traits::has_value<Rhs_T>)
|
|
416
|
+
{
|
|
417
|
+
return Lhs_T::value < Rhs_T::value;
|
|
418
|
+
}
|
|
419
|
+
else
|
|
420
|
+
{
|
|
421
|
+
return get (lhs) < get (rhs);
|
|
422
|
+
}
|
|
423
|
+
#if defined(__GNUC__)
|
|
424
|
+
#pragma GCC diagnostic pop
|
|
425
|
+
#endif
|
|
426
|
+
}() }
|
|
427
|
+
{
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// ------------------------------------------------------------------------
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* @details
|
|
434
|
+
* Evaluates whether `lhs <= rhs` inside an immediately invoked lambda
|
|
435
|
+
* and passes the boolean result to the `binary_op_` base class
|
|
436
|
+
* constructor. Supports types with static `value` members and generic
|
|
437
|
+
* types.
|
|
438
|
+
*/
|
|
439
|
+
template <class Lhs_T, class Rhs_T>
|
|
440
|
+
constexpr le_<Lhs_T, Rhs_T>::le_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
441
|
+
: binary_op_<Lhs_T, Rhs_T>{ lhs, rhs, [&]
|
|
442
|
+
{
|
|
443
|
+
using std::operator<=;
|
|
444
|
+
|
|
445
|
+
#if defined(__GNUC__)
|
|
446
|
+
#pragma GCC diagnostic push
|
|
447
|
+
#pragma GCC diagnostic ignored "-Wconversion"
|
|
448
|
+
#pragma GCC diagnostic ignored "-Wdouble-promotion"
|
|
449
|
+
#pragma GCC diagnostic ignored "-Wsign-compare"
|
|
450
|
+
#if defined(__clang__)
|
|
451
|
+
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
|
|
452
|
+
#pragma clang diagnostic ignored "-Wpedantic"
|
|
453
|
+
#endif
|
|
454
|
+
#endif
|
|
455
|
+
if constexpr (type_traits::has_value<Lhs_T>
|
|
456
|
+
and type_traits::has_value<Rhs_T>)
|
|
457
|
+
{
|
|
458
|
+
return Lhs_T::value <= Rhs_T::value;
|
|
459
|
+
}
|
|
460
|
+
else
|
|
461
|
+
{
|
|
462
|
+
return get (lhs) <= get (rhs);
|
|
463
|
+
}
|
|
464
|
+
#if defined(__GNUC__)
|
|
465
|
+
#pragma GCC diagnostic pop
|
|
466
|
+
#endif
|
|
467
|
+
}() }
|
|
468
|
+
{
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ------------------------------------------------------------------------
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* @details
|
|
475
|
+
* Evaluates the logical conjunction `static_cast<bool>(lhs) and
|
|
476
|
+
* static_cast<bool>(rhs)` and passes the result to the `binary_op_`
|
|
477
|
+
* base class constructor.
|
|
478
|
+
*/
|
|
479
|
+
template <class Lhs_T, class Rhs_T>
|
|
480
|
+
constexpr and_<Lhs_T, Rhs_T>::and_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
481
|
+
: binary_op_<Lhs_T, Rhs_T>{
|
|
482
|
+
lhs, rhs, static_cast<bool> (lhs) and static_cast<bool> (rhs)
|
|
483
|
+
}
|
|
484
|
+
{
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// ------------------------------------------------------------------------
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @details
|
|
491
|
+
* Evaluates the logical disjunction `static_cast<bool>(lhs) or
|
|
492
|
+
* static_cast<bool>(rhs)` and passes the result to the `binary_op_`
|
|
493
|
+
* base class constructor.
|
|
494
|
+
*/
|
|
495
|
+
template <class Lhs_T, class Rhs_T>
|
|
496
|
+
constexpr or_<Lhs_T, Rhs_T>::or_ (const Lhs_T& lhs, const Rhs_T& rhs)
|
|
497
|
+
: binary_op_<Lhs_T, Rhs_T>{
|
|
498
|
+
lhs, rhs, static_cast<bool> (lhs) or static_cast<bool> (rhs)
|
|
499
|
+
}
|
|
500
|
+
{
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ------------------------------------------------------------------------
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* @details
|
|
507
|
+
* Evaluates the logical negation `not static_cast<bool>(t)` and
|
|
508
|
+
* passes the result to the `unary_op_` base class constructor.
|
|
509
|
+
*/
|
|
510
|
+
template <class T>
|
|
511
|
+
constexpr not_<T>::not_ (const T& t)
|
|
512
|
+
: unary_op_<T>{ t, not static_cast<bool> (t) }
|
|
513
|
+
{
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// ------------------------------------------------------------------------
|
|
517
|
+
|
|
518
|
+
#if defined(__cpp_exceptions)
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* @details
|
|
522
|
+
* Stores the pre-computed boolean result in the private `value_`
|
|
523
|
+
* member.
|
|
524
|
+
*/
|
|
525
|
+
constexpr callable_op_::callable_op_ (bool value) : value_{ value }
|
|
526
|
+
{
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* @details
|
|
531
|
+
* Returns the pre-computed boolean result stored by the derived
|
|
532
|
+
* operator's constructor.
|
|
533
|
+
*/
|
|
534
|
+
constexpr callable_op_::
|
|
535
|
+
operator bool () const
|
|
536
|
+
{
|
|
537
|
+
return value_;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ------------------------------------------------------------------------
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* @details
|
|
544
|
+
* Invokes `func` inside a try/catch block. If `func` throws an
|
|
545
|
+
* exception of type `Exception_T`, the result is `true`; if it throws
|
|
546
|
+
* any other exception the result is `false`; if no exception is thrown
|
|
547
|
+
* the result is `false`. The result is passed to the `callable_op_`
|
|
548
|
+
* base class constructor.
|
|
549
|
+
*/
|
|
550
|
+
template <class Callable_T, class Exception_T>
|
|
551
|
+
constexpr throws_<Callable_T, Exception_T>::throws_ (
|
|
552
|
+
const Callable_T& func)
|
|
553
|
+
: callable_op_{ [&func]
|
|
554
|
+
{
|
|
555
|
+
try
|
|
556
|
+
{
|
|
557
|
+
func ();
|
|
558
|
+
}
|
|
559
|
+
catch (const Exception_T&)
|
|
560
|
+
{
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
catch (...)
|
|
564
|
+
{
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
return false;
|
|
568
|
+
}() }
|
|
569
|
+
{
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// ------------------------------------------------------------------------
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* @details
|
|
576
|
+
* Invokes `func` inside a try/catch block. If `func` throws any
|
|
577
|
+
* exception the result is `true`; if no exception is thrown the result
|
|
578
|
+
* is `false`. The result is passed to the `callable_op_` base class
|
|
579
|
+
* constructor.
|
|
580
|
+
*/
|
|
581
|
+
template <class Callable_T>
|
|
582
|
+
constexpr throws_<Callable_T, void>::throws_ (const Callable_T& func)
|
|
583
|
+
: callable_op_{ [&func]
|
|
584
|
+
{
|
|
585
|
+
try
|
|
586
|
+
{
|
|
587
|
+
func ();
|
|
588
|
+
}
|
|
589
|
+
catch (...)
|
|
590
|
+
{
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
return false;
|
|
594
|
+
}() }
|
|
595
|
+
{
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// ------------------------------------------------------------------------
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* @details
|
|
602
|
+
* Invokes `func` inside a try/catch block. If `func` completes without
|
|
603
|
+
* throwing, the result is `true`; if any exception is thrown the result
|
|
604
|
+
* is `false`. The result is passed to the `callable_op_` base class
|
|
605
|
+
* constructor.
|
|
606
|
+
*/
|
|
607
|
+
template <class Callable_T>
|
|
608
|
+
constexpr nothrow_<Callable_T>::nothrow_ (const Callable_T& func)
|
|
609
|
+
: callable_op_{ [&func]
|
|
610
|
+
{
|
|
611
|
+
try
|
|
612
|
+
{
|
|
613
|
+
func ();
|
|
614
|
+
}
|
|
615
|
+
catch (...)
|
|
616
|
+
{
|
|
617
|
+
return false;
|
|
618
|
+
}
|
|
619
|
+
return true;
|
|
620
|
+
}() }
|
|
621
|
+
{
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
#endif // defined(__cpp_exceptions)
|
|
625
|
+
|
|
626
|
+
// ------------------------------------------------------------------------
|
|
627
|
+
|
|
628
|
+
#if defined(__GNUC__)
|
|
629
|
+
#pragma GCC diagnostic push
|
|
630
|
+
#if defined(__clang__)
|
|
631
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
|
632
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
633
|
+
#endif
|
|
634
|
+
#endif
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* @details
|
|
638
|
+
* For `long double`, a platform-specific path is chosen:
|
|
639
|
+
* - On Windows and on platforms where `long double` has the same
|
|
640
|
+
* storage width as `double` (e.g., ARM, RISC-V), the value is cast
|
|
641
|
+
* to `double` and formatted with `std::to_chars`.
|
|
642
|
+
* - On x86-64 Linux/macOS with 80-bit extended precision, `snprintf`
|
|
643
|
+
* with `%Lg` is used as a portable fallback because
|
|
644
|
+
* `std::to_chars` for `long double` may be unavailable when linking
|
|
645
|
+
* with `lld`.
|
|
646
|
+
*
|
|
647
|
+
* For all other numeric types, `std::to_chars` is called directly,
|
|
648
|
+
* providing locale-independent, allocation-free formatting.
|
|
649
|
+
*/
|
|
650
|
+
template <class T>
|
|
651
|
+
requires std::is_arithmetic_v<T>
|
|
652
|
+
void
|
|
653
|
+
append_number_ (std::string& buffer, const T v)
|
|
654
|
+
{
|
|
655
|
+
char buf[32];
|
|
656
|
+
if constexpr (std::is_same_v<T, long double>)
|
|
657
|
+
{
|
|
658
|
+
#if defined(_WIN32) \
|
|
659
|
+
|| (defined(__SIZEOF_LONG_DOUBLE__) \
|
|
660
|
+
&& __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__)
|
|
661
|
+
// On Windows (all toolchains: MinGW, Clang, MSVC), the C runtime
|
|
662
|
+
// does not handle the %Lg printf specifier correctly for 80-bit
|
|
663
|
+
// long double, producing garbage output. On platforms where long
|
|
664
|
+
// double has the same width as double (ARM, RISC-V), the cast is
|
|
665
|
+
// lossless. In both cases, cast to double and use std::to_chars.
|
|
666
|
+
const auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf),
|
|
667
|
+
static_cast<double> (v));
|
|
668
|
+
if (ec == std::errc{})
|
|
669
|
+
buffer.append (buf, ptr);
|
|
670
|
+
#else
|
|
671
|
+
// On x86-64 Linux/macOS with 80-bit extended-precision long double,
|
|
672
|
+
// std::to_chars for long double may be unavailable (e.g., with lld).
|
|
673
|
+
// Use snprintf as a portable fallback; %Lg is supported correctly
|
|
674
|
+
// by glibc and libc++ on these platforms.
|
|
675
|
+
snprintf (buf, sizeof (buf), "%Lg", v);
|
|
676
|
+
buffer.append (buf);
|
|
677
|
+
#endif
|
|
678
|
+
}
|
|
679
|
+
else
|
|
680
|
+
{
|
|
681
|
+
const auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf), v);
|
|
682
|
+
if (ec == std::errc{})
|
|
683
|
+
buffer.append (buf, ptr);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
#if defined(__GNUC__)
|
|
688
|
+
#pragma GCC diagnostic pop
|
|
689
|
+
#endif
|
|
690
|
+
|
|
691
|
+
// ------------------------------------------------------------------------
|
|
692
|
+
|
|
693
|
+
} // namespace detail
|
|
694
|
+
|
|
695
|
+
// --------------------------------------------------------------------------
|
|
696
|
+
|
|
697
|
+
} // namespace micro_os_plus::micro_test_plus
|
|
698
|
+
|
|
699
|
+
#if defined(__GNUC__)
|
|
700
|
+
#pragma GCC diagnostic pop
|
|
701
|
+
#endif
|
|
702
|
+
|
|
703
|
+
// ----------------------------------------------------------------------------
|
|
704
|
+
|
|
705
|
+
#endif // __cplusplus
|
|
706
|
+
|
|
707
|
+
// ----------------------------------------------------------------------------
|
|
708
|
+
|
|
709
|
+
#endif // MICRO_TEST_PLUS_DETAIL_INLINES_H_
|
|
710
|
+
|
|
711
|
+
// ----------------------------------------------------------------------------
|