Skip to main content

reporter.cpp File

C++ source file with implementations for the µTest++ test reporter member functions. 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...

namespacedetail

Internal implementation details for the µTest++ framework. More...

namespaceanonymous{reporter.cpp}

Local helpers of the reporter base class. More...

Functions Index​

reporter &endl (reporter &stream)

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

voidformat_skipped (size_t count, char(&message)[fragment_size])

Formats the number of items skipped by the filter. More...

constexpr const char *plural (size_t count) noexcept

Returns the plural suffix for a count. More...

voidwrite_without_colours (FILE *file, std::string_view text)

Writes a text to a file, without the ANSI colour sequences. More...

Variables Index​

constexpr size_tfragment_size = 21 + (std::numeric_limits<size_t>::digits10 + 1)

Size of the array that receives a fragment of the totals. More...

Description​

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

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 output-file handling, informational banner emission, buffering helpers, stream operators, the formatting of the totals and of the elapsed times, and pass/fail dispatch to reporter-specific prefix/suffix hooks. The command-line options are parsed by runner_options.

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

All definitions reside within the micro_os_plus::micro_test_plus::detail namespace, since the reporters are internal to the framework.

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

Functions​

endl()​

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

Output stream manipulator for ending a line in test reports.

Calls reporter::end_line(), which appends a line ending to the internal buffer. Unlike std::endl, it does not flush; the buffer is written later, by the concrete reporters.

Parameters
stream

Reference to the reporter instance.

Returns

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

The endl function calls reporter::end_line(), which appends a newline character to the buffer of the specified reporter.

Definition at line 218 of file reporter.cpp.

218 endl (reporter& stream)
219 {
220 stream.end_line ();
221 return stream;
222 }

References micro_os_plus::micro_test_plus::detail::reporter::end_line and micro_os_plus::micro_test_plus::detail::endl.

Referenced by micro_os_plus::micro_test_plus::detail::endl, micro_os_plus::micro_test_plus::detail::reporter_human::fail_suite, micro_os_plus::micro_test_plus::detail::reporter_tap::fail_suite, micro_os_plus::micro_test_plus::detail::reporter_tap::output_fail_prefix, micro_os_plus::micro_test_plus::detail::reporter_human::output_fail_suffix, micro_os_plus::micro_test_plus::detail::reporter_tap::output_fail_suffix, micro_os_plus::micro_test_plus::detail::reporter_human::output_pass_suffix, micro_os_plus::micro_test_plus::detail::reporter_tap::output_pass_suffix and micro_os_plus::micro_test_plus::detail::reporter_tap::pass_without_text.

format_skipped()​

void micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::format_skipped (size_t count, char(&message)[fragment_size])

Formats the number of items skipped by the filter.

The text is ", <count> skipped", appended to the count of the items, or empty when no item was skipped, so that the totals lines of the runs without a filter are not longer.

Parameters
count

The number of skipped items.

message

The character array that receives the null-terminated text.

Returns

Nothing.

Definition at line 874 of file reporter.cpp.

874 format_skipped (size_t count, char (&message)[fragment_size])
875 {
876 if (count > 0)
877 {
878 snprintf (message, sizeof (message),
880 count);
881 }
882 else
883 {
884 message[0] = '\0';
885 }
886 }

References micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::format_skipped, micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::fragment_size and MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::format_skipped.

plural()​

const char * micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::plural (size_t count)
constexpr noexcept

Returns the plural suffix for a count.

The totals lines are in English, where only the count 1 takes the singular form.

Parameters
count

The count that precedes the noun.

Returns

"" for 1, and "s" otherwise.

Definition at line 854 of file reporter.cpp.

854 plural (size_t count) noexcept
855 {
856 return count == 1 ? "" : "s";
857 }

Reference micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::plural.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::plural.

write_without_colours()​

void micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::write_without_colours (FILE * file, std::string_view text)

Writes a text to a file, without the ANSI colour sequences.

The text may contain ANSI colour sequences, added when the console is a terminal, which must not reach the file. They are removed while writing: each ESC [, followed by any digits and semicolons, and terminated by m, is skipped, and the text between the sequences is written unchanged. Any other use of ESC is written as is. No line ending is appended.

Parameters
file

The file to write to; must not be null.

text

The text to write.

Returns

Nothing.

Definition at line 113 of file reporter.cpp.

113 write_without_colours (FILE* file, std::string_view text)
114 {
115 size_t start = 0;
116 size_t pos = text.find ('\033');
117 while (pos != std::string_view::npos)
118 {
119 // Parse `ESC [ <digits and semicolons> m`.
120 size_t end = pos + 1;
121 if (end < text.size () && text[end] == '[')
122 {
123 ++end;
124 while (end < text.size ()
125 && ((text[end] >= '0' && text[end] <= '9')
126 || text[end] == ';'))
127 {
128 ++end;
129 }
130 if (end < text.size () && text[end] == 'm')
131 {
132 // A colour sequence; write the preceding text and skip
133 // it.
134 const std::string_view chunk
135 = text.substr (start, pos - start);
136 fwrite (chunk.data (), 1, chunk.size (), file);
137 start = end + 1;
138 }
139 }
140 pos = text.find ('\033', pos + 1);
141 }
142
143 const std::string_view chunk = text.substr (start);
144 fwrite (chunk.data (), 1, chunk.size (), file);
145 }

Reference micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::write_without_colours.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::write_without_colours.

Variables​

fragment_size​

size_t micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::fragment_size = 21 + (std::numeric_limits<size_t>::digits10 + 1)
constexpr

Size of the array that receives a fragment of the totals.

Large enough for ", N test cases failed", the longest fragment (20 characters and the count), and the terminator, with the count of the largest size_t value (10 digits on 32-bit targets, 20 on 64-bit ones, as in ", 18446744073709551615 test cases failed").

Definition at line 840 of file reporter.cpp.

841 = 21 + (std::numeric_limits<size_t>::digits10 + 1);

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::format_skipped.

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
12// ----------------------------------------------------------------------------
13
37
38// ----------------------------------------------------------------------------
39
46
47#if __has_include("micro-os-plus/diag/trace.h")
48#include "micro-os-plus/diag/trace.h"
49#endif // __has_include("micro-os-plus/diag/trace.h")
50
51#include <cstdarg>
52// For the PRIu32 macro used in snprintf() formatting of uint32_t values.
53#include <cinttypes>
54#include <limits>
55
56// ----------------------------------------------------------------------------
57
58#if defined(__GNUC__)
59#pragma GCC diagnostic ignored "-Waggregate-return"
60#if defined(__clang__)
61#pragma clang diagnostic ignored "-Wunknown-warning-option"
62#pragma clang diagnostic ignored "-Wc++98-compat"
63#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
64#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
65#endif // defined(__clang__)
66#endif // defined(__GNUC__)
67
68// ============================================================================
69
70#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED)
71
72// ----------------------------------------------------------------------------
73
75{
76 // --------------------------------------------------------------------------
77
94 namespace
95 {
112 void
113 write_without_colours (FILE* file, std::string_view text)
114 {
115 size_t start = 0;
116 size_t pos = text.find ('\033');
117 while (pos != std::string_view::npos)
118 {
119 // Parse `ESC [ <digits and semicolons> m`.
120 size_t end = pos + 1;
121 if (end < text.size () && text[end] == '[')
122 {
123 ++end;
124 while (end < text.size ()
125 && ((text[end] >= '0' && text[end] <= '9')
126 || text[end] == ';'))
127 {
128 ++end;
129 }
130 if (end < text.size () && text[end] == 'm')
131 {
132 // A colour sequence; write the preceding text and skip
133 // it.
134 const std::string_view chunk
135 = text.substr (start, pos - start);
136 fwrite (chunk.data (), 1, chunk.size (), file);
137 start = end + 1;
138 }
139 }
140 pos = text.find ('\033', pos + 1);
141 }
142
143 const std::string_view chunk = text.substr (start);
144 fwrite (chunk.data (), 1, chunk.size (), file);
145 }
146 } // namespace
147
148 // --------------------------------------------------------------------------
149
163 : verbosity_{ opts.verbosity_level }
164 {
165#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
166 trace::printf ("%s\n", __PRETTY_FUNCTION__);
167#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
168
169 if (!opts.output_file_path.empty ())
170 {
171 output_file_ = fopen (opts.output_file_path.c_str (), "w");
172 if (output_file_ == nullptr)
173 {
174 fprintf (stderr, "error: failed to open output file '%s'\n",
175 opts.output_file_path.c_str ());
177 }
178 else
179 {
181 }
182 }
183
184 // Pre-allocate buffer to reduce dynamic allocations.
185 buffer_.reserve (128);
186 }
187
195 {
196#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
197 trace::printf ("%s\n", __PRETTY_FUNCTION__);
198#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
199
200 if (output_file_ != nullptr)
201 {
202 fflush (output_file_);
203 fclose (output_file_);
204
205 output_file_ = nullptr;
206 output_file_path_.clear ();
207 }
208 }
209
210 // --------------------------------------------------------------------------
211
218 endl (reporter& stream)
219 {
220 stream.end_line ();
221 return stream;
222 }
223
231 void
233 {
234 buffer_.append ("\n");
235 }
236
243 void
245 {
246 if (output_file_ == nullptr)
247 {
248 return;
249 }
250
252
254 {
255 write_console ("%sTest output written to '%s'.\n", comment_prefix (),
256 output_file_path_.c_str ());
257 fflush (stdout);
258 }
259 }
260
266 const char*
267 reporter::error_prefix (void) const noexcept
268 {
269 return "error: ";
270 }
271
280 reporter::route (record_kind kind) const noexcept
281 {
282 bool console;
284 || kind == record_kind::abort)
285 {
286 console = (verbosity_ != verbosity::silent);
287 }
288 else if (kind == record_kind::test_case_heading
290 {
291 console = (verbosity_ == verbosity::verbose);
292 }
293#if defined(MICRO_OS_PLUS_STARTUP_ENABLED) \
294 && defined(MICRO_OS_PLUS_DIAG_TRACE_ENABLED)
295 else if (kind == record_kind::info)
296 {
297 // The startup code already displays this information.
298 console = false;
299 }
300#endif // defined(MICRO_OS_PLUS_STARTUP_ENABLED) && ...
301 else
302 {
303 console = (verbosity_ == verbosity::normal
305 }
306
307 return { console, output_file_ != nullptr };
308 }
309
319 bool
320 reporter::writes_passed_checks (void) const noexcept
321 {
322 return output_file_ != nullptr || verbosity_ == verbosity::verbose;
323 }
324
331 std::string_view
332 reporter::console_lines (bool failed) const noexcept
333 {
335 {
336 return buffer_;
337 }
339 {
340 return failed ? std::string_view{ buffer_ } : std::string_view{};
341 }
343 {
344 return failures_;
345 }
346 return {};
347 }
348
354 void
355 reporter::write_console_text (std::string_view text)
356 {
357 // Pass only the text, do not add an `\n` here.
358 fwrite (text.data (), 1, text.size (), stdout);
359 }
360
366 void
368 {
370 {
371 failures_.append (buffer_, begin, std::string::npos);
372 }
374 }
375
381 void
383 {
384 const size_t count = include_last || open_test_cases_.empty ()
385 ? open_test_cases_.size ()
386 : open_test_cases_.size () - 1;
387 bool is_first = true;
388 for (size_t i = 0; i < count; ++i)
389 {
391 if (open.name_displayed)
392 {
393 continue;
394 }
395
396 display_open_heading (open, is_first);
397 is_first = false;
398
399 open.name_displayed = true;
400 }
401 }
402
408 void
409 reporter::enter_suite (const suite& suite, bool displayed)
410 {
412 suite_displayed_ = displayed;
413 }
414
424 void
426 {
427 if (output_file_ == nullptr)
428 {
429 return;
430 }
431
432 // Pass only the string, do not add an `\n` here.
433 write_without_colours (output_file_, buffer_);
434 }
435
443 void
444 reporter::write_console (const char* format, ...)
445 {
446 va_list args;
447 va_start (args, format);
448 vfprintf (stdout, format, args);
449 va_end (args);
450 }
451
457 void
458 reporter::write_file (const char* format, ...)
459 {
460 if (output_file_ == nullptr)
461 {
462 return;
463 }
464
465 va_list args;
466 va_start (args, format);
467 vfprintf (output_file_, format, args);
468 va_end (args);
469 }
470
484 void
485 reporter::write_line (bool to_console, const char* format, ...)
486 {
487 if (output_file_ == nullptr && !to_console)
488 {
489 return;
490 }
491
492 va_list args;
493 va_start (args, format);
494 va_list args_copy;
495 va_copy (args_copy, args);
496
497 char local_text[128];
498 const int length
499 = vsnprintf (local_text, sizeof (local_text), format, args);
500 va_end (args);
501
502 if (length < 0)
503 {
504 va_end (args_copy);
505 return;
506 }
507
508 const size_t size = static_cast<size_t> (length);
509 std::string long_text;
510 std::string_view text{ local_text, size };
511 if (size >= sizeof (local_text))
512 {
513 // The terminating null character is written over the one kept by
514 // the string after its content.
515 long_text.resize (size);
516 vsnprintf (long_text.data (), size + 1, format, args_copy);
517 text = long_text;
518 }
519 va_end (args_copy);
520
521 if (output_file_ != nullptr)
522 {
523 write_without_colours (output_file_, text);
524 }
525
526 if (to_console)
527 {
528 fwrite (text.data (), 1, text.size (), stdout);
529 }
530 }
531
546 void
547 reporter::write_info (const std::vector<std::string>& arguments)
548 {
549 const bool to_console = route (record_kind::info).console;
550
551 if (!arguments.empty ())
552 {
553 std::string line;
554 line.reserve (256);
555 line.append (comment_prefix ());
556 line.append ("Running: ");
557
558 // Append only the file name part of argv[0].
559 line.append (utility::extract_file_name (arguments[0].c_str ()));
560
561 for (size_t i = 1; i < arguments.size (); ++i)
562 {
563 line.append (" ");
564 line.append (arguments[i]);
565 }
566 line.append ("\n");
567
568 write_line (to_console, "%s", line.c_str ());
569 }
570
571 {
572 // Build the "Built with ..." line, including the compiler version
573 // (via __VERSION__); the same line goes to the file and to stdout.
574 std::string line;
575 line.reserve (256);
576 line.append (comment_prefix ());
577 line.append ("Built with ");
578#if defined(__clang__)
579 line.append ("clang " __VERSION__);
580#elif defined(__GNUC__)
581 line.append ("GCC " __VERSION__);
582#elif defined(_MSC_VER)
583 line.append ("MSVC");
584 char msvc_ver[16];
585 snprintf (msvc_ver, sizeof (msvc_ver), " - %d", _MSC_VER);
586 line.append (msvc_ver);
587#else
588 line.append ("an unknown compiler");
589#endif // defined(__clang__)
590#if !(defined(__APPLE__) || defined(__linux__) || defined(__unix__) \
591 || defined(_WIN32))
592 // This is relevant only on bare-metal.
593#if defined(__ARM_PCS_VFP) || defined(__ARM_FP)
594 line.append (", with FP");
595#else
596 line.append (", no FP");
597#endif // defined(__ARM_PCS_VFP) || defined(__ARM_FP)
598#endif // bare-metal only
599#if defined(__cpp_exceptions)
600 line.append (", with exceptions");
601#else
602 line.append (", no exceptions");
603#endif // defined(__cpp_exceptions)
604#if defined(MICRO_OS_PLUS_DEBUG_ENABLED)
605 line.append (", with MICRO_OS_PLUS_DEBUG_ENABLED");
606#endif // defined(MICRO_OS_PLUS_DEBUG_ENABLED)
607#if defined(MICRO_OS_PLUS_DIAG_TRACE_ENABLED)
608 line.append (", with MICRO_OS_PLUS_DIAG_TRACE_ENABLED");
609#endif // defined(MICRO_OS_PLUS_DIAG_TRACE_ENABLED)
610
611 write_line (to_console, "%s\n", line.c_str ());
612 }
613 }
614
621 void
623 {
624 fflush (stdout);
625 if (output_file_ != nullptr)
626 {
627 fflush (output_file_);
628 }
629 }
630
635 bool
636 reporter::has_output_file_error (void) const noexcept
637 {
639 }
640
641 // --------------------------------------------------------------------------
642
652 {
653 // Call the endl function.
654 (*func) (*this);
655 return *this;
656 }
657
666 {
667 buffer_.append (m.level * indent_size_, ' ');
668 return *this;
669 }
670
677 reporter::operator<<(std::string_view sv)
678 {
679 buffer_.append (sv);
680 return *this;
681 }
682
690 {
691 buffer_.append (1, c);
692 return *this;
693 }
694
704 reporter::operator<<(const char* s)
705 {
706 if (s == nullptr)
707 {
708 buffer_.append ("nullptr");
709 }
710 else
711 {
712 buffer_.append (s);
713 }
714 return *this;
715 }
716
727 {
728 buffer_.append (v ? "true" : "false");
729 return *this;
730 }
731
738 reporter::operator<<(std::nullptr_t)
739 {
740 buffer_.append ("nullptr");
741 return *this;
742 }
743
750 void
751 reporter::pass (const std::string& message, const std::string& expression,
752 const test_case& test_case)
753 {
755
756 if (message.empty ())
757 {
758 *this << expression;
759 }
760
762 }
763
770 void
771 reporter::fail (const failure_info& failure, const std::string& expression,
772 const test_case& test_case)
773 {
774 const size_t begin = buffer_.size ();
775
777 failure.location, test_case);
778
779 if (failure.has_expression)
780 {
781 *this << expression;
782 }
783
784 output_fail_suffix (failure.location, failure.kind, test_case);
785
786 mark_failure (begin);
787 }
788
794 void
796 {
797 buffer_.clear ();
798 failures_.clear ();
800 }
801
809 void
811 char (&message)[elapsed_time_size_])
812 {
813 const auto elapsed = stopwatch.elapsed ().count ();
814 if (elapsed > 0)
815 {
816 snprintf (message, sizeof (message),
817 ", time: %" PRIu32 ".%03" PRIu32 " ms",
818 static_cast<uint32_t> (elapsed / 1000),
819 static_cast<uint32_t> (elapsed % 1000));
820 }
821 else
822 {
823 message[0] = '\0';
824 }
825 }
826
827 // --------------------------------------------------------------------------
828
829 namespace
830 {
840 constexpr size_t fragment_size
841 = 21 + (std::numeric_limits<size_t>::digits10 + 1);
842
853 constexpr const char*
854 plural (size_t count) noexcept
855 {
856 return count == 1 ? "" : "s";
857 }
858
873 void
874 format_skipped (size_t count, char (&message)[fragment_size])
875 {
876 if (count > 0)
877 {
878 snprintf (message, sizeof (message),
880 count);
881 }
882 else
883 {
884 message[0] = '\0';
885 }
886 }
887 } // namespace
888
895 void
897 char (&message)[totals_size_])
898 {
899 // The fixed text, four counts, two fragments, and the terminator.
900 static_assert (totals_size_
901 >= 54 + 4 * (std::numeric_limits<size_t>::digits10 + 1)
902 + 2 * (fragment_size - 1),
903 "totals_size_ too small for the session totals");
904
905 const counters& totals = runner.totals ();
906 const size_t suites_count = runner.total_suites_count ();
907
908 char message_skipped_test_cases[fragment_size];
909 format_skipped (totals.skipped_test_cases (), message_skipped_test_cases);
910
911 char message_skipped_suites[fragment_size];
912 format_skipped (runner.skipped_suites_count (), message_skipped_suites);
913
914 snprintf (message, sizeof (message),
918 " test case%s%s, %" MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE " "
919 "test suite%s%s",
920 totals.passed_checks (), plural (totals.passed_checks ()),
921 totals.failed_checks (), totals.executed_test_cases (),
922 plural (totals.executed_test_cases ()),
923 message_skipped_test_cases, suites_count, plural (suites_count),
924 message_skipped_suites);
925 }
926
932 void
934 char (&message)[totals_size_])
935 {
936 const counters& totals = suite.totals ();
937
938 char message_skipped[fragment_size];
939 format_skipped (totals.skipped_test_cases (), message_skipped);
940
941 if (totals.passed ()) [[likely]]
942 {
943 snprintf (message, sizeof (message),
946 " test case%s%s",
947 totals.passed_checks (), plural (totals.passed_checks ()),
948 totals.executed_test_cases (),
949 plural (totals.executed_test_cases ()), message_skipped);
950 }
951 else
952 {
953 snprintf (message, sizeof (message),
957 " test case%s%s",
958 totals.passed_checks (), plural (totals.passed_checks ()),
959 totals.failed_checks (), totals.executed_test_cases (),
960 plural (totals.executed_test_cases ()), message_skipped);
961 }
962 }
963
969 void
971 char (&message)[totals_size_])
972 {
973 const counters& totals = test_case.totals ();
974
975 if (totals.passed ()) [[likely]]
976 {
977 snprintf (message, sizeof (message),
979 totals.passed_checks (), plural (totals.passed_checks ()));
980 }
981 else
982 {
983 char message_test_cases[fragment_size] = "";
984 if (totals.failed_test_cases () > 0)
985 {
986 snprintf (message_test_cases, sizeof (message_test_cases),
988 " test case%s failed",
989 totals.failed_test_cases (),
990 plural (totals.failed_test_cases ()));
991 }
992
993 snprintf (message, sizeof (message),
996 " failed%s",
997 totals.passed_checks (), plural (totals.passed_checks ()),
998 totals.failed_checks (), message_test_cases);
999 }
1000 }
1001
1012 void
1014 {
1015 if (!buffer_.empty ())
1016 {
1017 commit_buffer ();
1018 }
1019 }
1020
1021 // --------------------------------------------------------------------------
1022} // namespace micro_os_plus::micro_test_plus::detail
1023
1024// ----------------------------------------------------------------------------
1025
1026#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED)
1027
1028// ----------------------------------------------------------------------------

Generated via doxygen2docusaurus 2.2.8 by Doxygen 1.18.0.