@micro-os-plus/micro-test-plus 3.3.1 → 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 +412 -2
- package/CMakeLists.txt +134 -28
- package/README.md +3 -2
- package/config/xcdl-build.json +11 -4
- package/include/micro-os-plus/micro-test-plus/README.md +6 -0
- package/include/micro-os-plus/micro-test-plus/deferred-reporter.h +267 -0
- package/include/micro-os-plus/micro-test-plus/detail.h +272 -1425
- package/include/micro-os-plus/micro-test-plus/exceptions.h +125 -0
- package/include/micro-os-plus/micro-test-plus/expression-formatter.h +669 -0
- package/include/micro-os-plus/micro-test-plus/function-comparators.h +15 -7
- package/include/micro-os-plus/micro-test-plus/inlines/{details-inlines.h → deferred-reporter-inlines.h} +66 -44
- 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/{test-reporter-inlines.h → expression-formatter-inlines.h} +232 -198
- package/include/micro-os-plus/micro-test-plus/inlines/function-comparators-inlines.h +24 -20
- package/include/micro-os-plus/micro-test-plus/inlines/literals-inlines.h +50 -31
- package/include/micro-os-plus/micro-test-plus/inlines/math-inlines.h +25 -19
- 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 +39 -21
- package/include/micro-os-plus/micro-test-plus/inlines/reporter-inlines.h +205 -0
- package/include/micro-os-plus/micro-test-plus/inlines/runner-inlines.h +151 -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 +555 -0
- 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/inlines/utility-inlines.h +126 -0
- package/include/micro-os-plus/micro-test-plus/literals.h +12 -17
- package/include/micro-os-plus/micro-test-plus/math.h +14 -6
- package/include/micro-os-plus/micro-test-plus/operators.h +53 -209
- package/include/micro-os-plus/micro-test-plus/reflection.h +8 -4
- package/include/micro-os-plus/micro-test-plus/{test-reporter-basic.h → reporter-human.h} +80 -74
- package/include/micro-os-plus/micro-test-plus/{test-reporter-tap.h → reporter-tap.h} +77 -71
- package/include/micro-os-plus/micro-test-plus/reporter.h +619 -0
- package/include/micro-os-plus/micro-test-plus/runner-totals.h +250 -0
- package/include/micro-os-plus/micro-test-plus/runner.h +472 -0
- package/include/micro-os-plus/micro-test-plus/test.h +1013 -0
- package/include/micro-os-plus/micro-test-plus/timings.h +363 -0
- package/include/micro-os-plus/micro-test-plus/type-traits.h +223 -577
- package/include/micro-os-plus/micro-test-plus/utility.h +136 -0
- package/include/micro-os-plus/micro-test-plus.h +42 -236
- package/meson.build +11 -6
- package/package.json +11 -3
- package/src/deferred-reporter.cpp +137 -0
- package/src/expression-formatter.cpp +289 -0
- package/src/reflection.cpp +97 -0
- package/src/reporter-human.cpp +816 -0
- package/src/reporter-tap.cpp +772 -0
- package/src/reporter.cpp +481 -0
- package/src/runner-totals.cpp +98 -0
- package/src/runner.cpp +669 -0
- package/src/test.cpp +503 -0
- package/src/timings.cpp +210 -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/inlines/test-suite-inlines.h +0 -115
- package/include/micro-os-plus/micro-test-plus/test-reporter.h +0 -846
- 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/runner.cpp
ADDED
|
@@ -0,0 +1,669 @@
|
|
|
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 runner
|
|
21
|
+
* methods.
|
|
22
|
+
*
|
|
23
|
+
* @details
|
|
24
|
+
* This source file contains the core implementations for the test runner
|
|
25
|
+
* facilities of the µTest++ framework. It provides the logic for initialising
|
|
26
|
+
* the test environment, registering and managing test suites, handling
|
|
27
|
+
* command-line arguments, orchestrating test execution, and determining the
|
|
28
|
+
* overall test result. The implementation supports automated discovery and
|
|
29
|
+
* execution of test suites, flexible verbosity control, and robust mechanisms
|
|
30
|
+
* for aborting test execution in critical scenarios.
|
|
31
|
+
*
|
|
32
|
+
* All definitions reside within the `micro_os_plus::micro_test_plus`
|
|
33
|
+
* namespace, ensuring clear separation from user code and minimising the risk
|
|
34
|
+
* of naming conflicts.
|
|
35
|
+
*
|
|
36
|
+
* This file must be included when building the µTest++ library.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
// ----------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
#include <algorithm>
|
|
42
|
+
#include <string>
|
|
43
|
+
|
|
44
|
+
#if defined(MICRO_OS_PLUS_INCLUDE_CONFIG_H)
|
|
45
|
+
#include <micro-os-plus/config.h>
|
|
46
|
+
#endif // MICRO_OS_PLUS_INCLUDE_CONFIG_H
|
|
47
|
+
|
|
48
|
+
#if defined(MICRO_OS_PLUS_TRACE)
|
|
49
|
+
#include <micro-os-plus/diag/trace.h>
|
|
50
|
+
#endif // MICRO_OS_PLUS_TRACE
|
|
51
|
+
|
|
52
|
+
#include "micro-os-plus/micro-test-plus/runner.h"
|
|
53
|
+
#include "micro-os-plus/micro-test-plus/utility.h"
|
|
54
|
+
#include "micro-os-plus/micro-test-plus/reporter-tap.h"
|
|
55
|
+
#include "micro-os-plus/micro-test-plus/reporter-human.h"
|
|
56
|
+
|
|
57
|
+
// ----------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
#if defined(__GNUC__)
|
|
60
|
+
#pragma GCC diagnostic ignored "-Waggregate-return"
|
|
61
|
+
#if defined(__clang__)
|
|
62
|
+
#pragma clang diagnostic ignored "-Wc++98-compat"
|
|
63
|
+
#pragma clang diagnostic ignored "-Wc++98-c++11-c++14-compat"
|
|
64
|
+
#pragma clang diagnostic ignored "-Wpre-c++17-compat"
|
|
65
|
+
#endif
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
|
|
70
|
+
namespace micro_os_plus::micro_test_plus
|
|
71
|
+
{
|
|
72
|
+
// --------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @details
|
|
76
|
+
* Performs the `static_runner` to `runner` upcast where both types are
|
|
77
|
+
* complete, allowing headers with only forward declarations to request this
|
|
78
|
+
* conversion safely.
|
|
79
|
+
*/
|
|
80
|
+
runner&
|
|
81
|
+
detail::to_runner (static_runner& static_runner_ref) noexcept
|
|
82
|
+
{
|
|
83
|
+
return static_cast<runner&> (static_runner_ref);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @details
|
|
88
|
+
* Performs static-suite registration where `static_runner` is complete,
|
|
89
|
+
* allowing header-only template code to avoid direct dependence on
|
|
90
|
+
* `runner.h` include order.
|
|
91
|
+
*/
|
|
92
|
+
void
|
|
93
|
+
detail::register_static_suite (static_runner& static_runner_ref,
|
|
94
|
+
static_suite& static_suite_ref)
|
|
95
|
+
{
|
|
96
|
+
static_runner::register_static_suite (static_runner_ref, static_suite_ref);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// --------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @details
|
|
103
|
+
* The constructor initialises a new `runner` instance together with
|
|
104
|
+
* its top suite (`top_suite_`). If tracing is enabled, it outputs the
|
|
105
|
+
* function signature for diagnostic purposes.
|
|
106
|
+
*/
|
|
107
|
+
runner::runner (void) : test_node{ "runner" }, top_suite_{ "", *this }
|
|
108
|
+
{
|
|
109
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
110
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
111
|
+
#if defined(__GNUC__)
|
|
112
|
+
#pragma GCC diagnostic push
|
|
113
|
+
#if defined(__clang__)
|
|
114
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
115
|
+
#endif
|
|
116
|
+
#endif
|
|
117
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name ());
|
|
118
|
+
#if defined(__GNUC__)
|
|
119
|
+
#pragma GCC diagnostic pop
|
|
120
|
+
#endif
|
|
121
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @details
|
|
126
|
+
* The constructor initialises a new `runner` instance together with
|
|
127
|
+
* its top suite (`top_suite_`). If tracing is enabled, it outputs the
|
|
128
|
+
* function signature for diagnostic purposes.
|
|
129
|
+
*/
|
|
130
|
+
runner::runner (const char* top_suite_name)
|
|
131
|
+
: test_node{ "runner" }, top_suite_{ top_suite_name, *this }
|
|
132
|
+
{
|
|
133
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
134
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
135
|
+
#if defined(__GNUC__)
|
|
136
|
+
#pragma GCC diagnostic push
|
|
137
|
+
#if defined(__clang__)
|
|
138
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
139
|
+
#endif
|
|
140
|
+
#endif
|
|
141
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name ());
|
|
142
|
+
#if defined(__GNUC__)
|
|
143
|
+
#pragma GCC diagnostic pop
|
|
144
|
+
#endif
|
|
145
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* @details
|
|
150
|
+
* The `reporter_` unique pointer is released automatically. If tracing
|
|
151
|
+
* is enabled, the function signature is output for diagnostic purposes.
|
|
152
|
+
*/
|
|
153
|
+
runner::~runner ()
|
|
154
|
+
{
|
|
155
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
156
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
157
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
158
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
159
|
+
|
|
160
|
+
// reporter_ is a unique_ptr; destroyed automatically.
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#if defined(__GNUC__)
|
|
164
|
+
#pragma GCC diagnostic push
|
|
165
|
+
#if defined(__clang__)
|
|
166
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
|
167
|
+
#endif
|
|
168
|
+
#endif
|
|
169
|
+
/**
|
|
170
|
+
* @details
|
|
171
|
+
* Captures command-line arguments, selects the reporter implementation
|
|
172
|
+
* (`human` or `tap`), starts session timing, and emits the initial
|
|
173
|
+
* reporter notifications for the session and top suite.
|
|
174
|
+
*
|
|
175
|
+
* If the top suite name is not provided, it attempts to derive a name from
|
|
176
|
+
* `argv[0]` or defaults to "default suite".
|
|
177
|
+
*
|
|
178
|
+
* If tracing is enabled, the command-line arguments are
|
|
179
|
+
* also logged for diagnostic purposes.
|
|
180
|
+
*/
|
|
181
|
+
suite&
|
|
182
|
+
runner::initialise (int argc, char* argv[], const char* top_suite_name)
|
|
183
|
+
{
|
|
184
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
185
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
186
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
187
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
188
|
+
|
|
189
|
+
#if !(defined(MICRO_OS_PLUS_INCLUDE_STARTUP) && defined(MICRO_OS_PLUS_TRACE))
|
|
190
|
+
#if defined(MICRO_OS_PLUS_DEBUG)
|
|
191
|
+
trace::printf ("argv[");
|
|
192
|
+
for (int i = 0; i < argc; ++i)
|
|
193
|
+
{
|
|
194
|
+
if (i > 0)
|
|
195
|
+
{
|
|
196
|
+
trace::printf (", ");
|
|
197
|
+
}
|
|
198
|
+
trace::printf ("'%s'", argv[i]);
|
|
199
|
+
}
|
|
200
|
+
trace::puts ("]");
|
|
201
|
+
#endif // defined(MICRO_OS_PLUS_DEBUG)
|
|
202
|
+
#endif // !defined(MICRO_OS_PLUS_INCLUDE_STARTUP)
|
|
203
|
+
|
|
204
|
+
if (strlen (top_suite_name) > 0)
|
|
205
|
+
{
|
|
206
|
+
// If provided by this call, use it, possibly override the
|
|
207
|
+
// deprecated constructor.
|
|
208
|
+
top_suite_name_ = top_suite_name;
|
|
209
|
+
top_suite_.name (top_suite_name_.c_str ());
|
|
210
|
+
}
|
|
211
|
+
else if (strlen (top_suite_.name ()) == 0)
|
|
212
|
+
{
|
|
213
|
+
// If not provided by the constructor or by this call, try to extract a
|
|
214
|
+
// name from argv[0], which is commonly the executable name. If that
|
|
215
|
+
// fails, use a default name.
|
|
216
|
+
if (argc > 0 && argv != nullptr && argv[0] != nullptr)
|
|
217
|
+
{
|
|
218
|
+
std::string_view top_suite_name_view{ utility::extract_file_name (
|
|
219
|
+
argv[0]) };
|
|
220
|
+
|
|
221
|
+
const auto dot_pos = top_suite_name_view.rfind ('.');
|
|
222
|
+
if (dot_pos != std::string_view::npos)
|
|
223
|
+
{
|
|
224
|
+
top_suite_name_view = top_suite_name_view.substr (0, dot_pos);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
top_suite_name_ = top_suite_name_view;
|
|
228
|
+
}
|
|
229
|
+
else
|
|
230
|
+
{
|
|
231
|
+
top_suite_name_ = "default suite";
|
|
232
|
+
}
|
|
233
|
+
top_suite_.name (top_suite_name_.c_str ());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
std::vector<std::string_view> argvs (argv, argv + argc);
|
|
237
|
+
|
|
238
|
+
std::string_view reporter_name{ "tap" };
|
|
239
|
+
static constexpr std::string_view reporter_prefix{ "--reporter=" };
|
|
240
|
+
for (size_t i = 0; i < argvs.size (); ++i)
|
|
241
|
+
{
|
|
242
|
+
if (argvs[i].starts_with (reporter_prefix))
|
|
243
|
+
{
|
|
244
|
+
reporter_name = argvs[i].substr (reporter_prefix.size ());
|
|
245
|
+
}
|
|
246
|
+
else if (argvs[i]
|
|
247
|
+
== reporter_prefix.substr (0, reporter_prefix.size () - 1))
|
|
248
|
+
{
|
|
249
|
+
if (i + 1 < argvs.size ())
|
|
250
|
+
{
|
|
251
|
+
reporter_name = argvs[++i];
|
|
252
|
+
}
|
|
253
|
+
else
|
|
254
|
+
{
|
|
255
|
+
fprintf (stderr, "error: --reporter option requires a "
|
|
256
|
+
"reporter name argument\n");
|
|
257
|
+
exit (1);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Initialise and configure the reporter.
|
|
263
|
+
if (reporter_name == "human")
|
|
264
|
+
{
|
|
265
|
+
reporter_ = std::make_unique<reporter_human> (
|
|
266
|
+
std::make_unique<std::vector<std::string_view>> (
|
|
267
|
+
std::move (argvs)));
|
|
268
|
+
}
|
|
269
|
+
else if (reporter_name == "tap")
|
|
270
|
+
{
|
|
271
|
+
reporter_ = std::make_unique<reporter_tap> (
|
|
272
|
+
std::make_unique<std::vector<std::string_view>> (
|
|
273
|
+
std::move (argvs)));
|
|
274
|
+
}
|
|
275
|
+
else
|
|
276
|
+
{
|
|
277
|
+
fprintf (stderr, "error: unknown reporter '%.*s'\n",
|
|
278
|
+
static_cast<int> (reporter_name.size ()),
|
|
279
|
+
reporter_name.data ());
|
|
280
|
+
exit (1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ------------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
timings_.timestamp_begin ();
|
|
286
|
+
reporter_->begin_session (*this);
|
|
287
|
+
|
|
288
|
+
top_suite_.timings ().timestamp_begin ();
|
|
289
|
+
reporter_->begin_suite (top_suite_);
|
|
290
|
+
|
|
291
|
+
return top_suite_;
|
|
292
|
+
}
|
|
293
|
+
#if defined(__GNUC__)
|
|
294
|
+
#pragma GCC diagnostic pop
|
|
295
|
+
#endif
|
|
296
|
+
|
|
297
|
+
// --------------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* @details
|
|
301
|
+
* Takes ownership of the supplied `suite` unique pointer and appends
|
|
302
|
+
* it to the internal `children_suites_` vector, deferring execution
|
|
303
|
+
* until `run_suites_()` is called. If tracing is enabled, the suite
|
|
304
|
+
* name is logged for diagnostic purposes.
|
|
305
|
+
*/
|
|
306
|
+
void
|
|
307
|
+
runner::register_suite_ (std::unique_ptr<class suite> suite)
|
|
308
|
+
{
|
|
309
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
310
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
311
|
+
#if defined(__GNUC__)
|
|
312
|
+
#pragma GCC diagnostic push
|
|
313
|
+
#if defined(__clang__)
|
|
314
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
315
|
+
#endif
|
|
316
|
+
#endif
|
|
317
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, suite->name ());
|
|
318
|
+
#if defined(__GNUC__)
|
|
319
|
+
#pragma GCC diagnostic pop
|
|
320
|
+
#endif
|
|
321
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
322
|
+
|
|
323
|
+
children_suites_.push_back (std::move (suite));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* @details
|
|
328
|
+
* Sorts `children_suites_` alphabetically by suite name using a
|
|
329
|
+
* selection sort on `unique_ptr::swap`, avoiding the
|
|
330
|
+
* `-Waggregate-return` diagnostic that `std::sort` would trigger on
|
|
331
|
+
* unique-pointer iterators. Each suite is assigned a 1-based index
|
|
332
|
+
* offset by the top-suite index, executed via `suite::run()`, and its
|
|
333
|
+
* totals are accumulated into the runner totals. The executed-subtest
|
|
334
|
+
* counter is not incremented; suites are not counted as subtests.
|
|
335
|
+
*/
|
|
336
|
+
void
|
|
337
|
+
runner::run_suites_ (void)
|
|
338
|
+
{
|
|
339
|
+
// Use selection sort with unique_ptr::swap (returns void) to avoid
|
|
340
|
+
// std::sort triggering -Waggregate-return via std::move_backward,
|
|
341
|
+
// which returns a class-type iterator when operating on unique_ptr
|
|
342
|
+
// elements.
|
|
343
|
+
const size_t n = children_suites_.size ();
|
|
344
|
+
for (size_t i = 0; i < n; ++i)
|
|
345
|
+
{
|
|
346
|
+
size_t min_idx = i;
|
|
347
|
+
for (size_t j = i + 1; j < n; ++j)
|
|
348
|
+
{
|
|
349
|
+
if (std::string_view{ children_suites_[j]->name () }
|
|
350
|
+
< std::string_view{ children_suites_[min_idx]->name () })
|
|
351
|
+
min_idx = j;
|
|
352
|
+
}
|
|
353
|
+
if (min_idx != i)
|
|
354
|
+
children_suites_[i].swap (children_suites_[min_idx]);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
for (size_t i = 0; i < n; ++i)
|
|
358
|
+
{
|
|
359
|
+
auto* suite_ptr = children_suites_[i].get ();
|
|
360
|
+
|
|
361
|
+
// +1 for 1-based index, +1 for top suite
|
|
362
|
+
suite_ptr->own_index (i + 1 + 1);
|
|
363
|
+
|
|
364
|
+
// Run the child suite immediately.
|
|
365
|
+
suite_ptr->run ();
|
|
366
|
+
|
|
367
|
+
// Accumulate the totals from the child suite into the runner
|
|
368
|
+
// totals.
|
|
369
|
+
// DO NOT increment executed_subtests here.
|
|
370
|
+
totals_ += suite_ptr->totals ();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @details
|
|
376
|
+
* Finalises the top suite by recording its end timestamp and notifying
|
|
377
|
+
* the reporter, then accumulates its totals into the runner totals.
|
|
378
|
+
* Subsequently invokes `run_suites_()` to sort, execute, and
|
|
379
|
+
* accumulate all registered child suites. Finally, records the session
|
|
380
|
+
* end timestamp, notifies the reporter, and returns `0` if all checks
|
|
381
|
+
* passed or `1` otherwise.
|
|
382
|
+
*/
|
|
383
|
+
int
|
|
384
|
+
runner::exit_code (void)
|
|
385
|
+
{
|
|
386
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
387
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
388
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
389
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
390
|
+
|
|
391
|
+
if (reporter_ == nullptr)
|
|
392
|
+
{
|
|
393
|
+
fprintf (stderr, "error: test runner not initialised\n");
|
|
394
|
+
return 1;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
top_suite_.timings ().timestamp_end ();
|
|
398
|
+
reporter_->end_suite (top_suite_);
|
|
399
|
+
totals_ += top_suite_.totals ();
|
|
400
|
+
|
|
401
|
+
run_suites_ ();
|
|
402
|
+
|
|
403
|
+
timings_.timestamp_end ();
|
|
404
|
+
reporter_->end_session (*this);
|
|
405
|
+
|
|
406
|
+
const int result = totals_.was_successful () ? 0 : 1;
|
|
407
|
+
|
|
408
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
409
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
410
|
+
#if defined(__GNUC__)
|
|
411
|
+
#pragma GCC diagnostic push
|
|
412
|
+
#if defined(__clang__)
|
|
413
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
414
|
+
#endif
|
|
415
|
+
#endif
|
|
416
|
+
trace::printf ("%s -> %d\n", __PRETTY_FUNCTION__, result);
|
|
417
|
+
#if defined(__GNUC__)
|
|
418
|
+
#pragma GCC diagnostic pop
|
|
419
|
+
#endif
|
|
420
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
421
|
+
|
|
422
|
+
return result;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* @details
|
|
427
|
+
* Prints the source location of the fatal error to `stderr` and then
|
|
428
|
+
* terminates the process via `::abort()`.
|
|
429
|
+
*/
|
|
430
|
+
void
|
|
431
|
+
runner::abort (const reflection::source_location& sl)
|
|
432
|
+
{
|
|
433
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
434
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
435
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
436
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
437
|
+
|
|
438
|
+
#if defined(__GNUC__)
|
|
439
|
+
#pragma GCC diagnostic push
|
|
440
|
+
#if defined(__clang__)
|
|
441
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
442
|
+
#endif
|
|
443
|
+
#endif
|
|
444
|
+
fprintf (stderr, "\nerror: test execution aborted at %s:%u\n",
|
|
445
|
+
reflection::short_name (sl.file_name ()), sl.line ());
|
|
446
|
+
#if defined(__GNUC__)
|
|
447
|
+
#pragma GCC diagnostic pop
|
|
448
|
+
#endif
|
|
449
|
+
|
|
450
|
+
::abort ();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* @details
|
|
455
|
+
* Returns the number of registered child suites plus one, accounting
|
|
456
|
+
* for the top suite.
|
|
457
|
+
*/
|
|
458
|
+
size_t
|
|
459
|
+
runner::suites_count (void) const noexcept
|
|
460
|
+
{
|
|
461
|
+
return children_suites_.size () + 1;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* @details
|
|
466
|
+
* For the base `runner`, the total suite count equals `suites_count()`,
|
|
467
|
+
* as there are no additional static suites.
|
|
468
|
+
*/
|
|
469
|
+
size_t
|
|
470
|
+
runner::total_suites_count (void) const noexcept
|
|
471
|
+
{
|
|
472
|
+
return suites_count ();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// ==========================================================================
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* @details
|
|
479
|
+
* Delegates construction to the `runner` base class.
|
|
480
|
+
* If tracing is enabled, the function signature
|
|
481
|
+
* and suite name are output for diagnostic purposes.
|
|
482
|
+
*/
|
|
483
|
+
static_runner::static_runner (void) : runner{}
|
|
484
|
+
{
|
|
485
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
486
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
487
|
+
#if defined(__GNUC__)
|
|
488
|
+
#pragma GCC diagnostic push
|
|
489
|
+
#if defined(__clang__)
|
|
490
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
491
|
+
#endif
|
|
492
|
+
#endif
|
|
493
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name ());
|
|
494
|
+
#if defined(__GNUC__)
|
|
495
|
+
#pragma GCC diagnostic pop
|
|
496
|
+
#endif
|
|
497
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* @details
|
|
502
|
+
* Delegates construction to the `runner` base class with the given
|
|
503
|
+
* @p top_suite_name. If tracing is enabled, the function signature
|
|
504
|
+
* and suite name are output for diagnostic purposes.
|
|
505
|
+
*/
|
|
506
|
+
static_runner::static_runner (const char* top_suite_name)
|
|
507
|
+
: runner{ top_suite_name }
|
|
508
|
+
{
|
|
509
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
510
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
511
|
+
#if defined(__GNUC__)
|
|
512
|
+
#pragma GCC diagnostic push
|
|
513
|
+
#if defined(__clang__)
|
|
514
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
515
|
+
#endif
|
|
516
|
+
#endif
|
|
517
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name ());
|
|
518
|
+
#if defined(__GNUC__)
|
|
519
|
+
#pragma GCC diagnostic pop
|
|
520
|
+
#endif
|
|
521
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* @details
|
|
526
|
+
* If `static_children_suites_` is non-null, the dynamically allocated
|
|
527
|
+
* vector of raw pointers is deleted and the pointer is reset to
|
|
528
|
+
* `nullptr`. The pointed-to `static_suite` objects are not deleted,
|
|
529
|
+
* as they are static storage-duration objects. If tracing is enabled,
|
|
530
|
+
* the function signature is output for diagnostic purposes.
|
|
531
|
+
*/
|
|
532
|
+
static_runner::~static_runner ()
|
|
533
|
+
{
|
|
534
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
535
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
536
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
537
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
538
|
+
|
|
539
|
+
if (static_children_suites_ != nullptr)
|
|
540
|
+
{
|
|
541
|
+
// The tests are static, so we do not delete them, but we need to
|
|
542
|
+
// delete the array of pointers.
|
|
543
|
+
delete static_children_suites_;
|
|
544
|
+
static_children_suites_ = nullptr;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* @details
|
|
550
|
+
* Returns the number of elements in `static_children_suites_`, or
|
|
551
|
+
* zero if the vector has not been allocated yet.
|
|
552
|
+
*/
|
|
553
|
+
size_t
|
|
554
|
+
static_runner::static_suites_count (void) const noexcept
|
|
555
|
+
{
|
|
556
|
+
return static_children_suites_ != nullptr
|
|
557
|
+
? static_children_suites_->size ()
|
|
558
|
+
: 0;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* @details
|
|
563
|
+
* Returns the combined count of dynamically registered suites (from
|
|
564
|
+
* the base `runner`) and statically registered suites.
|
|
565
|
+
*/
|
|
566
|
+
size_t
|
|
567
|
+
static_runner::total_suites_count (void) const noexcept
|
|
568
|
+
{
|
|
569
|
+
return suites_count () + static_suites_count ();
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* @details
|
|
574
|
+
* First invokes `runner::run_suites_()` to execute all dynamically
|
|
575
|
+
* registered child suites. If `static_children_suites_` is non-null,
|
|
576
|
+
* its contents are sorted alphabetically by suite name using selection
|
|
577
|
+
* sort on raw pointers, each suite is assigned a 1-based index offset
|
|
578
|
+
* by the dynamic suite count, executed via `suite::run()`, and its
|
|
579
|
+
* totals are accumulated into the runner totals.
|
|
580
|
+
*/
|
|
581
|
+
void
|
|
582
|
+
static_runner::run_suites_ (void)
|
|
583
|
+
{
|
|
584
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
585
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
586
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
587
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
588
|
+
|
|
589
|
+
runner::run_suites_ ();
|
|
590
|
+
|
|
591
|
+
if (static_children_suites_ != nullptr)
|
|
592
|
+
{
|
|
593
|
+
// Use selection sort with std::swap on raw pointers (returns void)
|
|
594
|
+
// to avoid std::sort triggering -Waggregate-return via
|
|
595
|
+
// std::move_backward returning a class-type iterator.
|
|
596
|
+
const size_t n = static_children_suites_->size ();
|
|
597
|
+
auto& suites = *static_children_suites_;
|
|
598
|
+
for (size_t i = 0; i < n; ++i)
|
|
599
|
+
{
|
|
600
|
+
size_t min_idx = i;
|
|
601
|
+
for (size_t j = i + 1; j < n; ++j)
|
|
602
|
+
{
|
|
603
|
+
if (std::string_view{ suites[j]->name () }
|
|
604
|
+
< std::string_view{ suites[min_idx]->name () })
|
|
605
|
+
min_idx = j;
|
|
606
|
+
}
|
|
607
|
+
if (min_idx != i)
|
|
608
|
+
std::swap (suites[i], suites[min_idx]);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
for (size_t i = 0; i < n; ++i)
|
|
612
|
+
{
|
|
613
|
+
auto* suite_ptr = suites[i];
|
|
614
|
+
|
|
615
|
+
suite_ptr->own_index (i + 1 + suites_count ());
|
|
616
|
+
|
|
617
|
+
// Run the child suite immediately.
|
|
618
|
+
suite_ptr->run ();
|
|
619
|
+
|
|
620
|
+
// Accumulate the totals from the static suite into the runner
|
|
621
|
+
// totals.
|
|
622
|
+
// DO NOT increment executed_subtests here.
|
|
623
|
+
totals_ += suite_ptr->totals ();
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* @details
|
|
630
|
+
* If `runner.static_children_suites_` is null, a new
|
|
631
|
+
* `std::vector<static_suite*>` is heap-allocated and assigned to it.
|
|
632
|
+
* The address of @p suite is then appended to the vector. This method
|
|
633
|
+
* is intended to be called from the constructor of `static_suite`,
|
|
634
|
+
* before test execution begins.
|
|
635
|
+
*/
|
|
636
|
+
void
|
|
637
|
+
static_runner::register_static_suite (static_runner& runner,
|
|
638
|
+
static_suite& suite)
|
|
639
|
+
{
|
|
640
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
641
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
642
|
+
#if defined(__GNUC__)
|
|
643
|
+
#pragma GCC diagnostic push
|
|
644
|
+
#if defined(__clang__)
|
|
645
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
646
|
+
#endif
|
|
647
|
+
#endif
|
|
648
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, suite.name ());
|
|
649
|
+
#if defined(__GNUC__)
|
|
650
|
+
#pragma GCC diagnostic pop
|
|
651
|
+
#endif
|
|
652
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
653
|
+
|
|
654
|
+
if (runner.static_children_suites_ == nullptr)
|
|
655
|
+
{
|
|
656
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
657
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
658
|
+
trace::printf ("%s new static_children_suites_ array\n",
|
|
659
|
+
__PRETTY_FUNCTION__);
|
|
660
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
661
|
+
runner.static_children_suites_ = new std::vector<static_suite*>;
|
|
662
|
+
}
|
|
663
|
+
runner.static_children_suites_->push_back (&suite);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// --------------------------------------------------------------------------
|
|
667
|
+
} // namespace micro_os_plus::micro_test_plus
|
|
668
|
+
|
|
669
|
+
// ----------------------------------------------------------------------------
|