@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
|
@@ -0,0 +1,816 @@
|
|
|
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++ human test
|
|
21
|
+
* reporter methods.
|
|
22
|
+
*
|
|
23
|
+
* @details
|
|
24
|
+
* This source file contains the implementations for `reporter_human`,
|
|
25
|
+
* the default concrete implementation of the `reporter` abstract
|
|
26
|
+
* interface. It formats and presents test results using `printf`-based
|
|
27
|
+
* standard output, accumulating output in an internal string buffer and
|
|
28
|
+
* supporting colour-coded diagnostics and multiple verbosity levels.
|
|
29
|
+
*
|
|
30
|
+
* All definitions reside within the `micro_os_plus::micro_test_plus`
|
|
31
|
+
* namespace, ensuring clear separation from user code and minimising the risk
|
|
32
|
+
* of naming conflicts.
|
|
33
|
+
*
|
|
34
|
+
* This file must be included when building the µTest++ library.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
// ----------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
// For the PRIu32 macro used in snprintf() formatting of uint32_t values.
|
|
40
|
+
#include <cinttypes>
|
|
41
|
+
|
|
42
|
+
#if defined(__APPLE__) || defined(__linux__) || defined(__unix__)
|
|
43
|
+
// For isatty() to detect if stdout is a terminal, enabling colour output.
|
|
44
|
+
#include <unistd.h>
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
#if defined(MICRO_OS_PLUS_INCLUDE_CONFIG_H)
|
|
48
|
+
#include <micro-os-plus/config.h>
|
|
49
|
+
#endif // MICRO_OS_PLUS_INCLUDE_CONFIG_H
|
|
50
|
+
|
|
51
|
+
#if defined(MICRO_OS_PLUS_TRACE)
|
|
52
|
+
#include <micro-os-plus/diag/trace.h>
|
|
53
|
+
#endif // MICRO_OS_PLUS_TRACE
|
|
54
|
+
|
|
55
|
+
#include "micro-os-plus/micro-test-plus/reporter-human.h"
|
|
56
|
+
#include "micro-os-plus/micro-test-plus/runner.h"
|
|
57
|
+
#include "micro-os-plus/micro-test-plus/test.h"
|
|
58
|
+
|
|
59
|
+
// ----------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
#if defined(__GNUC__)
|
|
62
|
+
#pragma GCC diagnostic ignored "-Waggregate-return"
|
|
63
|
+
#if defined(__clang__)
|
|
64
|
+
#pragma clang diagnostic ignored "-Wunknown-warning-option"
|
|
65
|
+
#pragma clang diagnostic ignored "-Wc++98-compat"
|
|
66
|
+
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
|
67
|
+
#endif
|
|
68
|
+
#endif
|
|
69
|
+
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
namespace micro_os_plus::micro_test_plus
|
|
73
|
+
{
|
|
74
|
+
// --------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @details
|
|
78
|
+
* Delegates construction to the `reporter` base class with the supplied
|
|
79
|
+
* argument vector. On POSIX platforms, if `stdout` is connected to a
|
|
80
|
+
* terminal (`isatty()`), colour output is enabled by selecting the
|
|
81
|
+
* red/green colour scheme. If tracing is enabled, the function
|
|
82
|
+
* signature is output for diagnostic purposes.
|
|
83
|
+
*/
|
|
84
|
+
reporter_human::reporter_human (
|
|
85
|
+
std::unique_ptr<std::vector<std::string_view>> argvs)
|
|
86
|
+
: reporter{ std::move (argvs) }
|
|
87
|
+
{
|
|
88
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
89
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
90
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
91
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
92
|
+
|
|
93
|
+
#if defined(__APPLE__) || defined(__linux__) || defined(__unix__)
|
|
94
|
+
if (isatty (fileno (stdout)))
|
|
95
|
+
{
|
|
96
|
+
colours_ = detail::colours_red_green;
|
|
97
|
+
}
|
|
98
|
+
#endif
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* @details
|
|
103
|
+
* No resources are owned directly by `reporter_human`; the destructor
|
|
104
|
+
* performs no explicit clean-up. If tracing is enabled, the function
|
|
105
|
+
* signature is output for diagnostic purposes.
|
|
106
|
+
*/
|
|
107
|
+
reporter_human::~reporter_human ()
|
|
108
|
+
{
|
|
109
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
110
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
|
|
111
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
112
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// --------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @brief Number of spaces per indentation level.
|
|
119
|
+
*
|
|
120
|
+
* @details
|
|
121
|
+
* Used by `operator<<(indent_t)` and related methods to compute
|
|
122
|
+
* the leading whitespace for each nesting depth.
|
|
123
|
+
*/
|
|
124
|
+
constexpr size_t indent_size = 4;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @details
|
|
128
|
+
* This operator overload appends spaces to the internal output buffer
|
|
129
|
+
* corresponding to `m.level` two-space indentation levels. It enables
|
|
130
|
+
* structured, readable nesting of test output across all test cases and
|
|
131
|
+
* folders by allowing `*this << indent(n) << "text"` chaining.
|
|
132
|
+
*/
|
|
133
|
+
reporter_human&
|
|
134
|
+
reporter_human::operator<< (detail::indent_t m)
|
|
135
|
+
{
|
|
136
|
+
buffer_.append (m.level * indent_size, ' ');
|
|
137
|
+
return *this;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// --------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @details
|
|
144
|
+
* If verbosity is not silent, a blank line is printed to `stdout`
|
|
145
|
+
* before the build-information block emitted by `write_info_()`. A
|
|
146
|
+
* fixed "µTest++ human report" heading is then written both to the
|
|
147
|
+
* output file (if open) and to `stdout`. The `add_empty_line_` flag
|
|
148
|
+
* is set so that subsequent suite output is visually separated.
|
|
149
|
+
*/
|
|
150
|
+
void
|
|
151
|
+
reporter_human::begin_session ([[maybe_unused]] runner& runner)
|
|
152
|
+
{
|
|
153
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
154
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
155
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
156
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
157
|
+
|
|
158
|
+
#if defined(__GNUC__)
|
|
159
|
+
#pragma GCC diagnostic push
|
|
160
|
+
#if defined(__clang__)
|
|
161
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
162
|
+
#endif
|
|
163
|
+
#endif
|
|
164
|
+
|
|
165
|
+
if (verbosity_ != verbosity::silent)
|
|
166
|
+
{
|
|
167
|
+
printf ("\n");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
write_info_ ();
|
|
171
|
+
|
|
172
|
+
const char* message = "µTest++ human report";
|
|
173
|
+
if (output_file_ != nullptr)
|
|
174
|
+
{
|
|
175
|
+
fprintf (output_file_, "%s\n", message);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (verbosity_ != verbosity::silent)
|
|
179
|
+
{
|
|
180
|
+
printf ("%s\n", message);
|
|
181
|
+
|
|
182
|
+
flush ();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
add_empty_line_ = true;
|
|
186
|
+
|
|
187
|
+
#if defined(__GNUC__)
|
|
188
|
+
#pragma GCC diagnostic pop
|
|
189
|
+
#endif
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @details
|
|
194
|
+
* Prints a summary line to `stdout` (and to the output file if open)
|
|
195
|
+
* showing the total number of successful checks, failed checks,
|
|
196
|
+
* executed test cases, and test suites, together with the elapsed
|
|
197
|
+
* time when timing data is available. The line is prefixed with a
|
|
198
|
+
* green `✓` tick on success or a red `✗` cross on failure, using
|
|
199
|
+
* ANSI colour codes when colour output is enabled.
|
|
200
|
+
*/
|
|
201
|
+
void
|
|
202
|
+
reporter_human::end_session (runner& runner)
|
|
203
|
+
{
|
|
204
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
205
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
206
|
+
trace::printf ("%s\n", __PRETTY_FUNCTION__);
|
|
207
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
208
|
+
|
|
209
|
+
#if defined(__GNUC__)
|
|
210
|
+
#pragma GCC diagnostic push
|
|
211
|
+
#if defined(__clang__)
|
|
212
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
213
|
+
#endif
|
|
214
|
+
#endif
|
|
215
|
+
|
|
216
|
+
if (verbosity_ != verbosity::silent)
|
|
217
|
+
{
|
|
218
|
+
if (add_empty_line_)
|
|
219
|
+
{
|
|
220
|
+
printf ("\n");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
size_t total_suites_count = runner.total_suites_count ();
|
|
224
|
+
|
|
225
|
+
uint32_t milliseconds = 0;
|
|
226
|
+
uint32_t microseconds = 0;
|
|
227
|
+
if (runner.timings ().has_timestamps ())
|
|
228
|
+
{
|
|
229
|
+
runner.timings ().compute_elapsed_time (milliseconds,
|
|
230
|
+
microseconds);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
char message_totals[300];
|
|
234
|
+
snprintf (message_totals, sizeof (message_totals),
|
|
235
|
+
"Total: %zu check%s passed, %zu failed, in %zu test "
|
|
236
|
+
"case%s, %zu test suite%s",
|
|
237
|
+
runner.totals ().successful_checks (),
|
|
238
|
+
runner.totals ().successful_checks () == 1 ? "" : "s",
|
|
239
|
+
runner.totals ().failed_checks (),
|
|
240
|
+
runner.totals ().executed_subtests (),
|
|
241
|
+
runner.totals ().executed_subtests () == 1 ? "" : "s",
|
|
242
|
+
total_suites_count, total_suites_count == 1 ? "" : "s");
|
|
243
|
+
|
|
244
|
+
char message_time[120] = "";
|
|
245
|
+
if (milliseconds > 0 || microseconds > 0)
|
|
246
|
+
{
|
|
247
|
+
snprintf (message_time, sizeof (message_time),
|
|
248
|
+
", time: %" PRIu32 ".%03" PRIu32 " ms", milliseconds,
|
|
249
|
+
microseconds);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (runner.totals ().was_successful ()) [[likely]]
|
|
253
|
+
{
|
|
254
|
+
if (output_file_ != nullptr)
|
|
255
|
+
{
|
|
256
|
+
fprintf (output_file_, "✓ %s%s\n", message_totals,
|
|
257
|
+
message_time);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
printf ("%s✓%s %s%s\n", colours_.pass, colours_.none,
|
|
261
|
+
message_totals, message_time);
|
|
262
|
+
}
|
|
263
|
+
else
|
|
264
|
+
{
|
|
265
|
+
if (output_file_ != nullptr)
|
|
266
|
+
{
|
|
267
|
+
fprintf (output_file_, "✗ %s%s\n", message_totals,
|
|
268
|
+
message_time);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
printf ("%s✗%s %s%s\n", colours_.fail, colours_.none,
|
|
272
|
+
message_totals, message_time);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
flush ();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
#if defined(__GNUC__)
|
|
279
|
+
#pragma GCC diagnostic pop
|
|
280
|
+
#endif
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// --------------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* @details
|
|
287
|
+
* This method marks the beginning of a test suite, ensuring that output is
|
|
288
|
+
* properly separated and clearly presented. If there is pending output, the
|
|
289
|
+
* stream is flushed and an empty line is added for clarity. For silent or
|
|
290
|
+
* quiet verbosity levels, output is suppressed. Otherwise, a message
|
|
291
|
+
* indicating the start of the test suite is displayed. This approach
|
|
292
|
+
* enhances the organisation and readability of test results across all test
|
|
293
|
+
* cases and folders.
|
|
294
|
+
*/
|
|
295
|
+
void
|
|
296
|
+
reporter_human::begin_suite (suite& suite)
|
|
297
|
+
{
|
|
298
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
299
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
300
|
+
#pragma GCC diagnostic push
|
|
301
|
+
#if defined(__clang__)
|
|
302
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
303
|
+
#endif
|
|
304
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, suite.name ());
|
|
305
|
+
#pragma GCC diagnostic pop
|
|
306
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
307
|
+
|
|
308
|
+
#if defined(__GNUC__)
|
|
309
|
+
#pragma GCC diagnostic push
|
|
310
|
+
#if defined(__clang__)
|
|
311
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
312
|
+
#endif
|
|
313
|
+
#endif
|
|
314
|
+
|
|
315
|
+
if (verbosity_ == verbosity::normal || verbosity_ == verbosity::verbose)
|
|
316
|
+
{
|
|
317
|
+
if (add_empty_line_)
|
|
318
|
+
{
|
|
319
|
+
printf ("\n");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (output_file_ != nullptr)
|
|
323
|
+
{
|
|
324
|
+
fprintf (output_file_, "• %s\n", suite.name ());
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
printf ("• %s\n", suite.name ());
|
|
328
|
+
|
|
329
|
+
flush ();
|
|
330
|
+
|
|
331
|
+
add_empty_line_ = true;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
#if defined(__GNUC__)
|
|
335
|
+
#pragma GCC diagnostic pop
|
|
336
|
+
#endif
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @details
|
|
341
|
+
* This method marks the end of a test suite, summarising the overall results
|
|
342
|
+
* and presenting them with appropriate formatting and colour coding. If the
|
|
343
|
+
* suite contains test cases and the verbosity is not set to quiet, an empty
|
|
344
|
+
* line is added for clarity. For suites with no failed checks and at least
|
|
345
|
+
* one successful check, a success message is displayed, including the number
|
|
346
|
+
* of checks and test cases. Otherwise, a failure message is shown, detailing
|
|
347
|
+
* the number of successful and failed checks, as well as the total number of
|
|
348
|
+
* test cases. The output is immediately flushed to ensure prompt and
|
|
349
|
+
* organised reporting across all test cases and folders.
|
|
350
|
+
*/
|
|
351
|
+
void
|
|
352
|
+
reporter_human::end_suite (suite& suite)
|
|
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__, suite.name ());
|
|
363
|
+
#if defined(__GNUC__)
|
|
364
|
+
#pragma GCC diagnostic pop
|
|
365
|
+
#endif
|
|
366
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
367
|
+
|
|
368
|
+
#if defined(__GNUC__)
|
|
369
|
+
#pragma GCC diagnostic push
|
|
370
|
+
#if defined(__clang__)
|
|
371
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
372
|
+
#endif
|
|
373
|
+
#endif
|
|
374
|
+
|
|
375
|
+
uint32_t milliseconds = 0;
|
|
376
|
+
uint32_t microseconds = 0;
|
|
377
|
+
if (suite.timings ().has_timestamps ())
|
|
378
|
+
{
|
|
379
|
+
suite.timings ().compute_elapsed_time (milliseconds, microseconds);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
char message_time[120] = "";
|
|
383
|
+
if (milliseconds > 0 || microseconds > 0)
|
|
384
|
+
{
|
|
385
|
+
snprintf (message_time, sizeof (message_time),
|
|
386
|
+
", time: %" PRIu32 ".%03" PRIu32 " ms", milliseconds,
|
|
387
|
+
microseconds);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// At this point, the buffer may contain output from the test case, which
|
|
391
|
+
// should be displayed.
|
|
392
|
+
if (verbosity_ == verbosity::normal || verbosity_ == verbosity::verbose)
|
|
393
|
+
{
|
|
394
|
+
std::string indent (indent_size, ' ');
|
|
395
|
+
|
|
396
|
+
if (suite.totals ().executed_subtests () > 0)
|
|
397
|
+
{
|
|
398
|
+
printf ("\n");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (suite.totals ().was_successful ()) [[likely]]
|
|
402
|
+
{
|
|
403
|
+
// Successful test suite.
|
|
404
|
+
|
|
405
|
+
char message_totals[300];
|
|
406
|
+
snprintf (message_totals, sizeof (message_totals),
|
|
407
|
+
"(%zu check%s in %zu test case%s)",
|
|
408
|
+
suite.totals ().successful_checks (),
|
|
409
|
+
suite.totals ().successful_checks () == 1 ? "" : "s",
|
|
410
|
+
suite.totals ().executed_subtests (),
|
|
411
|
+
suite.totals ().executed_subtests () == 1 ? "" : "s");
|
|
412
|
+
|
|
413
|
+
if (output_file_ != nullptr)
|
|
414
|
+
{
|
|
415
|
+
write_buffer_to_file_ ();
|
|
416
|
+
|
|
417
|
+
fprintf (output_file_, "✓ %s - passed %s%s\n", suite.name (),
|
|
418
|
+
message_totals, message_time);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (verbosity_ == verbosity::verbose)
|
|
422
|
+
{
|
|
423
|
+
// With verbosity, show full TAP output accumulated in the
|
|
424
|
+
// buffer.
|
|
425
|
+
write_buffer_to_stdout ();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
printf ("%s✓%s %s - passed %s%s\n", colours_.pass, colours_.none,
|
|
429
|
+
suite.name (), message_totals, message_time);
|
|
430
|
+
}
|
|
431
|
+
else
|
|
432
|
+
{
|
|
433
|
+
// Failed test suite.
|
|
434
|
+
|
|
435
|
+
char message_totals[300];
|
|
436
|
+
snprintf (message_totals, sizeof (message_totals),
|
|
437
|
+
"(%zu check%s passed, %zu "
|
|
438
|
+
"failed, in %zu test case%s)",
|
|
439
|
+
suite.totals ().successful_checks (),
|
|
440
|
+
suite.totals ().successful_checks () == 1 ? "" : "s",
|
|
441
|
+
suite.totals ().failed_checks (),
|
|
442
|
+
suite.totals ().executed_subtests (),
|
|
443
|
+
suite.totals ().executed_subtests () == 1 ? "" : "s");
|
|
444
|
+
|
|
445
|
+
if (output_file_ != nullptr)
|
|
446
|
+
{
|
|
447
|
+
write_buffer_to_file_ ();
|
|
448
|
+
|
|
449
|
+
fprintf (output_file_, "✗ %s - FAILED %s%s\n", suite.name (),
|
|
450
|
+
message_totals, message_time);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Show full TAP output accumulated in the buffer for failed suite
|
|
454
|
+
// cases, as it may contain useful information about the failure.
|
|
455
|
+
write_buffer_to_stdout ();
|
|
456
|
+
|
|
457
|
+
printf ("%s✗%s %s - %sFAILED%s %s%s\n", colours_.fail,
|
|
458
|
+
colours_.none, suite.name (), colours_.fail, colours_.none,
|
|
459
|
+
message_totals, message_time);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
flush ();
|
|
464
|
+
|
|
465
|
+
// Clear residual content when less verbose.
|
|
466
|
+
buffer_.clear ();
|
|
467
|
+
|
|
468
|
+
add_empty_line_ = true;
|
|
469
|
+
|
|
470
|
+
#if defined(__GNUC__)
|
|
471
|
+
#pragma GCC diagnostic pop
|
|
472
|
+
#endif
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// --------------------------------------------------------------------------
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* @details
|
|
479
|
+
* This method marks the beginning of a test case, setting the internal state
|
|
480
|
+
* to indicate that test output is now within a test case context. If there
|
|
481
|
+
* is pending output and the verbosity level is set to verbose, it ensures
|
|
482
|
+
* that output is properly separated and displayed, adding an empty line if
|
|
483
|
+
* necessary. The output buffer is cleared and the stream is flushed to
|
|
484
|
+
* guarantee that all previous output is visible before the new test case
|
|
485
|
+
* begins. This approach enhances the clarity and organisation of test
|
|
486
|
+
* results across all test cases and folders.
|
|
487
|
+
*/
|
|
488
|
+
void
|
|
489
|
+
reporter_human::begin_subtest (subtest& subtest)
|
|
490
|
+
{
|
|
491
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
492
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
493
|
+
#if defined(__GNUC__)
|
|
494
|
+
#pragma GCC diagnostic push
|
|
495
|
+
#if defined(__clang__)
|
|
496
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
497
|
+
#endif
|
|
498
|
+
#endif
|
|
499
|
+
trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, subtest.name ());
|
|
500
|
+
#if defined(__GNUC__)
|
|
501
|
+
#pragma GCC diagnostic pop
|
|
502
|
+
#endif
|
|
503
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
504
|
+
|
|
505
|
+
#if defined(__GNUC__)
|
|
506
|
+
#pragma GCC diagnostic push
|
|
507
|
+
#if defined(__clang__)
|
|
508
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
509
|
+
#endif
|
|
510
|
+
#endif
|
|
511
|
+
|
|
512
|
+
if (!buffer_.empty ())
|
|
513
|
+
{
|
|
514
|
+
// Each suite should start with an empty buffer.
|
|
515
|
+
fprintf (stderr,
|
|
516
|
+
"Buffer not empty at the beginning of a test case:\n%s\n",
|
|
517
|
+
buffer_.c_str ());
|
|
518
|
+
flush ();
|
|
519
|
+
abort ();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
std::string indent (indent_size * subtest.nesting_depth (), ' ');
|
|
523
|
+
|
|
524
|
+
if (output_file_ != nullptr)
|
|
525
|
+
{
|
|
526
|
+
fprintf (output_file_, "%s• %s\n", indent.c_str (), subtest.name ());
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (verbosity_ == verbosity::verbose)
|
|
530
|
+
{
|
|
531
|
+
if (add_empty_line_)
|
|
532
|
+
{
|
|
533
|
+
printf ("\n");
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
printf ("%s• %s\n", indent.c_str (), subtest.name ());
|
|
537
|
+
|
|
538
|
+
add_empty_line_ = false;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
flush ();
|
|
542
|
+
|
|
543
|
+
#if defined(__GNUC__)
|
|
544
|
+
#pragma GCC diagnostic pop
|
|
545
|
+
#endif
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* @details
|
|
550
|
+
* This method marks the end of a test case, summarising its outcome and
|
|
551
|
+
* outputting the results with appropriate formatting and colour coding. If
|
|
552
|
+
* any checks have failed, a failure message is displayed, including the
|
|
553
|
+
* number of successful and failed checks. For passing test cases, a success
|
|
554
|
+
* message is shown with the total number of checks. The output is adjusted
|
|
555
|
+
* according to the verbosity level, and additional spacing is managed for
|
|
556
|
+
* clarity. The output buffer is cleared and the stream is flushed to ensure
|
|
557
|
+
* all results are immediately visible, supporting clear and organised
|
|
558
|
+
* reporting across all test cases and folders.
|
|
559
|
+
*/
|
|
560
|
+
void
|
|
561
|
+
reporter_human::end_subtest (subtest& subtest)
|
|
562
|
+
{
|
|
563
|
+
#if defined(MICRO_OS_PLUS_TRACE) \
|
|
564
|
+
&& defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
|
|
565
|
+
#if defined(__GNUC__)
|
|
566
|
+
#pragma GCC diagnostic push
|
|
567
|
+
#if defined(__clang__)
|
|
568
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
569
|
+
#endif
|
|
570
|
+
#endif
|
|
571
|
+
trace::printf ("%s '%s' i%zu\n", __PRETTY_FUNCTION__, subtest.name (),
|
|
572
|
+
subtest.nesting_depth ());
|
|
573
|
+
#if defined(__GNUC__)
|
|
574
|
+
#pragma GCC diagnostic pop
|
|
575
|
+
#endif
|
|
576
|
+
#endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
|
|
577
|
+
|
|
578
|
+
#if defined(__GNUC__)
|
|
579
|
+
#pragma GCC diagnostic push
|
|
580
|
+
#if defined(__clang__)
|
|
581
|
+
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
|
|
582
|
+
#endif
|
|
583
|
+
#endif
|
|
584
|
+
|
|
585
|
+
// At this point, the buffer may contain output from the subtest, which
|
|
586
|
+
// should be displayed.
|
|
587
|
+
if (verbosity_ == verbosity::normal || verbosity_ == verbosity::verbose)
|
|
588
|
+
{
|
|
589
|
+
std::string indent (indent_size * subtest.nesting_depth (), ' ');
|
|
590
|
+
std::string indent2 (indent_size * (subtest.nesting_depth () + 1),
|
|
591
|
+
' ');
|
|
592
|
+
|
|
593
|
+
if (add_empty_line_)
|
|
594
|
+
{
|
|
595
|
+
printf ("\n");
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
if (subtest.totals ().was_successful ()) [[likely]]
|
|
599
|
+
{
|
|
600
|
+
// Successful subtest.
|
|
601
|
+
|
|
602
|
+
char message_totals[300];
|
|
603
|
+
snprintf (message_totals, sizeof (message_totals),
|
|
604
|
+
"%s - passed (%zu check%s)", subtest.name (),
|
|
605
|
+
subtest.totals ().successful_checks (),
|
|
606
|
+
subtest.totals ().successful_checks () == 1 ? "" : "s");
|
|
607
|
+
|
|
608
|
+
if (output_file_ != nullptr)
|
|
609
|
+
{
|
|
610
|
+
write_buffer_to_file_ ();
|
|
611
|
+
|
|
612
|
+
fprintf (output_file_, "%s✓ %s\n", indent.c_str (),
|
|
613
|
+
message_totals);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (verbosity_ == verbosity::verbose)
|
|
617
|
+
{
|
|
618
|
+
// With verbosity, show full TAP output accumulated in the
|
|
619
|
+
// buffer.
|
|
620
|
+
write_buffer_to_stdout ();
|
|
621
|
+
|
|
622
|
+
printf ("%s%s✓%s %s\n", indent.c_str (), colours_.pass,
|
|
623
|
+
colours_.none, message_totals);
|
|
624
|
+
|
|
625
|
+
add_empty_line_ = true;
|
|
626
|
+
}
|
|
627
|
+
else
|
|
628
|
+
{
|
|
629
|
+
printf ("%s%s✓%s %s\n", indent.c_str (), colours_.pass,
|
|
630
|
+
colours_.none, message_totals);
|
|
631
|
+
|
|
632
|
+
add_empty_line_ = false;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
else
|
|
636
|
+
{
|
|
637
|
+
// Failed subtest.
|
|
638
|
+
char message_totals[300];
|
|
639
|
+
snprintf (message_totals, sizeof (message_totals),
|
|
640
|
+
"(%zu check%s passed, %zu failed)",
|
|
641
|
+
subtest.totals ().successful_checks (),
|
|
642
|
+
subtest.totals ().successful_checks () == 1 ? "" : "s",
|
|
643
|
+
subtest.totals ().failed_checks ());
|
|
644
|
+
|
|
645
|
+
if (output_file_ != nullptr)
|
|
646
|
+
{
|
|
647
|
+
write_buffer_to_file_ ();
|
|
648
|
+
|
|
649
|
+
fprintf (output_file_, "%s✗ %s - %sFAILED%s %s\n",
|
|
650
|
+
indent.c_str (), subtest.name (), colours_.fail,
|
|
651
|
+
colours_.none, message_totals);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (verbosity_ == verbosity::normal)
|
|
655
|
+
{
|
|
656
|
+
if (!add_empty_line_)
|
|
657
|
+
{
|
|
658
|
+
printf ("\n");
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
printf ("%s• %s\n", indent.c_str (), subtest.name ());
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Show full output accumulated in the buffer for failed
|
|
665
|
+
// subtests, as it may contain useful information about the
|
|
666
|
+
// failure.
|
|
667
|
+
write_buffer_to_stdout ();
|
|
668
|
+
|
|
669
|
+
printf ("%s%s✗%s %s - %sFAILED%s %s\n", indent.c_str (),
|
|
670
|
+
colours_.fail, colours_.none, subtest.name (),
|
|
671
|
+
colours_.fail, colours_.none, message_totals);
|
|
672
|
+
|
|
673
|
+
add_empty_line_ = true;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
flush ();
|
|
678
|
+
|
|
679
|
+
// Clear residual content when less verbose.
|
|
680
|
+
buffer_.clear ();
|
|
681
|
+
|
|
682
|
+
#if defined(__GNUC__)
|
|
683
|
+
#pragma GCC diagnostic pop
|
|
684
|
+
#endif
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// --------------------------------------------------------------------------
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* @details
|
|
691
|
+
* Returns an empty string. The human reporter does not prefix comment
|
|
692
|
+
* lines; the `write_info_()` output appears as plain text.
|
|
693
|
+
*/
|
|
694
|
+
const char*
|
|
695
|
+
reporter_human::get_comment_prefix (void)
|
|
696
|
+
{
|
|
697
|
+
return "";
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* @details
|
|
702
|
+
* This method outputs the prefix for a passing check result, applying the
|
|
703
|
+
* appropriate colour formatting and symbols to clearly indicate success. If
|
|
704
|
+
* the output occurs within a subtest, additional indentation is applied
|
|
705
|
+
* for readability. The prefix includes a tick symbol (`✓`) and, if provided,
|
|
706
|
+
* an associated message. Colour formatting is reset after the prefix to
|
|
707
|
+
* maintain consistent output style across all test cases and folders.
|
|
708
|
+
*
|
|
709
|
+
* The prefix/suffix methods help shorten the code
|
|
710
|
+
* generated by the template methods.
|
|
711
|
+
*/
|
|
712
|
+
void
|
|
713
|
+
reporter_human::output_pass_prefix_ (std::string& message, subtest& subtest)
|
|
714
|
+
{
|
|
715
|
+
size_t level = subtest.nesting_depth ();
|
|
716
|
+
|
|
717
|
+
*this << indent (level + 1);
|
|
718
|
+
*this << colours_.pass << "✓" << colours_.none << " ";
|
|
719
|
+
if (!message.empty ())
|
|
720
|
+
{
|
|
721
|
+
*this << message.c_str ();
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* @details
|
|
727
|
+
* Completes pass output by appending `endl` and flushing buffered
|
|
728
|
+
* content to the configured sinks.
|
|
729
|
+
|
|
730
|
+
* The prefix/suffix methods help shorten the code
|
|
731
|
+
* generated by the template methods.
|
|
732
|
+
*/
|
|
733
|
+
void
|
|
734
|
+
reporter_human::output_pass_suffix_ ([[maybe_unused]] subtest& subtest)
|
|
735
|
+
{
|
|
736
|
+
*this << endl;
|
|
737
|
+
|
|
738
|
+
flush ();
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* @details
|
|
743
|
+
* This method outputs the prefix for a failing check result, applying the
|
|
744
|
+
* appropriate colour formatting and symbols to clearly indicate failure. If
|
|
745
|
+
* the output occurs within a subtest, additional indentation is applied
|
|
746
|
+
* for readability. The prefix includes a cross symbol (`✗`), an optional
|
|
747
|
+
* message, and the label "FAILED". The source location is appended in
|
|
748
|
+
* parentheses, showing the file or folder name and line number where the
|
|
749
|
+
* failure occurred. Colour formatting is reset after the prefix to maintain
|
|
750
|
+
* consistent output style across all test cases and folders.
|
|
751
|
+
*/
|
|
752
|
+
void
|
|
753
|
+
reporter_human::output_fail_prefix_ (
|
|
754
|
+
std::string& message, const bool has_expression,
|
|
755
|
+
const reflection::source_location& location, subtest& subtest)
|
|
756
|
+
{
|
|
757
|
+
#if defined(__GNUC__)
|
|
758
|
+
#pragma GCC diagnostic push
|
|
759
|
+
#if defined(__clang__)
|
|
760
|
+
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
761
|
+
#elif defined(__GNUC__)
|
|
762
|
+
#pragma GCC diagnostic ignored "-Wnarrowing"
|
|
763
|
+
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
|
764
|
+
#endif
|
|
765
|
+
#endif
|
|
766
|
+
|
|
767
|
+
size_t level = subtest.nesting_depth ();
|
|
768
|
+
|
|
769
|
+
*this << indent (level + 1);
|
|
770
|
+
*this << colours_.fail << "✗" << colours_.none << " ";
|
|
771
|
+
if (!message.empty ())
|
|
772
|
+
{
|
|
773
|
+
*this << message.c_str ();
|
|
774
|
+
*this << " ";
|
|
775
|
+
}
|
|
776
|
+
*this << colours_.fail << "FAILED" << colours_.none;
|
|
777
|
+
*this << " (" << reflection::short_name (location.file_name ()) << ":"
|
|
778
|
+
<< location.line ();
|
|
779
|
+
if (has_expression)
|
|
780
|
+
{
|
|
781
|
+
*this << ", ";
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
#if defined(__GNUC__)
|
|
785
|
+
#pragma GCC diagnostic pop
|
|
786
|
+
#endif
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* @details
|
|
791
|
+
* This method outputs the suffix for a failing check result by closing the
|
|
792
|
+
* location information, appending an "aborted..." message if the check was
|
|
793
|
+
* aborted, and then adding a newline to the output. The output stream
|
|
794
|
+
* is flushed to ensure immediate visibility. This approach guarantees that
|
|
795
|
+
* failure results are clearly separated, promptly reported, and easily
|
|
796
|
+
* distinguishable across all test cases and folders.
|
|
797
|
+
*/
|
|
798
|
+
void
|
|
799
|
+
reporter_human::output_fail_suffix_ (
|
|
800
|
+
[[maybe_unused]] const reflection::source_location& location, bool abort,
|
|
801
|
+
[[maybe_unused]] subtest& subtest)
|
|
802
|
+
{
|
|
803
|
+
*this << ")";
|
|
804
|
+
if (abort)
|
|
805
|
+
{
|
|
806
|
+
*this << " aborted...";
|
|
807
|
+
}
|
|
808
|
+
*this << endl;
|
|
809
|
+
|
|
810
|
+
flush ();
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// --------------------------------------------------------------------------
|
|
814
|
+
} // namespace micro_os_plus::micro_test_plus
|
|
815
|
+
|
|
816
|
+
// ----------------------------------------------------------------------------
|