micro-test-plus 3.2.2
µTest++ Testing Framework
Loading...
Searching...
No Matches
test-reporter.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ project (https://micro-os-plus.github.io/).
3 * Copyright (c) 2021 Liviu Ionescu. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software
6 * for any 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
9 * be 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
43
44// ----------------------------------------------------------------------------
45
46#if defined(MICRO_OS_PLUS_INCLUDE_CONFIG_H)
47#include <micro-os-plus/config.h>
48#endif // MICRO_OS_PLUS_INCLUDE_CONFIG_H
49
51
52// ----------------------------------------------------------------------------
53
54#pragma GCC diagnostic ignored "-Waggregate-return"
55#if defined(__clang__)
56#pragma clang diagnostic ignored "-Wc++98-compat"
57#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
58#endif
59
61{
62 // --------------------------------------------------------------------------
63
74 {
75 reporter.endline ();
76 return stream;
77 }
78
79 // --------------------------------------------------------------------------
80
93 void
95 {
96 *this << colors_.pass;
98 {
99 *this << " ";
100 }
101 *this << " ✓ ";
102 *this << colors_.none;
103 if (!message.empty ())
104 {
105 *this << message.c_str ();
106 }
107 }
108
124 void
126 {
127 *this << endl;
128
129 flush ();
130 }
131
143 void
145 std::string& message, const reflection::source_location& location)
146 {
147 *this << colors_.fail;
149 {
150 *this << " ";
151 }
152 *this << " ✗ ";
153 *this << colors_.none;
154 if (!message.empty ())
155 {
156 *this << message.c_str ();
157 *this << " ";
158 }
159 *this << colors_.fail << "FAILED" << colors_.none;
160#pragma GCC diagnostic push
161#if defined(__clang__)
162#pragma clang diagnostic ignored "-Wsign-conversion"
163#elif defined(__GNUC__)
164#pragma GCC diagnostic ignored "-Wnarrowing"
165#pragma GCC diagnostic ignored "-Wsign-conversion"
166#endif
167 *this << " (" << reflection::short_name (location.file_name ()) << ":"
169 location.line ()
170 };
171#pragma GCC diagnostic pop
172 }
173
183 void
185 {
186 *this << ")";
187 if (abort)
188 {
189 *this << " aborted...";
190 }
191 *this << endl;
192
193 flush ();
194 }
195
207 {
208 // Call the endl function.
209 (*func) (*this);
210 return *this;
211 }
212
221 void
223 {
224 out_.append ("\n");
225 flush ();
226 }
227
235 void
237 {
238 fflush (stdout); // Sync STDOUT.
239 }
240
250 test_reporter::operator<< (std::string_view sv)
251 {
252 out_.append (sv);
253 return *this;
254 }
255
265 {
266 out_.append (1, c);
267 return *this;
268 }
269
279 test_reporter::operator<< (const char* s)
280 {
281 out_.append (s);
282 return *this;
283 }
284
295 {
296 out_.append (s);
297 return *this;
298 }
299
310 {
311 out_.append (v ? "true" : "false");
312 return *this;
313 }
314
323 test_reporter::operator<< (std::nullptr_t)
324 {
325 out_.append ("nullptr");
326 return *this;
327 }
328
338 test_reporter::operator<< (signed char c)
339 {
340 out_.append (std::to_string (c));
341 out_.append ("c");
342 return *this;
343 }
344
354 test_reporter::operator<< (unsigned char c)
355 {
356 out_.append (std::to_string (static_cast<int> (c)));
357 out_.append ("uc");
358 return *this;
359 }
360
370 test_reporter::operator<< (signed short v)
371 {
372 out_.append (std::to_string (v));
373 out_.append ("s");
374 return *this;
375 }
376
386 test_reporter::operator<< (unsigned short v)
387 {
388 out_.append (std::to_string (static_cast<long> (v)));
389 out_.append ("us");
390 return *this;
391 }
392
402 test_reporter::operator<< (signed int v)
403 {
404 out_.append (std::to_string (v));
405 return *this;
406 }
407
417 test_reporter::operator<< (unsigned int v)
418 {
419 out_.append (std::to_string (v));
420 out_.append ("u");
421 return *this;
422 }
423
433 test_reporter::operator<< (signed long v)
434 {
435 out_.append (std::to_string (v));
436 out_.append ("l");
437 return *this;
438 }
439
449 test_reporter::operator<< (unsigned long v)
450 {
451 out_.append (std::to_string (v));
452 out_.append ("ul");
453 return *this;
454 }
455
465 test_reporter::operator<< (signed long long v)
466 {
467 out_.append (std::to_string (v));
468 out_.append ("ll");
469 return *this;
470 }
471
481 test_reporter::operator<< (unsigned long long v)
482 {
483 out_.append (std::to_string (v));
484 out_.append ("ull");
485 return *this;
486 }
487
498 {
499 out_.append (std::to_string (v));
500 out_.append ("f");
501 return *this;
502 }
503
514 {
515 out_.append (std::to_string (v));
516 return *this;
517 }
518
529 test_reporter::operator<< (long double v)
530 {
531 out_.append (std::to_string (v));
532 out_.append ("l");
533 return *this;
534 }
535
547 void
548 test_reporter::begin_test_case ([[maybe_unused]] const char* name)
549 {
550 is_in_test_case_ = true;
551
552 if (!out_.empty () && (verbosity == verbosity::verbose))
553 {
554 if (add_empty_line)
555 {
556 printf ("\n");
557 }
558 output ();
559 add_empty_line = true;
560 }
561
562 out_.clear ();
563
564 flush ();
565 }
566
579 void
580 test_reporter::end_test_case ([[maybe_unused]] const char* name)
581 {
583 {
584 if (current_test_suite->current_test_case.failed_checks > 0)
585 {
586 if (true /* add_empty_line */)
587 {
588 printf ("\n");
589 }
590 printf (" • %s - test case started\n", name);
591 output ();
592 printf (
593 " %s✗%s %s - test case %sFAILED%s (%d %s passed, %d "
594 "failed)\n",
595 colors_.fail, colors_.none, name, colors_.fail, colors_.none,
596 current_test_suite->current_test_case.successful_checks,
597 current_test_suite->current_test_case.successful_checks == 1
598 ? "check"
599 : "checks",
600 current_test_suite->current_test_case.failed_checks);
601 add_empty_line = true;
602 }
603 else
604 {
605 if (add_empty_line)
606 {
607 printf ("\n");
608 }
610 {
611 printf (" • %s - test case started\n", name);
612 output ();
613 printf (
614 " %s✓%s %s - test case passed (%d %s)\n", colors_.pass,
615 colors_.none, name,
616 current_test_suite->current_test_case.successful_checks,
617 current_test_suite->current_test_case.successful_checks
618 == 1
619 ? "check"
620 : "checks");
621
622 add_empty_line = true;
623 }
624 else
625 {
626 printf (
627 " %s✓%s %s - test case passed (%d %s)\n", colors_.pass,
628 colors_.none, name,
629 current_test_suite->current_test_case.successful_checks,
630 current_test_suite->current_test_case.successful_checks
631 == 1
632 ? "check"
633 : "checks");
634
635 add_empty_line = false;
636 }
637 }
638 }
639
640 out_.clear ();
641 flush ();
642
643 is_in_test_case_ = false;
644 }
645
656 void
658 {
659 if (add_empty_line)
660 {
661 flush ();
662 printf ("\n");
663 }
664
666 {
667 add_empty_line = false;
668 return;
669 }
670
671 printf ("• %s - test suite started\n", name);
672
673 add_empty_line = true;
674 }
675
688 void
690 {
692 {
693 return;
694 }
695
696 if (suite.test_cases () > 0 && verbosity != verbosity::quiet)
697 {
698 printf ("\n");
699 add_empty_line = true;
700 }
701
702 // Also fail if none passed.
703 if (suite.failed_checks () == 0 && suite.successful_checks () != 0)
704 {
705 printf ("%s✓%s %s - test suite passed (%d %s in %d test %s)\n",
706 colors_.pass, colors_.none, suite.name (),
707 suite.successful_checks (),
708 suite.successful_checks () == 1 ? "check" : "checks",
709 suite.test_cases (),
710 suite.test_cases () == 1 ? "case" : "cases");
711 }
712 else
713 {
714 printf ("%s✗%s %s - test suite %sFAILED%s (%d %s passed, %d failed, "
715 "in %d test %s)\n",
716 colors_.fail, colors_.none, suite.name (), colors_.fail,
717 colors_.none, suite.successful_checks (),
718 suite.successful_checks () == 1 ? "check" : "checks",
719 suite.failed_checks (), suite.test_cases (),
720 suite.test_cases () == 1 ? "case" : "cases");
721 }
722 flush ();
723 }
724
734 void
736 {
737 printf ("%s", out_.c_str ()); // No `\n` here.
738 out_.clear ();
739 }
740
741 // --------------------------------------------------------------------------
742} // namespace micro_os_plus::micro_test_plus
743
744// ----------------------------------------------------------------------------
Local implementation of source location information for diagnostics.
Definition reflection.h:137
constexpr auto file_name(void) const noexcept
Retrieve the file name associated with this source location.
constexpr auto line(void) const noexcept
Retrieve the line number associated with this source location.
Reporter to display test results, including operand values and types for failures.
colors colors_
ANSI colour codes for output formatting.
void endline(void)
Inserts a line ending into the output buffer.
bool is_in_test_case_
Indicates whether the reporter is currently within a test case.
std::string out_
Internal output buffer for accumulating report content.
test_reporter()=default
Default constructor for the test_reporter class.
void output_pass_suffix_(void)
Outputs the suffix for a passing condition.
void output(void)
Output the current buffered content.
void output_fail_suffix_(bool abort)
Outputs the suffix for a failing condition.
void flush(void)
Flush the current buffered content.
void end_test_case(const char *name)
Mark the end of a test case.
void begin_test_case(const char *name)
Mark the beginning of a test case.
test_reporter & operator<<(std::string_view sv)
Output operator for std::string_view.
void end_test_suite(test_suite_base &suite)
Mark the end of a test suite.
void begin_test_suite(const char *name)
Mark the beginning of a test suite.
verbosity_t verbosity
The verbosity level for test reporting.
void output_fail_prefix_(std::string &message, const reflection::source_location &location)
Outputs the prefix for a failing condition.
bool add_empty_line
Controls whether to add an empty line between successful test cases.
void output_pass_prefix_(std::string &message)
Outputs the prefix for a passing condition.
Base class for all test suites.
Definition test-suite.h:98
constexpr const char * name(void)
Gets the suite name.
Definition test-suite.h:178
int failed_checks
Number of failed checks in the current test case.
Definition test-suite.h:343
int successful_checks
Number of successful checks in the current test case.
Definition test-suite.h:338
constexpr int test_cases(void)
Gets the number of test cases.
Definition test-suite.h:239
Main C++ header with the declarations for the µTest++ Testing Framework.
const char * short_name(const char *name)
Extract a short type or function name from a fully qualified name.
Primary namespace for the µTest++ testing framework.
test_suite_base * current_test_suite
Global pointer references the currently active test suite.
test_reporter & endl(test_reporter &stream)
Output stream manipulator for ending a line in test reports.
test_reporter reporter
Global instance of test_reporter.
Struct template representing a genuine integral value.