@micro-os-plus/micro-test-plus 3.3.1 → 4.0.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 +330 -2
- package/CMakeLists.txt +79 -23
- package/README.md +1 -1
- package/config/xcdl-build.json +11 -4
- package/include/micro-os-plus/micro-test-plus/deferred-reporter.h +292 -0
- package/include/micro-os-plus/micro-test-plus/detail.h +462 -1076
- package/include/micro-os-plus/micro-test-plus/exceptions.h +126 -0
- package/include/micro-os-plus/micro-test-plus/function-comparators.h +10 -7
- package/include/micro-os-plus/micro-test-plus/inlines/{details-inlines.h → deferred-reporter-inlines.h} +49 -22
- package/include/micro-os-plus/micro-test-plus/inlines/function-comparators-inlines.h +67 -4
- package/include/micro-os-plus/micro-test-plus/inlines/literals-inlines.h +3 -6
- package/include/micro-os-plus/micro-test-plus/inlines/math-inlines.h +21 -15
- package/include/micro-os-plus/micro-test-plus/inlines/reflection-inlines.h +35 -17
- package/include/micro-os-plus/micro-test-plus/inlines/{test-reporter-inlines.h → reporter-inlines.h} +176 -106
- package/include/micro-os-plus/micro-test-plus/inlines/{test-suite-inlines.h → runner-inlines.h} +41 -43
- package/include/micro-os-plus/micro-test-plus/inlines/test-inlines.h +369 -0
- package/include/micro-os-plus/micro-test-plus/inlines/utility-inlines.h +126 -0
- package/include/micro-os-plus/micro-test-plus/literals.h +4 -3
- package/include/micro-os-plus/micro-test-plus/math.h +9 -6
- package/include/micro-os-plus/micro-test-plus/operators.h +38 -44
- package/include/micro-os-plus/micro-test-plus/reflection.h +15 -4
- package/include/micro-os-plus/micro-test-plus/{test-reporter-basic.h → reporter-human.h} +72 -72
- package/include/micro-os-plus/micro-test-plus/{test-reporter-tap.h → reporter-tap.h} +69 -69
- package/include/micro-os-plus/micro-test-plus/{test-reporter.h → reporter.h} +296 -200
- package/include/micro-os-plus/micro-test-plus/runner-totals.h +264 -0
- package/include/micro-os-plus/micro-test-plus/runner.h +453 -0
- package/include/micro-os-plus/micro-test-plus/test.h +1069 -0
- package/include/micro-os-plus/micro-test-plus/timings.h +366 -0
- package/include/micro-os-plus/micro-test-plus/type-traits.h +239 -545
- package/include/micro-os-plus/micro-test-plus/utility.h +135 -0
- package/include/micro-os-plus/micro-test-plus.h +25 -228
- package/meson.build +10 -6
- package/package.json +1 -1
- package/src/deferred-reporter.cpp +118 -0
- package/src/reflection.cpp +95 -0
- package/src/reporter-human.cpp +822 -0
- package/src/reporter-tap.cpp +782 -0
- package/src/reporter.cpp +676 -0
- package/src/runner-totals.cpp +95 -0
- package/src/runner.cpp +563 -0
- package/src/test.cpp +496 -0
- package/src/timings.cpp +209 -0
- package/src/utility.cpp +163 -0
- package/.cmake-format.yaml +0 -11
- package/include/micro-os-plus/micro-test-plus/inlines/micro-test-plus-inlines.h +0 -313
- package/include/micro-os-plus/micro-test-plus/test-runner.h +0 -281
- package/include/micro-os-plus/micro-test-plus/test-suite.h +0 -492
- package/src/micro-test-plus.cpp +0 -316
- package/src/test-reporter-basic.cpp +0 -466
- package/src/test-reporter-tap.cpp +0 -530
- package/src/test-reporter.cpp +0 -399
- package/src/test-runner.cpp +0 -311
- package/src/test-suite.cpp +0 -304
package/src/test.cpp
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
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++ source file with implementations for the µTest++ test suite
|
|
21
|
+
* methods.
|
|
22
|
+
*
|
|
23
|
+
* @details
|
|
24
|
+
* This source file contains the core implementations for the test suite
|
|
25
|
+
* facilities of the µTest++ framework. It provides the logic for constructing,
|
|
26
|
+
* registering, and managing test suites and their associated test cases. The
|
|
27
|
+
* implementation covers initialisation and clean-up routines, execution of
|
|
28
|
+
* test suites and test cases, tracking of successful and failed checks, and
|
|
29
|
+
* integration with the test reporter for structured output.
|
|
30
|
+
*
|
|
31
|
+
* The design ensures that test suites are non-copyable and non-movable,
|
|
32
|
+
* maintaining unique ownership and consistent state. Flexible support for
|
|
33
|
+
* callable objects enables a wide range of test suite definitions,
|
|
34
|
+
* facilitating expressive and maintainable test organisation across embedded
|
|
35
|
+
* and general C++ projects.
|
|
36
|
+
*
|
|
37
|
+
* All definitions reside within the `micro_os_plus::micro_test_plus`
|
|
38
|
+
* namespace, ensuring clear separation from user code and minimising the risk
|
|
39
|
+
* of naming conflicts.
|
|
40
|
+
*
|
|
41
|
+
* This file must be included when building the µTest++ library.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
// ----------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
#if defined(MICRO_OS_PLUS_INCLUDE_CONFIG_H)
|
|
47
|
+
#include <micro-os-plus/config.h>
|
|
48
|
+
#endif // MICRO_OS_PLUS_INCLUDE_CONFIG_H
|
|
49
|
+
|
|
50
|
+
#include <micro-os-plus/micro-test-plus.h>
|
|
51
|
+
#include <micro-os-plus/diag/trace.h>
|
|
52
|
+
|
|
53
|
+
// ----------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
#if defined(__GNUC__)
|
|
56
|
+
#if defined(__clang__)
|
|
57
|
+
#pragma clang diagnostic ignored "-Wc++98-compat"
|
|
58
|
+
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
|
59
|
+
#else // GCC only
|
|
60
|
+
#pragma GCC diagnostic ignored "-Wredundant-tags"
|
|
61
|
+
#pragma GCC diagnostic ignored "-Wsuggest-final-types"
|
|
62
|
+
#pragma GCC diagnostic ignored "-Wsuggest-final-methods"
|
|
63
|
+
#endif
|
|
64
|
+
#endif
|
|
65
|
+
|
|
66
|
+
// ==========================================================================
|
|
67
|
+
|
|
68
|
+
namespace micro_os_plus::micro_test_plus
|
|
69
|
+
{
|
|
70
|
+
// ==========================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @details
|
|
74
|
+
* Stores the supplied @p name pointer, which is expected to point to
|
|
75
|
+
* a string with a lifetime exceeding that of this instance. If
|
|
76
|
+
* tracing is enabled, the name is output for diagnostic purposes.
|
|
77
|
+
*/
|
|
78
|
+
test_node::test_node (const char* name) : name_{ name }
|
|
79
|
+
{
|
|
80
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
81
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
82
|
+
#if defined(__GNUC__)
|
|
83
|
+
#pragma GCC diagnostic push
|
|
84
|
+
#if defined(__clang__)
|
|
85
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
86
|
+
#endif
|
|
87
|
+
#endif
|
|
88
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name);
|
|
89
|
+
#if defined(__GNUC__)
|
|
90
|
+
#pragma GCC diagnostic pop
|
|
91
|
+
#endif
|
|
92
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @details
|
|
97
|
+
* No resources are owned by `test_node`; the destructor performs no
|
|
98
|
+
* explicit clean-up. If tracing is enabled, the node name is output
|
|
99
|
+
* for diagnostic purposes.
|
|
100
|
+
*/
|
|
101
|
+
test_node::~test_node ()
|
|
102
|
+
{
|
|
103
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
104
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
105
|
+
#if defined(__GNUC__)
|
|
106
|
+
#pragma GCC diagnostic push
|
|
107
|
+
#if defined(__clang__)
|
|
108
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
109
|
+
#endif
|
|
110
|
+
#endif
|
|
111
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
112
|
+
#if defined(__GNUC__)
|
|
113
|
+
#pragma GCC diagnostic pop
|
|
114
|
+
#endif
|
|
115
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ==========================================================================
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @details
|
|
122
|
+
* The constructor initialises a new instance of the `runnable_base` class
|
|
123
|
+
* with the specified name. It sets up the internal state required for
|
|
124
|
+
* managing test cases within the suite. If tracing is enabled, the function
|
|
125
|
+
* signature is output for diagnostic purposes. The default test suite does
|
|
126
|
+
* not require explicit registration, ensuring seamless integration within
|
|
127
|
+
* the µTest++ framework and supporting organised test management across all
|
|
128
|
+
* files and folders.
|
|
129
|
+
*/
|
|
130
|
+
runnable_base::runnable_base (const char* name, class runner& runner,
|
|
131
|
+
size_t own_index)
|
|
132
|
+
: test_node{ name }, runner_{ runner }, own_index_{ own_index }
|
|
133
|
+
{
|
|
134
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
135
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
136
|
+
#if defined(__GNUC__)
|
|
137
|
+
#pragma GCC diagnostic push
|
|
138
|
+
#if defined(__clang__)
|
|
139
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
140
|
+
#endif
|
|
141
|
+
#endif
|
|
142
|
+
trace::printf ("%s '%s' %zu\n", __PRETTY_FUNCTION__, name, own_index_);
|
|
143
|
+
#if defined(__GNUC__)
|
|
144
|
+
#pragma GCC diagnostic pop
|
|
145
|
+
#endif
|
|
146
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @details
|
|
151
|
+
* The destructor releases any resources associated with the
|
|
152
|
+
* `runnable_base` instance. It ensures that the test suite is properly
|
|
153
|
+
* cleaned up after execution, supporting robust and reliable test management
|
|
154
|
+
* across all files and folders within the µTest++ framework.
|
|
155
|
+
*/
|
|
156
|
+
runnable_base::~runnable_base ()
|
|
157
|
+
{
|
|
158
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
159
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
160
|
+
#if defined(__GNUC__)
|
|
161
|
+
#pragma GCC diagnostic push
|
|
162
|
+
#if defined(__clang__)
|
|
163
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
164
|
+
#endif
|
|
165
|
+
#endif
|
|
166
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
167
|
+
#if defined(__GNUC__)
|
|
168
|
+
#pragma GCC diagnostic pop
|
|
169
|
+
#endif
|
|
170
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
171
|
+
|
|
172
|
+
// children_subtests_ holds unique_ptrs; destroyed automatically.
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @details
|
|
177
|
+
* Delegates immediately to `runner_.reporter()`, returning the
|
|
178
|
+
* reporter associated with the owning runner instance.
|
|
179
|
+
*/
|
|
180
|
+
[[nodiscard]] reporter&
|
|
181
|
+
runnable_base::reporter (void) const noexcept
|
|
182
|
+
{
|
|
183
|
+
return runner_.reporter ();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @details
|
|
188
|
+
* Delegates immediately to `runner_.abort()`, passing the supplied
|
|
189
|
+
* source location so that the error message identifies the call site
|
|
190
|
+
* before the process is terminated via `::abort()`.
|
|
191
|
+
*/
|
|
192
|
+
[[noreturn]] void
|
|
193
|
+
runnable_base::abort (const reflection::source_location& sl)
|
|
194
|
+
{
|
|
195
|
+
runner_.abort (sl);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @details
|
|
200
|
+
* Transfers ownership of @p child_test into `children_subtests_` and
|
|
201
|
+
* immediately invokes `subtest::run()` on the newly stored subtest.
|
|
202
|
+
* The parent's executed-subtest counter is then incremented. The
|
|
203
|
+
* child's check counters are intentionally not merged into the parent
|
|
204
|
+
* totals; each subtest reports only its own counters. The child's
|
|
205
|
+
* totals are, however, accumulated into @p suite so that the suite
|
|
206
|
+
* summary reflects all checks performed by its subtests.
|
|
207
|
+
*/
|
|
208
|
+
void
|
|
209
|
+
runnable_base::after_subtest_create_ (
|
|
210
|
+
std::unique_ptr<class subtest> child_test, suite& suite)
|
|
211
|
+
{
|
|
212
|
+
// Transfer ownership into the vector.
|
|
213
|
+
children_subtests_.push_back (std::move (child_test));
|
|
214
|
+
|
|
215
|
+
// Run the child test case immediately.
|
|
216
|
+
class subtest& subtest = *children_subtests_.back ();
|
|
217
|
+
subtest.run ();
|
|
218
|
+
|
|
219
|
+
// This test executed one more subtest.
|
|
220
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
221
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
222
|
+
#if defined(__GNUC__)
|
|
223
|
+
#pragma GCC diagnostic push
|
|
224
|
+
#if defined(__clang__)
|
|
225
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
226
|
+
#endif
|
|
227
|
+
#endif
|
|
228
|
+
trace::printf ("%s subtest '%s' executed one more subtest\n",
|
|
229
|
+
__PRETTY_FUNCTION__, name ());
|
|
230
|
+
#if defined(__GNUC__)
|
|
231
|
+
#pragma GCC diagnostic pop
|
|
232
|
+
#endif
|
|
233
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
234
|
+
totals ().increment_executed_subtests ();
|
|
235
|
+
// Do not accumulate the totals from the child test into the current test
|
|
236
|
+
// totals, each subtest shows only its counters.
|
|
237
|
+
|
|
238
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
239
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
240
|
+
#if defined(__GNUC__)
|
|
241
|
+
#pragma GCC diagnostic push
|
|
242
|
+
#if defined(__clang__)
|
|
243
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
244
|
+
#endif
|
|
245
|
+
#endif
|
|
246
|
+
trace::printf ("%s suite '%s' totals\n", __PRETTY_FUNCTION__,
|
|
247
|
+
suite.name ());
|
|
248
|
+
#if defined(__GNUC__)
|
|
249
|
+
#pragma GCC diagnostic pop
|
|
250
|
+
#endif
|
|
251
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
252
|
+
|
|
253
|
+
// Accumulate the totals from the child test into the suite totals.
|
|
254
|
+
suite.totals () += subtest.totals ();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ==========================================================================
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @details
|
|
261
|
+
* The destructor releases any resources associated with the
|
|
262
|
+
* `test` instance. If tracing is enabled, it outputs the
|
|
263
|
+
* function signature for diagnostic purposes. This ensures that the test
|
|
264
|
+
* suite is properly cleaned up after execution, supporting robust and
|
|
265
|
+
* reliable test management across all files and folders within the µTest++
|
|
266
|
+
* framework.
|
|
267
|
+
*/
|
|
268
|
+
subtest::~subtest ()
|
|
269
|
+
{
|
|
270
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
271
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
272
|
+
#if defined(__GNUC__)
|
|
273
|
+
#pragma GCC diagnostic push
|
|
274
|
+
#if defined(__clang__)
|
|
275
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
276
|
+
#endif
|
|
277
|
+
#endif
|
|
278
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
279
|
+
#if defined(__GNUC__)
|
|
280
|
+
#pragma GCC diagnostic pop
|
|
281
|
+
#endif
|
|
282
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @details
|
|
287
|
+
* Invokes the stored callable with the `Self_T` instance, surrounded by
|
|
288
|
+
* reporter calls to begin and end the subtest.
|
|
289
|
+
*/
|
|
290
|
+
void
|
|
291
|
+
subtest::run (void)
|
|
292
|
+
{
|
|
293
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
294
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
295
|
+
#if defined(__GNUC__)
|
|
296
|
+
#pragma GCC diagnostic push
|
|
297
|
+
#if defined(__clang__)
|
|
298
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
299
|
+
#endif
|
|
300
|
+
#endif
|
|
301
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
302
|
+
#if defined(__GNUC__)
|
|
303
|
+
#pragma GCC diagnostic pop
|
|
304
|
+
#endif
|
|
305
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
306
|
+
|
|
307
|
+
class reporter& reporter = this->reporter ();
|
|
308
|
+
|
|
309
|
+
// For now, subtests do not record the time.
|
|
310
|
+
// this->timings.timestamp_begin ();
|
|
311
|
+
reporter.begin_subtest (*this);
|
|
312
|
+
|
|
313
|
+
// Invoke the callable, passing the self reference followed by the variadic
|
|
314
|
+
// arguments.
|
|
315
|
+
callable_ (*this);
|
|
316
|
+
|
|
317
|
+
// this->timings.timestamp_end ();
|
|
318
|
+
reporter.end_subtest (*this);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// ==========================================================================
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* @details
|
|
325
|
+
* No resources are owned directly by `suite`; the destructor performs
|
|
326
|
+
* no explicit clean-up. If tracing is enabled, the suite name is
|
|
327
|
+
* output for diagnostic purposes.
|
|
328
|
+
*/
|
|
329
|
+
suite::~suite ()
|
|
330
|
+
{
|
|
331
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
332
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
333
|
+
#if defined(__GNUC__)
|
|
334
|
+
#pragma GCC diagnostic push
|
|
335
|
+
#if defined(__clang__)
|
|
336
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
337
|
+
#endif
|
|
338
|
+
#endif
|
|
339
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
340
|
+
#if defined(__GNUC__)
|
|
341
|
+
#pragma GCC diagnostic pop
|
|
342
|
+
#endif
|
|
343
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* @details
|
|
348
|
+
* Invokes the stored callable with the `Self_T` instance, surrounded by
|
|
349
|
+
* reporter calls to begin and end the suite.
|
|
350
|
+
*/
|
|
351
|
+
void
|
|
352
|
+
suite::run (void)
|
|
353
|
+
{
|
|
354
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
355
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
356
|
+
#if defined(__GNUC__)
|
|
357
|
+
#pragma GCC diagnostic push
|
|
358
|
+
#if defined(__clang__)
|
|
359
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
360
|
+
#endif
|
|
361
|
+
#endif
|
|
362
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
363
|
+
#if defined(__GNUC__)
|
|
364
|
+
#pragma GCC diagnostic pop
|
|
365
|
+
#endif
|
|
366
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
367
|
+
|
|
368
|
+
class reporter& reporter = this->reporter ();
|
|
369
|
+
|
|
370
|
+
this->timings ().timestamp_begin ();
|
|
371
|
+
reporter.begin_suite (*this);
|
|
372
|
+
|
|
373
|
+
// Invoke the callable, passing the self reference followed by the variadic
|
|
374
|
+
// arguments.
|
|
375
|
+
callable_ (*this);
|
|
376
|
+
|
|
377
|
+
this->timings ().timestamp_end ();
|
|
378
|
+
reporter.end_suite (*this);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ==========================================================================
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @details
|
|
385
|
+
* Initialises the base `suite` with @p name, the given @p runner, and
|
|
386
|
+
* a no-op callable. Sets `own_index` to 1, reserving index 0 for the
|
|
387
|
+
* runner itself. If tracing is enabled, the name is output for
|
|
388
|
+
* diagnostic purposes.
|
|
389
|
+
*/
|
|
390
|
+
top_suite::top_suite (const char* name, class runner& runner)
|
|
391
|
+
: suite{ name, runner, [] (suite&) noexcept {} }
|
|
392
|
+
{
|
|
393
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
394
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
395
|
+
#if defined(__GNUC__)
|
|
396
|
+
#pragma GCC diagnostic push
|
|
397
|
+
#if defined(__clang__)
|
|
398
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
399
|
+
#endif
|
|
400
|
+
#endif
|
|
401
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name);
|
|
402
|
+
#if defined(__GNUC__)
|
|
403
|
+
#pragma GCC diagnostic pop
|
|
404
|
+
#endif
|
|
405
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
406
|
+
|
|
407
|
+
own_index (1);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* @details
|
|
412
|
+
* No resources are owned directly by `top_suite`; the destructor
|
|
413
|
+
* performs no explicit clean-up. If tracing is enabled, the suite
|
|
414
|
+
* name is output for diagnostic purposes.
|
|
415
|
+
*/
|
|
416
|
+
top_suite::~top_suite ()
|
|
417
|
+
{
|
|
418
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
419
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
420
|
+
#if defined(__GNUC__)
|
|
421
|
+
#pragma GCC diagnostic push
|
|
422
|
+
#if defined(__clang__)
|
|
423
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
424
|
+
#endif
|
|
425
|
+
#endif
|
|
426
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
427
|
+
#if defined(__GNUC__)
|
|
428
|
+
#pragma GCC diagnostic pop
|
|
429
|
+
#endif
|
|
430
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// ==========================================================================
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* @details
|
|
437
|
+
* No resources are owned directly by `static_suite`; the destructor
|
|
438
|
+
* performs no explicit clean-up. If tracing is enabled, the suite
|
|
439
|
+
* name is output for diagnostic purposes.
|
|
440
|
+
*/
|
|
441
|
+
static_suite::~static_suite ()
|
|
442
|
+
{
|
|
443
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
444
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
445
|
+
#if defined(__GNUC__)
|
|
446
|
+
#pragma GCC diagnostic push
|
|
447
|
+
#if defined(__clang__)
|
|
448
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
449
|
+
#endif
|
|
450
|
+
#endif
|
|
451
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
452
|
+
#if defined(__GNUC__)
|
|
453
|
+
#pragma GCC diagnostic pop
|
|
454
|
+
#endif
|
|
455
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @details
|
|
460
|
+
* Records the suite begin timestamp, notifies the reporter via
|
|
461
|
+
* `begin_suite()`, invokes the stored static callable with `*this`,
|
|
462
|
+
* records the suite end timestamp, and notifies the reporter via
|
|
463
|
+
* `end_suite()`.
|
|
464
|
+
*/
|
|
465
|
+
void
|
|
466
|
+
static_suite::run (void)
|
|
467
|
+
{
|
|
468
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
469
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
470
|
+
#if defined(__GNUC__)
|
|
471
|
+
#pragma GCC diagnostic push
|
|
472
|
+
#if defined(__clang__)
|
|
473
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
474
|
+
#endif
|
|
475
|
+
#endif
|
|
476
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
|
|
477
|
+
#if defined(__GNUC__)
|
|
478
|
+
#pragma GCC diagnostic pop
|
|
479
|
+
#endif
|
|
480
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
481
|
+
|
|
482
|
+
class reporter& reporter = this->reporter ();
|
|
483
|
+
|
|
484
|
+
this->timings ().timestamp_begin ();
|
|
485
|
+
reporter.begin_suite (*this);
|
|
486
|
+
|
|
487
|
+
static_callable_ (*this);
|
|
488
|
+
|
|
489
|
+
this->timings ().timestamp_end ();
|
|
490
|
+
reporter.end_suite (*this);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// --------------------------------------------------------------------------
|
|
494
|
+
} // namespace micro_os_plus::micro_test_plus
|
|
495
|
+
|
|
496
|
+
// ----------------------------------------------------------------------------
|
package/src/timings.cpp
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
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++ source file with implementations for the µTest++ timings
|
|
21
|
+
* methods.
|
|
22
|
+
*
|
|
23
|
+
* @details
|
|
24
|
+
* This source file contains the implementations for the `timestamp` and
|
|
25
|
+
* `timestamps` classes of the µTest++ framework. It provides methods
|
|
26
|
+
* for capturing monotonic clock values, checking whether valid
|
|
27
|
+
* timestamps have been recorded, and computing the elapsed time in
|
|
28
|
+
* milliseconds and microseconds between a begin and an end timestamp.
|
|
29
|
+
*
|
|
30
|
+
* All definitions reside within the
|
|
31
|
+
* `micro_os_plus::micro_test_plus` namespace.
|
|
32
|
+
*
|
|
33
|
+
* This file must be included when building the µTest++ library.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
// ----------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
#if defined(MICRO_OS_PLUS_INCLUDE_CONFIG_H)
|
|
39
|
+
#include <micro-os-plus/config.h>
|
|
40
|
+
#endif // MICRO_OS_PLUS_INCLUDE_CONFIG_H
|
|
41
|
+
|
|
42
|
+
#include <micro-os-plus/micro-test-plus.h>
|
|
43
|
+
|
|
44
|
+
#include <cassert>
|
|
45
|
+
|
|
46
|
+
// ----------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
#if defined(__GNUC__)
|
|
49
|
+
#pragma GCC diagnostic ignored "-Waggregate-return"
|
|
50
|
+
#if defined(__clang__)
|
|
51
|
+
#pragma clang diagnostic ignored "-Wpre-c++17-compat"
|
|
52
|
+
#pragma clang diagnostic ignored "-Wc++98-compat"
|
|
53
|
+
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
|
54
|
+
#endif
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
|
|
59
|
+
namespace micro_os_plus::micro_test_plus
|
|
60
|
+
{
|
|
61
|
+
// --------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @details
|
|
65
|
+
* On Windows, the current time is captured via `timespec_get()` with
|
|
66
|
+
* `TIME_UTC`. On POSIX platforms with `CLOCK_MONOTONIC` defined,
|
|
67
|
+
* `clock_gettime(CLOCK_MONOTONIC)` is used to obtain a monotonic
|
|
68
|
+
* timestamp. On platforms where neither macro is defined, `value_`
|
|
69
|
+
* remains zero-initialised.
|
|
70
|
+
*/
|
|
71
|
+
timestamp::timestamp () noexcept
|
|
72
|
+
{
|
|
73
|
+
#if defined(_WIN32)
|
|
74
|
+
timespec_get (&value_, TIME_UTC);
|
|
75
|
+
#elif defined(CLOCK_MONOTONIC)
|
|
76
|
+
clock_gettime (CLOCK_MONOTONIC, &value_);
|
|
77
|
+
#endif
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @details
|
|
82
|
+
* Returns `true` if at least one of the `tv_sec` or `tv_nsec` fields
|
|
83
|
+
* of the underlying `timespec` is non-zero, indicating that a valid
|
|
84
|
+
* clock reading was successfully captured.
|
|
85
|
+
*/
|
|
86
|
+
bool
|
|
87
|
+
timestamp::has_clock (void) const noexcept
|
|
88
|
+
{
|
|
89
|
+
return value_.tv_sec != 0 || value_.tv_nsec != 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @details
|
|
96
|
+
* If the begin timestamp has not yet been set, a `timestamp` is
|
|
97
|
+
* constructed in-place using the default constructor, which captures
|
|
98
|
+
* the current monotonic time. Subsequent calls are silently ignored,
|
|
99
|
+
* ensuring idempotent behaviour.
|
|
100
|
+
*/
|
|
101
|
+
void
|
|
102
|
+
timestamps::timestamp_begin (void) noexcept
|
|
103
|
+
{
|
|
104
|
+
// Ensure it is timestamped only once.
|
|
105
|
+
if (!begin_time_.has_value ())
|
|
106
|
+
{
|
|
107
|
+
begin_time_.emplace ();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @details
|
|
113
|
+
* If the begin timestamp has not yet been set, a `timestamp` is
|
|
114
|
+
* constructed in-place from the supplied `timespec` value. Subsequent
|
|
115
|
+
* calls are silently ignored, ensuring idempotent behaviour.
|
|
116
|
+
*/
|
|
117
|
+
void
|
|
118
|
+
timestamps::timestamp_begin (const timespec& ts) noexcept
|
|
119
|
+
{
|
|
120
|
+
// Ensure it is timestamped only once.
|
|
121
|
+
if (!begin_time_.has_value ())
|
|
122
|
+
{
|
|
123
|
+
begin_time_.emplace (ts);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @details
|
|
129
|
+
* If the end timestamp has not yet been set, a `timestamp` is
|
|
130
|
+
* constructed in-place using the default constructor, which captures
|
|
131
|
+
* the current monotonic time. Subsequent calls are silently ignored,
|
|
132
|
+
* ensuring idempotent behaviour.
|
|
133
|
+
*/
|
|
134
|
+
void
|
|
135
|
+
timestamps::timestamp_end (void) noexcept
|
|
136
|
+
{
|
|
137
|
+
// Ensure it is timestamped only once.
|
|
138
|
+
if (!end_time_.has_value ())
|
|
139
|
+
{
|
|
140
|
+
end_time_.emplace ();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @details
|
|
146
|
+
* If the end timestamp has not yet been set, a `timestamp` is
|
|
147
|
+
* constructed in-place from the supplied `timespec` value. Subsequent
|
|
148
|
+
* calls are silently ignored, ensuring idempotent behaviour.
|
|
149
|
+
*/
|
|
150
|
+
void
|
|
151
|
+
timestamps::timestamp_end (const timespec& ts) noexcept
|
|
152
|
+
{
|
|
153
|
+
// Ensure it is timestamped only once.
|
|
154
|
+
if (!end_time_.has_value ())
|
|
155
|
+
{
|
|
156
|
+
end_time_.emplace (ts);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @details
|
|
162
|
+
* Returns `true` only when both the begin and end optional timestamps
|
|
163
|
+
* are engaged and each contains a valid (non-zero) clock reading, as
|
|
164
|
+
* determined by `timestamp::has_clock()`.
|
|
165
|
+
*/
|
|
166
|
+
bool
|
|
167
|
+
timestamps::has_timestamps (void) const noexcept
|
|
168
|
+
{
|
|
169
|
+
return begin_time_.has_value () && begin_time_->has_clock ()
|
|
170
|
+
&& end_time_.has_value () && end_time_->has_clock ();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @details
|
|
175
|
+
* Subtracts the begin timestamp from the end timestamp in nanoseconds.
|
|
176
|
+
* If the nanosecond difference is negative, one second is borrowed
|
|
177
|
+
* from the seconds delta to normalise the result. The total elapsed
|
|
178
|
+
* duration in microseconds is then split into whole milliseconds
|
|
179
|
+
* (written to @p milliseconds) and the remainder microseconds (written
|
|
180
|
+
* to @p microseconds). Requires `has_timestamps()` to be `true`;
|
|
181
|
+
* behaviour is undefined otherwise.
|
|
182
|
+
*/
|
|
183
|
+
void
|
|
184
|
+
timestamps::compute_elapsed_time (uint32_t& milliseconds,
|
|
185
|
+
uint32_t& microseconds) const
|
|
186
|
+
{
|
|
187
|
+
assert (has_timestamps ());
|
|
188
|
+
|
|
189
|
+
// Precondition: has_timestamps() must be true before calling this method.
|
|
190
|
+
// Invoking it with disengaged optionals is undefined behaviour.
|
|
191
|
+
long long delta_ns
|
|
192
|
+
= end_time_->value ().tv_nsec - begin_time_->value ().tv_nsec;
|
|
193
|
+
long long delta_s
|
|
194
|
+
= end_time_->value ().tv_sec - begin_time_->value ().tv_sec;
|
|
195
|
+
if (delta_ns < 0)
|
|
196
|
+
{
|
|
197
|
+
delta_ns += 1000000000LL;
|
|
198
|
+
--delta_s;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Split into milliseconds and microseconds.
|
|
202
|
+
const long long total_us = delta_s * 1000000LL + delta_ns / 1000LL;
|
|
203
|
+
milliseconds = static_cast<uint32_t> (total_us / 1000LL);
|
|
204
|
+
microseconds = static_cast<uint32_t> (total_us % 1000LL);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// --------------------------------------------------------------------------
|
|
208
|
+
|
|
209
|
+
} // namespace micro_os_plus::micro_test_plus
|