Skip to main content

reporter.cpp File

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

Included Headers

#include <micro-os-plus/diag/trace.h> #include "micro-os-plus/micro-test-plus/reporter.h"

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 210 of file reporter.cpp.

210 endl (reporter& stream)
211 {
212 stream.endline ();
213 return stream;
214 }

Reference micro_os_plus::micro_test_plus::reporter::endline.

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#include <micro-os-plus/diag/trace.h>
56
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
73{
74 // --------------------------------------------------------------------------
75
85 reporter::reporter (std::unique_ptr<std::vector<std::string_view>> argvs)
86 {
87#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
88 trace::printf ("%s\n", __PRETTY_FUNCTION__);
89#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
90
91 std::string_view output_file_sv{};
92
93 argvs_ = std::move (argvs);
94
95 static constexpr std::string_view output_file_prefix{ "--output-file=" };
96 if (argvs_)
97 {
98 const auto& args = *argvs_;
99 for (size_t i = 0; i < args.size (); ++i)
100 {
101 if (args[i] == "--verbose")
102 {
104 }
105 else if (args[i] == "--quiet")
106 {
108 }
109 else if (args[i] == "--silent")
110 {
112 }
113 else if (args[i].starts_with (output_file_prefix))
114 {
115 output_file_sv = args[i].substr (output_file_prefix.size ());
116 }
117 else if (args[i]
118 == output_file_prefix.substr (
119 0, output_file_prefix.size () - 1))
120 {
121 if (i + 1 < args.size ())
122 {
123 output_file_sv = args[++i];
124 }
125 else
126 {
127 fprintf (stderr, "error: --output-file option requires a "
128 "file path argument\n");
129 exit (1);
130 }
131 }
132 }
133 }
134
135 if (!output_file_sv.empty ())
136 {
137 // .data() is safe: all string_views are views into argv[]
138 // entries, which are null-terminated C strings.
139 output_file_ = fopen (output_file_sv.data (), "w");
140 if (output_file_ == nullptr)
141 {
142#if defined(__GNUC__)
143#pragma GCC diagnostic push
144#if defined(__clang__)
145#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
146#endif
147#endif
148 fprintf (stderr, "error: Failed to open output file '%.*s'\n",
149 static_cast<int> (output_file_sv.size ()),
150 output_file_sv.data ());
151#if defined(__GNUC__)
152#pragma GCC diagnostic pop
153#endif
154 exit (1);
155 }
156 // The original string is zero terminated, so we can safely use .data()
157 // here.
158 output_file_path_ = output_file_sv.data ();
159 }
160
161 // Pre-allocate buffer to reduce dynamic allocations.
162 buffer_.reserve (128);
163 }
164
173 {
174#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
175 trace::printf ("%s\n", __PRETTY_FUNCTION__);
176#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
177
178 if (output_file_ != nullptr)
179 {
180 fflush (output_file_);
181 fclose (output_file_);
182
183#if defined(__GNUC__)
184#pragma GCC diagnostic push
185#if defined(__clang__)
186#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
187#endif
188#endif
189 printf ("Test output written to '%s'.\n", output_file_path_);
190#if defined(__GNUC__)
191#pragma GCC diagnostic pop
192#endif
193
194 output_file_ = nullptr;
195 output_file_path_ = nullptr;
196 }
197 }
198
199 // --------------------------------------------------------------------------
200
210 endl (reporter& stream)
211 {
212 stream.endline ();
213 return stream;
214 }
215
224 void
226 {
227 buffer_.append ("\n");
228 flush ();
229 }
230
240 void
242 {
243 // Pass only the string, do not add an `\n` here.
244 printf ("%s", buffer_.c_str ());
245 }
246
253 void
255 {
256 // Pass only the string, do not add an `\n` here.
257 if (output_file_ != nullptr)
258 {
259 fprintf (output_file_, "%s", buffer_.c_str ());
260 }
261 }
262
273 void
275 {
276 if (argvs_ && !argvs_->empty ())
277 {
278 const auto& args = *argvs_;
279 std::string line;
280 line.reserve (256);
281 line.append (get_comment_prefix ());
282 line.append ("Running: ");
283
284 // Append only the file name part of argv[0].
285 const std::string_view arg0 = args[0];
286 const auto sep = arg0.rfind ('/');
287 line.append ((sep != std::string_view::npos) ? arg0.substr (sep + 1)
288 : arg0);
289
290 for (size_t i = 1; i < args.size (); ++i)
291 {
292 line.append (" ");
293 line.append (args[i]);
294 }
295 line.append ("\n");
296
297 if (output_file_ != nullptr)
298 fprintf (output_file_, "%s", line.c_str ());
299
300#if !(defined(MICRO_OS_PLUS_INCLUDE_STARTUP) \
301 && defined(MICRO_OS_PLUS_DIAG_TRACE_ENABLED))
304 printf ("%s", line.c_str ());
305#endif // !defined(MICRO_OS_PLUS_INCLUDE_STARTUP)
306 }
307
308 {
309 // Build the "Built with ..." line. For the output file the compiler
310 // version is omitted; for stdout it is appended via __VERSION__.
311 std::string line;
312 line.reserve (256);
313 line.append (get_comment_prefix ());
314 line.append ("Built with ");
315#if defined(__clang__)
316 line.append ("clang " __VERSION__);
317#elif defined(__GNUC__)
318 line.append ("GCC " __VERSION__);
319#elif defined(_MSC_VER)
320 line.append ("MSVC");
321 char msvc_ver[16];
322 snprintf (msvc_ver, sizeof (msvc_ver), " - %d", _MSC_VER);
323 line.append (msvc_ver);
324#else
325 line.append ("an unknown compiler");
326#endif
327#if !(defined(__APPLE__) || defined(__linux__) || defined(__unix__) \
328 || defined(WIN32))
329 // This is relevant only on bare-metal.
330#if defined(__ARM_PCS_VFP) || defined(__ARM_FP)
331 line.append (", with FP");
332#else
333 line.append (", no FP");
334#endif
335#endif
336#if defined(__EXCEPTIONS)
337 line.append (", with exceptions");
338#else
339 line.append (", no exceptions");
340#endif
341#if defined(MICRO_OS_PLUS_DEBUG)
342 line.append (", with MICRO_OS_PLUS_DEBUG");
343#endif
344#if defined(MICRO_OS_PLUS_DIAG_TRACE_ENABLED)
345 line.append (", with MICRO_OS_PLUS_DIAG_TRACE_ENABLED");
346#endif
347
348 if (output_file_ != nullptr)
349 {
350 fprintf (output_file_, "%s\n", line.c_str ());
351 }
352
353#if !(defined(MICRO_OS_PLUS_INCLUDE_STARTUP) \
354 && defined(MICRO_OS_PLUS_DIAG_TRACE_ENABLED))
356 {
357 printf ("%s\n", line.c_str ());
358 }
359#endif // !defined(MICRO_OS_PLUS_INCLUDE_STARTUP)
360 }
361 }
362
370 void
372 {
373 fflush (stdout);
374 if (output_file_ != nullptr)
375 {
376 fflush (output_file_);
377 }
378 }
379
380 // --------------------------------------------------------------------------
381
393 {
394 // Call the endl function.
395 (*func) (*this);
396 return *this;
397 }
398
408 reporter::operator<<(std::string_view sv)
409 {
410 buffer_.append (sv);
411 return *this;
412 }
413
423 {
424 buffer_.append (1, c);
425 return *this;
426 }
427
437 reporter::operator<<(const char* s)
438 {
439 buffer_.append (s);
440 return *this;
441 }
442
449 void
450 reporter::pass (std::string& message, const std::string& expression,
452 {
454
455 if (message.empty ())
456 {
457 *this << expression;
458 }
459
461 }
462
468 void
469 reporter::fail (bool abort, std::string& message,
470 const std::string& expression, bool has_expression,
471 const reflection::source_location& location,
473 {
474 output_fail_prefix_ (message, has_expression, location, subtest);
475
476 if (has_expression)
477 {
478 *this << expression;
479 }
480
481 output_fail_suffix_ (location, abort, subtest);
482 }
483
484 // --------------------------------------------------------------------------
485} // namespace micro_os_plus::micro_test_plus
486
487// ----------------------------------------------------------------------------

Generated via doxygen2docusaurus 2.2.1 by Doxygen 1.17.0.