19 fl::printf(
"===============================================================================\n");
21 fl::printf(
"===============================================================================\n");
26 fl::printf(
"===============================================================================\n");
28 fl::printf(
"-------------------------------------------------------------------------------\n");
29 if (stats.mTestCasesSkipped > 0) {
30 fl::printf(
"Test cases: %u passed, %u failed, %u skipped, %u total\n",
31 stats.mTestCasesPassed, stats.mTestCasesFailed,
32 stats.mTestCasesSkipped, stats.mTestCasesRun);
34 fl::printf(
"Test cases: %u passed, %u failed, %u total\n",
35 stats.mTestCasesPassed, stats.mTestCasesFailed, stats.mTestCasesRun);
37 fl::printf(
"Assertions: %u passed, %u failed\n",
38 stats.mAssertsPassed, stats.mAssertsFailed);
39 if (stats.mTotalDurationMs > 0) {
40 fl::printf(
"Duration: %u ms\n", stats.mTotalDurationMs);
42 fl::printf(
"===============================================================================\n");
44 if (stats.allPassed()) {
84 if (!
result.mExpanded.empty()) {
115 const char* filter =
nullptr;
116 if (argc > 1 && argv && argv[1]) {
126 for (fl::size i = 0; i <
mTestCases.size(); ++i) {
128 if (filter && filter[0] !=
'\0') {
137 return mStats.allPassed() ? 0 : 1;
145 for (fl::size i = 0; i <
mTestCases.size(); ++i) {
147 if (filter && filter[0] !=
'\0') {
158 fl::printf(
"Total: %u tests\n\n",
static_cast<fl::u32
>(count));
163 if (!filter || filter[0] ==
'\0') {
168 const char* n = name;
169 const char* f = filter;
172 bool hasWildcards =
false;
173 for (
const char* p = filter; *p; ++p) {
174 if (*p ==
'*' || *p ==
'?') {
184 const char* ff = filter;
185 while (*nn && *ff && *nn == *ff) {
212 }
else if (*f ==
'?') {
245 mReporter->testCaseStart(info.mName.c_str());
293 fl::u32 testDurationMs = 0;
296 mStats.mTotalDurationMs += testDurationMs;
300 mStats.mTestCasesSkipped++;
301 mReporter->testCaseEnd(
true, testDurationMs);
303 mStats.mTestCasesFailed++;
304 mReporter->testCaseEnd(
false, testDurationMs);
306 mStats.mTestCasesPassed++;
307 mReporter->testCaseEnd(
true, testDurationMs);
327 fl::printf(
" [TIMEOUT] Test exceeded %u ms (elapsed: %u ms)\n",
417 result.mExpression = expr;
472 fl::printf(
" [MESSAGE] %s:%d: %s\n", file, line, msg);
485 fl::printf(
" FAIL (fatal): %s:%d: %s\n", file, line, msg);
487 fl::printf(
" FAIL_CHECK: %s:%d: %s\n", file, line, msg);
500 fl::printf(
" [SKIPPED] %s:%d: %s\n", file, line, reason);
522 print(
"====== FL TEST: Running tests... ======\n");
526 print(
"\n====== FL TEST: Results ======\n");
530 ss <<
"Passed: " << stats.mTestCasesPassed
531 <<
"/" << stats.mTestCasesRun <<
" tests\n";
534 if (stats.mTestCasesSkipped > 0) {
536 ss_skip <<
"Skipped: " << stats.mTestCasesSkipped <<
"\n";
540 if (stats.mAssertsFailed > 0) {
542 ss2 <<
"Failed assertions: " << stats.mAssertsFailed <<
"\n";
546 if (stats.allPassed()) {
547 print(
"Status: PASS\n");
549 print(
"Status: FAIL\n");
555 ss <<
"\n[TEST] " << name <<
"\n";
561 if (durationMs > 0) {
563 ss <<
"[PASS] (" << durationMs <<
" ms)\n";
569 if (durationMs > 0) {
571 ss <<
"[FAIL] (" << durationMs <<
" ms)\n";
581 ss <<
" [SUBCASE] " << name <<
"\n";
592 ss <<
" FAIL: " <<
result.mLocation.mFile
593 <<
":" <<
result.mLocation.mLine <<
"\n";
594 ss <<
" Expr: " <<
result.mExpression <<
"\n";
595 if (!
result.mExpanded.empty()) {
596 ss <<
" Got: " <<
result.mExpanded <<
"\n";
610 for (
const char* p = text; *p; ++p) {
612 case '&':
result +=
"&";
break;
613 case '<':
result +=
"<";
break;
614 case '>':
result +=
">";
break;
615 case '"':
result +=
""";
break;
616 case '\'':
result +=
"'";
break;
617 default:
result += *p;
break;
633 ss <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
637 ss <<
"tests=\"" << stats.mTestCasesRun <<
"\" ";
638 ss <<
"failures=\"" << stats.mTestCasesFailed <<
"\" ";
639 ss <<
"errors=\"0\" ";
640 ss <<
"skipped=\"" << stats.mTestCasesSkipped <<
"\">\n";
647 ss <<
"</testsuite>\n";
663 if (durationMs > 0) {
665 fl::u32 secs = durationMs / 1000;
666 fl::u32
millis = durationMs % 1000;
667 ss <<
" time=\"" << secs <<
"." << (
millis < 100 ? (
millis < 10 ?
"00" :
"0") :
"") <<
millis <<
"\"";
674 ss <<
" <failure message=\"Test failed\">\n";
676 ss <<
" </failure>\n";
677 ss <<
" </testcase>\n";
696 ss <<
result.mLocation.mFile <<
":" <<
result.mLocation.mLine <<
"\n";
697 ss <<
" Expression: " <<
result.mExpression <<
"\n";
698 if (!
result.mExpanded.empty()) {
699 ss <<
" Expanded: " <<
result.mExpanded <<
"\n";
714 for (
const char* p = text; *p; ++p) {
716 case '\\':
result +=
"\\\\";
break;
717 case '"':
result +=
"\\\"";
break;
718 case '\n':
result +=
"\\n";
break;
719 case '\r':
result +=
"\\r";
break;
720 case '\t':
result +=
"\\t";
break;
723 if (
static_cast<unsigned char>(*p) < 32) {
727 hex[0] =
"0123456789abcdef"[(*p >> 4) & 0xF];
728 hex[1] =
"0123456789abcdef"[*p & 0xF];
750 ss <<
" \"summary\": {\n";
751 ss <<
" \"total\": " << stats.mTestCasesRun <<
",\n";
752 ss <<
" \"passed\": " << stats.mTestCasesPassed <<
",\n";
753 ss <<
" \"failed\": " << stats.mTestCasesFailed <<
",\n";
754 ss <<
" \"skipped\": " << stats.mTestCasesSkipped <<
",\n";
755 ss <<
" \"assertionsPassed\": " << stats.mAssertsPassed <<
",\n";
756 ss <<
" \"assertionsFailed\": " << stats.mAssertsFailed <<
"\n";
758 ss <<
" \"tests\": [\n";
784 ss <<
" \"passed\": " << (passed ?
"true" :
"false");
787 if (durationMs > 0) {
789 ss <<
" \"durationMs\": " << durationMs;
794 ss <<
" \"failures\": [\n";
827 ss <<
" \"line\": " <<
result.mLocation.mLine <<
",\n";
828 ss <<
" \"expression\": \"" <<
escapeJson(
result.mExpression.c_str()) <<
"\"";
830 if (!
result.mExpanded.empty()) {
873 ss <<
"1.." << stats.mTestCasesRun;
879 ss <<
"# Tests: " << stats.mTestCasesRun
880 <<
", Passed: " << stats.mTestCasesPassed
881 <<
", Failed: " << stats.mTestCasesFailed;
882 if (stats.mTestCasesSkipped > 0) {
883 ss <<
", Skipped: " << stats.mTestCasesSkipped;
910 if (durationMs > 0) {
911 ss <<
" # (" << durationMs <<
" ms)";
926 ss <<
" Subcase: " << (name ? name :
"unknown");
939 ss <<
" Failed at " <<
result.mLocation.mFile <<
":" <<
result.mLocation.mLine;
943 ss2 <<
" Expression: " <<
result.mExpression;
946 if (!
result.mExpanded.empty()) {
948 ss3 <<
" Expanded: " <<
result.mExpanded;
static T & instance() FL_NO_EXCEPT
const char * c_str() const FL_NO_EXCEPT
string str() const FL_NO_EXCEPT
void assertResult(const AssertResult &result) FL_NO_EXCEPT override
void testCaseEnd(bool passed, fl::u32 durationMs=0) FL_NO_EXCEPT override
Called when a test case ends.
void subcaseStart(const char *name) FL_NO_EXCEPT override
void testRunEnd(const TestStats &stats) FL_NO_EXCEPT override
void testRunStart() FL_NO_EXCEPT override
void subcaseEnd() FL_NO_EXCEPT override
void testCaseStart(const char *name) FL_NO_EXCEPT override
void testRunStart() FL_NO_EXCEPT override
void subcaseEnd() FL_NO_EXCEPT override
fl::vector< fl::string > mCurrentTestFailures
void testCaseEnd(bool passed, fl::u32 durationMs=0) FL_NO_EXCEPT override
Called when a test case ends.
static fl::string escapeJson(const char *text) FL_NO_EXCEPT
void assertResult(const AssertResult &result) FL_NO_EXCEPT override
fl::string mCurrentTestName
void testRunEnd(const TestStats &stats) FL_NO_EXCEPT override
fl::vector< fl::string > mTestResults
void subcaseStart(const char *name) FL_NO_EXCEPT override
void testCaseStart(const char *name) FL_NO_EXCEPT override
void testCaseEnd(bool passed, fl::u32 durationMs=0) FL_NO_EXCEPT override
Called when a test case ends.
void print(const char *msg) FL_NO_EXCEPT
void testRunStart() FL_NO_EXCEPT override
void subcaseStart(const char *name) FL_NO_EXCEPT override
SerialPrintFunc mPrintFunc
void testCaseStart(const char *name) FL_NO_EXCEPT override
void testRunEnd(const TestStats &stats) FL_NO_EXCEPT override
void assertResult(const AssertResult &result) FL_NO_EXCEPT override
void subcaseEnd() FL_NO_EXCEPT override
Subcase(const char *name, const char *file, int line) FL_NO_EXCEPT
SubcaseSignature mSignature
void subcaseEnd() FL_NO_EXCEPT override
void testRunEnd(const TestStats &stats) FL_NO_EXCEPT override
fl::string mCurrentTestName
void output(const char *line) FL_NO_EXCEPT
SerialPrintFunc mPrintFunc
fl::string mStreamingOutput
void testCaseStart(const char *name) FL_NO_EXCEPT override
void assertResult(const AssertResult &result) FL_NO_EXCEPT override
void testCaseEnd(bool passed, fl::u32 durationMs=0) FL_NO_EXCEPT override
Called when a test case ends.
void subcaseStart(const char *name) FL_NO_EXCEPT override
fl::vector< fl::string > mDiagnostics
void testRunStart() FL_NO_EXCEPT override
fl::u32 mDefaultTimeoutMs
fl::vector< SubcaseSignature > mNextSubcaseStack
void exitSubcase(const SubcaseSignature &sig) FL_NO_EXCEPT
fl::size mSubcaseDiscoveryDepth
DefaultReporter mDefaultReporter
bool enterSubcase(const SubcaseSignature &sig) FL_NO_EXCEPT
fl::u32 hashCurrentPath(const SubcaseSignature &sig) const FL_NO_EXCEPT
int run(int argc=0, const char *const *argv=nullptr) FL_NO_EXCEPT
static TestContext & instance() FL_NO_EXCEPT
TimeoutHandlerFunc mTimeoutHandler
TestContext() FL_NO_EXCEPT
fl::size mCurrentSubcaseDepth
void checkFailed(const char *expr, const char *file, int line) FL_NO_EXCEPT
fl::vector< TestCaseInfo > mTestCases
fl::u32 getElapsedMs() const FL_NO_EXCEPT
Get elapsed time for current test (in ms)
bool mCurrentTestTimedOut
fl::vector< fl::u32 > mFullyTraversedHashes
fl::vector< SubcaseSignature > mSubcaseStack
void requireFailed(const char *expr, const char *file, int line) FL_NO_EXCEPT
fl::size listTests(const char *filter=nullptr) const FL_NO_EXCEPT
bool matchesFilter(const char *name, const char *filter) const FL_NO_EXCEPT
void runTestCase(const TestCaseInfo &info) FL_NO_EXCEPT
bool checkTimeout() FL_NO_EXCEPT
Check if current test has timed out (call periodically in long tests) Returns true if timed out.
fl::u32 mCurrentTestStartMs
void reportAssert(const AssertResult &result) FL_NO_EXCEPT
int registerTest(TestFunc func, const char *name, const char *file, int line) FL_NO_EXCEPT
const char * mCurrentTestName
bool isFullyTraversed(fl::u32 hash) const FL_NO_EXCEPT
void markFullyTraversed(fl::u32 hash) FL_NO_EXCEPT
void testRunEnd(const TestStats &stats) FL_NO_EXCEPT override
void testRunStart() FL_NO_EXCEPT override
void testCaseStart(const char *name) FL_NO_EXCEPT override
void testCaseEnd(bool passed, fl::u32 durationMs=0) FL_NO_EXCEPT override
Called when a test case ends.
void subcaseEnd() FL_NO_EXCEPT override
static fl::string escapeXml(const char *text) FL_NO_EXCEPT
void subcaseStart(const char *name) FL_NO_EXCEPT override
void assertResult(const AssertResult &result) FL_NO_EXCEPT override
fl::vector< fl::string > mTestCaseResults
fl::string mCurrentTestName
fl::string mCurrentTestFailures
Portable test framework for FastLED.
Centralized logging categories for FastLED hardware interfaces and subsystems.
void outputCapture(const char *name, const char *value, const char *file, int line) FL_NO_EXCEPT
Helper to output CAPTURE variable.
static SkipState & skipState() FL_NO_EXCEPT
fl::u32 hashSubcaseSignature(const SubcaseSignature &sig) FL_NO_EXCEPT
void outputMessage(const char *msg, const char *file, int line) FL_NO_EXCEPT
Helper to output INFO/MESSAGE during test execution.
void fail(const char *msg, const char *file, int line, bool isFatal) FL_NO_EXCEPT
Helper for FAIL macros.
void skipTest(const char *reason, const char *file, int line) FL_NO_EXCEPT
Record that the current test should be skipped.
bool isTestSkipped() FL_NO_EXCEPT
Check if current test has been marked as skipped.
u8 u8 fract8 blur_amount FL_NO_EXCEPT
void print(const char *str) FL_NO_EXCEPT
constexpr int type_rank< T >::value
fl::u32 millis() FL_NO_EXCEPT
Universal millisecond timer - returns milliseconds since system startup.
void printf(const char *format) FL_NO_EXCEPT
expected< T, E > result
Alias for expected (Rust-style naming)
Base definition for an LED controller.