Skip to content

Commit

Permalink
Testing: Add --quiet switch and flags to execute sections only if exp…
Browse files Browse the repository at this point in the history
…licitly requested

This is helpful to spawn child test processes to avoid unwanted text in their stdout
  • Loading branch information
Pagghiu committed Apr 8, 2024
1 parent ddb2c27 commit 0cf618a
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 31 deletions.
73 changes: 50 additions & 23 deletions Libraries/Testing/Testing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ SC::TestReport::TestReport(Console& console, int argc, const char** argv) : cons
for (int idx = 1; idx < argc; ++idx)
{
const auto param = StringView::fromNullTerminated(argv[idx], StringEncoding::Ascii);
if (param == "--quiet"_a8)
{
quietMode = true;
}
if (param == "--test"_a8 && testToRun.isEmpty())
{
if (idx + 1 < argc)
{
testToRun = StringView::fromNullTerminated(argv[idx + 1], StringEncoding::Ascii);

console.print("TestReport::Running single test \"{}\"\n"_a8, testToRun);
if (not quietMode)
{
console.print("TestReport::Running single test \"{}\"\n"_a8, testToRun);
}
}
}
if (param == "--test-section"_a8 && sectionToRun.isEmpty())
Expand All @@ -31,7 +37,10 @@ SC::TestReport::TestReport(Console& console, int argc, const char** argv) : cons
{
sectionToRun = StringView::fromNullTerminated(argv[idx + 1], StringEncoding::Ascii);

console.print("TestReport::Running single section \"{}\"\n"_a8, sectionToRun);
if (not quietMode)
{
console.print("TestReport::Running single section \"{}\"\n"_a8, sectionToRun);
}
}
}
}
Expand All @@ -43,6 +52,8 @@ SC::TestReport::TestReport(Console& console, int argc, const char** argv) : cons

SC::TestReport::~TestReport()
{
if (quietMode)
return;
if (numTestsFailed > 0)
{
console.print(redEMOJI);
Expand All @@ -63,7 +74,10 @@ SC::TestCase::TestCase(TestReport& report, StringView testName)
{
if (report.isTestEnabled(testName))
{
report.console.print("[[ {} ]]\n\n"_a8, testName);
if (not report.quietMode)
{
report.console.print("[[ {} ]]\n\n"_a8, testName);
}
report.firstFailedTest = StringView();
report.currentSection = StringView();
}
Expand All @@ -77,25 +91,27 @@ SC::TestCase::~TestCase()
{
report.printSectionResult(*this);
}

report.console.print("\n"_a8);
if (numTestsFailed > 0)
if (not report.quietMode)
{
report.console.print(redEMOJI);
report.console.print(" [[ "_a8);
report.console.print(testName);
report.console.print(" ]]"_a8);
report.console.print(" FAILED = {} (Succeeded = {})\n"_a8, numTestsFailed, numTestsSucceeded);
}
else
{
report.console.print(greenEMOJI);
report.console.print(" [[ "_a8);
report.console.print(testName);
report.console.print(" ]]"_a8);
report.console.print(" SUCCEEDED = {}\n"_a8, numTestsSucceeded);
report.console.print("\n"_a8);
if (numTestsFailed > 0)
{
report.console.print(redEMOJI);
report.console.print(" [[ "_a8);
report.console.print(testName);
report.console.print(" ]]"_a8);
report.console.print(" FAILED = {} (Succeeded = {})\n"_a8, numTestsFailed, numTestsSucceeded);
}
else
{
report.console.print(greenEMOJI);
report.console.print(" [[ "_a8);
report.console.print(testName);
report.console.print(" ]]"_a8);
report.console.print(" SUCCEEDED = {}\n"_a8, numTestsSucceeded);
}
report.console.print("---------------------------------------------------\n"_a8);
}
report.console.print("---------------------------------------------------\n"_a8);
report.numTestsFailed += numTestsFailed;
report.numTestsSucceeded += numTestsSucceeded;
report.testCaseFinished(*this);
Expand Down Expand Up @@ -140,10 +156,21 @@ bool SC::TestCase::recordExpectation(StringView expression, Result status)
StringView({status.message, status.message ? ::strlen(status.message) : 0}, true, StringEncoding::Ascii));
}

bool SC::TestCase::test_section(StringView sectionName)
bool SC::TestCase::test_section(StringView sectionName, Execute execution)
{
numSectionTestsFailed = 0;
if (report.isTestEnabled(testName) && report.isSectionEnabled(sectionName))
bool isTestEnabled;
switch (execution)
{
case Execute::Default: //
isTestEnabled = report.isTestEnabled(testName) and report.isSectionEnabled(sectionName);
break;
case Execute::OnlyExplicit: //
isTestEnabled = report.sectionToRun == sectionName;
break;
default: return false;
}
if (isTestEnabled)
{
SC_ASSERT_DEBUG(sectionName.isNullTerminated());
if (not report.currentSection.isEmpty())
Expand Down
23 changes: 16 additions & 7 deletions Libraries/Testing/Testing.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ struct SC::TestReport
StringView applicationRootDirectory; ///< Path to application (on macOS is different from executable path)

// Options
bool abortOnFirstFailedTest = true; ///< If `true` will abort after first failed test
bool debugBreakOnFailedTest = true; ///< If `true` will issue a debugger halt when a test fails
bool abortOnFirstFailedTest = true; ///< If `true` will abort after first failed test
bool debugBreakOnFailedTest = true; ///< If `true` will issue a debugger halt when a test fails
bool quietMode = false; ///< If `true` will not print recaps at start or end of the test

/// @brief Build from a console and executable arguments
/// @param console A Console object where to print test results
Expand Down Expand Up @@ -85,19 +86,27 @@ struct SC::TestCase
/// @return `false` if `status` Result is not valid
bool recordExpectation(StringView expression, Result status);

enum class Execute
{
Default, ///< Test is executed if all tests are enabled or if this specific one matches --test-section
OnlyExplicit ///< Test is executed only if explicitly requested with --test-section
};

/// @brief Starts a new test section
/// @param sectionName The name of the section
/// @param execution Execution criteria
/// @return `true` if the test is enabled, `false` otherwise
[[nodiscard]] bool test_section(StringView sectionName);
[[nodiscard]] bool test_section(StringView sectionName, Execute execution = Execute::Default);

TestReport& report; ///< The TestReport object passed in the constructor
private:
friend struct TestReport;
const StringView testName;
uint32_t numTestsSucceeded;
uint32_t numTestsFailed;
uint32_t numSectionTestsFailed;
bool printedSection;

uint32_t numTestsSucceeded;
uint32_t numTestsFailed;
uint32_t numSectionTestsFailed;
bool printedSection;
};

/// Records a test expectation (eventually aborting or breaking o n failed test)
Expand Down
2 changes: 1 addition & 1 deletion Libraries/Threading/Threading.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ struct SC::ConditionVariable
/// thread.start([](Thread& thread)
/// {
/// // It's highly recommended setting a name for the thread
/// thread.setThreadName(SC_STR_NATIVE("My Thread"));
/// thread.setThreadName(SC_NATIVE_STR("My Thread"));
/// // Do something on the thread
/// Thread::Sleep(1000); // Sleep for 1 second
/// });
Expand Down

0 comments on commit 0cf618a

Please sign in to comment.