Skip to main content

reporter.cpp File

C++ source file with implementations for the µTest++ test reporter methods. More...

Included Headers

Namespaces Index

namespacemicro_os_plus

The primary namespace for the µOS++ framework. More...

namespacemicro_test_plus

Primary namespace for the µTest++ testing framework. More...

Functions Index

reporter &endl (reporter &stream)

Output stream manipulator for ending a line in test reports. More...

Description

C++ source file with implementations for the µTest++ test reporter methods.

This source file contains the core implementations for the test reporting facilities of the µTest++ framework. It provides lifecycle and utility behaviour for reporters, including command-line option parsing, output-file handling, informational banner emission, buffering helpers, stream operators, and pass/fail dispatch to reporter-specific prefix/ suffix hooks.

Concrete formatting behaviour is implemented by derived reporters (reporter_human and reporter_tap).

All definitions reside within the micro_os_plus::micro_test_plus namespace, ensuring clear separation from user code and minimising the risk of naming conflicts.

This file must be included when building the µTest++ library.

Functions

endl()

reporter & micro_os_plus::micro_test_plus::endl (reporter & stream)

Output stream manipulator for ending a line in test reports.

Parameters
stream

Reference to the reporter instance.

Returns

Reference to the same reporter instance, enabling chaining of output operations.

The endl function inserts a newline character into the specified reporter stream and flushes its output buffer. This operation ensures that each test output line is clearly separated and immediately visible, facilitating the readability and clarity of test results across all test cases and folders within the µTest++ framework.

Definition at line 214 of file reporter.cpp.

214 endl (reporter& stream)
215 {
216 stream.endline ();
217 return stream;
218 }

Referenced by micro_os_plus::micro_test_plus::reporter_tap::output_fail_prefix_, micro_os_plus::micro_test_plus::reporter_human::output_fail_suffix_, micro_os_plus::micro_test_plus::reporter_tap::output_fail_suffix_, micro_os_plus::micro_test_plus::reporter_human::output_pass_suffix_ and micro_os_plus::micro_test_plus::reporter_tap::output_pass_suffix_.

File Listing

The file content with the documentation metadata removed is:

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 Software License,
13 * which can be obtained from https://www.boost.org/LICENSE_1_0.txt.
14 */
15
16// ----------------------------------------------------------------------------
17
40
41// ----------------------------------------------------------------------------
42
43#if __has_include(<micro-os-plus/project-config.h>)
44#include <micro-os-plus/project-config.h>
45#elif __has_include(<micro-os-plus/config.h>)
46#pragma message \
47 "micro-os-plus/config.h is deprecated, rename to micro-os-plus/project-config.h and include it instead of micro-os-plus/config.h"
48#include <micro-os-plus/config.h>
49#endif // __has_include(<micro-os-plus/project-config.h>)
50
51#if __has_include(<micro-os-plus/micro-test-plus-defines.h>)
52#include <micro-os-plus/micro-test-plus-defines.h>
53#endif // __has_include(<micro-os-plus/micro-test-plus-defines.h>)
54
55#if defined(MICRO_OS_PLUS_TRACE)
56#include <micro-os-plus/diag/trace.h>
57#endif // MICRO_OS_PLUS_TRACE
58
60
61// ----------------------------------------------------------------------------
62
63#if defined(__GNUC__)
64#pragma GCC diagnostic ignored "-Waggregate-return"
65#if defined(__clang__)
66#pragma clang diagnostic ignored "-Wunknown-warning-option"
67#pragma clang diagnostic ignored "-Wc++98-compat"
68#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
69#endif
70#endif
71
72// =============================================================================
73
75{
76 // --------------------------------------------------------------------------
77
87 reporter::reporter (std::unique_ptr<std::vector<std::string_view>> argvs)
88 {
89#if defined(MICRO_OS_PLUS_TRACE) \
90 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
91 trace::printf ("%s\n", __PRETTY_FUNCTION__);
92#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
93
94 std::string_view output_file_sv{};
95
96 argvs_ = std::move (argvs);
97
98 static constexpr std::string_view output_file_prefix{ "--output-file=" };
99 if (argvs_)
100 {
101 const auto& args = *argvs_;
102 for (size_t i = 0; i < args.size (); ++i)
103 {
104 if (args[i] == "--verbose")
105 {
107 }
108 else if (args[i] == "--quiet")
109 {
111 }
112 else if (args[i] == "--silent")
113 {
115 }
116 else if (args[i].starts_with (output_file_prefix))
117 {
118 output_file_sv = args[i].substr (output_file_prefix.size ());
119 }
120 else if (args[i]
121 == output_file_prefix.substr (
122 0, output_file_prefix.size () - 1))
123 {
124 if (i + 1 < args.size ())
125 {
126 output_file_sv = args[++i];
127 }
128 else
129 {
130 fprintf (stderr, "error: --output-file option requires a "
131 "file path argument\n");
132 exit (1);
133 }
134 }
135 }
136 }
137
138 if (!output_file_sv.empty ())
139 {
140 // .data() is safe: all string_views are views into argv[]
141 // entries, which are null-terminated C strings.
142 output_file_ = fopen (output_file_sv.data (), "w");
143 if (output_file_ == nullptr)
144 {
145#if defined(__GNUC__)
146#pragma GCC diagnostic push
147#if defined(__clang__)
148#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
149#endif
150#endif
151 fprintf (stderr, "error: Failed to open output file '%.*s'\n",
152 static_cast<int> (output_file_sv.size ()),
153 output_file_sv.data ());
154#if defined(__GNUC__)
155#pragma GCC diagnostic pop
156#endif
157 exit (1);
158 }
159 // The original string is zero terminated, so we can safely use .data()
160 // here.
161 output_file_path_ = output_file_sv.data ();
162 }
163
164 // Pre-allocate buffer to reduce dynamic allocations.
165 buffer_.reserve (128);
166 }
167
176 {
177#if defined(MICRO_OS_PLUS_TRACE) \
178 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
179 trace::printf ("%s\n", __PRETTY_FUNCTION__);
180#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
181
182 if (output_file_ != nullptr)
183 {
184 fflush (output_file_);
185 fclose (output_file_);
186
187#if defined(__GNUC__)
188#pragma GCC diagnostic push
189#if defined(__clang__)
190#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
191#endif
192#endif
193 printf ("Test output written to '%s'.\n", output_file_path_);
194#if defined(__GNUC__)
195#pragma GCC diagnostic pop
196#endif
197
198 output_file_ = nullptr;
199 output_file_path_ = nullptr;
200 }
201 }
202
203 // --------------------------------------------------------------------------
204
214 endl (reporter& stream)
215 {
216 stream.endline ();
217 return stream;
218 }
219
228 void
230 {
231 buffer_.append ("\n");
232 flush ();
233 }
234
244 void
246 {
247 // Pass only the string, do not add an `\n` here.
248 printf ("%s", buffer_.c_str ());
249 }
250
257 void
259 {
260 // Pass only the string, do not add an `\n` here.
261 if (output_file_ != nullptr)
262 {
263 fprintf (output_file_, "%s", buffer_.c_str ());
264 }
265 }
266
277 void
279 {
280 if (argvs_ && !argvs_->empty ())
281 {
282 const auto& args = *argvs_;
283 std::string line;
284 line.reserve (256);
285 line.append (get_comment_prefix ());
286 line.append ("Running: ");
287
288 // Append only the file name part of argv[0].
289 const std::string_view arg0 = args[0];
290 const auto sep = arg0.rfind ('/');
291 line.append ((sep != std::string_view::npos) ? arg0.substr (sep + 1)
292 : arg0);
293
294 for (size_t i = 1; i < args.size (); ++i)
295 {
296 line.append (" ");
297 line.append (args[i]);
298 }
299 line.append ("\n");
300
301 if (output_file_ != nullptr)
302 fprintf (output_file_, "%s", line.c_str ());
303
304#if !(defined(MICRO_OS_PLUS_INCLUDE_STARTUP) && defined(MICRO_OS_PLUS_TRACE))
307 printf ("%s", line.c_str ());
308#endif // !defined(MICRO_OS_PLUS_INCLUDE_STARTUP)
309 }
310
311 {
312 // Build the "Built with ..." line. For the output file the compiler
313 // version is omitted; for stdout it is appended via __VERSION__.
314 std::string line;
315 line.reserve (256);
316 line.append (get_comment_prefix ());
317 line.append ("Built with ");
318#if defined(__clang__)
319 line.append ("clang " __VERSION__);
320#elif defined(__GNUC__)
321 line.append ("GCC " __VERSION__);
322#elif defined(_MSC_VER)
323 line.append ("MSVC");
324 char msvc_ver[16];
325 snprintf (msvc_ver, sizeof (msvc_ver), " - %d", _MSC_VER);
326 line.append (msvc_ver);
327#else
328 line.append ("an unknown compiler");
329#endif
330#if !(defined(__APPLE__) || defined(__linux__) || defined(__unix__) \
331 || defined(WIN32))
332 // This is relevant only on bare-metal.
333#if defined(__ARM_PCS_VFP) || defined(__ARM_FP)
334 line.append (", with FP");
335#else
336 line.append (", no FP");
337#endif
338#endif
339#if defined(__EXCEPTIONS)
340 line.append (", with exceptions");
341#else
342 line.append (", no exceptions");
343#endif
344#if defined(MICRO_OS_PLUS_DEBUG)
345 line.append (", with MICRO_OS_PLUS_DEBUG");
346#endif
347#if defined(MICRO_OS_PLUS_TRACE)
348 line.append (", with MICRO_OS_PLUS_TRACE");
349#endif
350
351 if (output_file_ != nullptr)
352 {
353 fprintf (output_file_, "%s\n", line.c_str ());
354 }
355
356#if !(defined(MICRO_OS_PLUS_INCLUDE_STARTUP) && defined(MICRO_OS_PLUS_TRACE))
358 {
359 printf ("%s\n", line.c_str ());
360 }
361#endif // !defined(MICRO_OS_PLUS_INCLUDE_STARTUP)
362 }
363 }
364
372 void
374 {
375 fflush (stdout);
376 if (output_file_ != nullptr)
377 {
378 fflush (output_file_);
379 }
380 }
381
382 // --------------------------------------------------------------------------
383
395 {
396 // Call the endl function.
397 (*func) (*this);
398 return *this;
399 }
400
410 reporter::operator<<(std::string_view sv)
411 {
412 buffer_.append (sv);
413 return *this;
414 }
415
425 {
426 buffer_.append (1, c);
427 return *this;
428 }
429
439 reporter::operator<<(const char* s)
440 {
441 buffer_.append (s);
442 return *this;
443 }
444
451 void
452 reporter::pass (std::string& message, const std::string& expression,
454 {
456
457 if (message.empty ())
458 {
459 *this << expression;
460 }
461
463 }
464
470 void
471 reporter::fail (bool abort, std::string& message,
472 const std::string& expression, bool has_expression,
473 const reflection::source_location& location,
475 {
476 output_fail_prefix_ (message, has_expression, location, subtest);
477
478 if (has_expression)
479 {
480 *this << expression;
481 }
482
483 output_fail_suffix_ (location, abort, subtest);
484 }
485
486 // --------------------------------------------------------------------------
487} // namespace micro_os_plus::micro_test_plus
488
489// ----------------------------------------------------------------------------

Generated via doxygen2docusaurus 2.2.0 by Doxygen 1.17.0.