#include "expression_test_logger.hpp" #include "expression_test_runner.hpp" #include "filesystem.hpp" #include #include #include using namespace mbgl; using namespace std::literals; namespace { const char* resultsStyle = R"HTML( )HTML"; const char* resultsHeaderButtons = R"HTML( )HTML"; const char* resultsScript = R"HTML( )HTML"; std::string createResultItem(const TestRunOutput& result, const std::string& status, bool shouldHide) { std::ostringstream html; html << "
\n"; html << R"(

)" << status << " " << result.id << "

\n"; html << "

"s << result.expression << "

\n"s; if (result.passed) { html << "Serialized:

"s << result.serialized << "

\n"s; } else { html << "

Difference:

" << result.text << "

\n"; } html << "
\n"; return html.str(); } std::string createResultPage(const TestStats& stats, bool shuffle, uint32_t seed) { const std::size_t unsuccessfulCount = stats.errored.size() + stats.failed.size(); const bool unsuccessful = unsuccessfulCount > 0; std::ostringstream resultsPage; // Style resultsPage << resultsStyle; // Header with buttons if (unsuccessful) { resultsPage << R"HTML(

)HTML"; resultsPage << util::toString(unsuccessfulCount) << " tests failed."; } else { resultsPage << R"HTML(

)HTML"; resultsPage << "All tests passed!"; } resultsPage << resultsHeaderButtons; // Test sequence { resultsPage << "
\n"; // Failed tests if (unsuccessful) { resultsPage << "

Failed tests:"; for (const auto& failed : stats.failed) { resultsPage << failed.id << " "; } resultsPage << "

Errored tests:"; for (const auto& errored : stats.errored) { resultsPage << errored.id << " "; } resultsPage << "

\n"; } // Test sequence resultsPage << "

Test sequence: "; for (const auto& id : stats.ids) { resultsPage << id << " "; } resultsPage << "

\n"; // Shuffle if (shuffle) { resultsPage << "

Shuffle seed: " << util::toString(seed) << "

\n"; } resultsPage << "
\n"; } // Script resultsPage << resultsScript; // Tests resultsPage << "
\n"; const auto appendResult = [&] (const auto& results, const std::string& status, bool hide = false) { for (const auto& result : results) { resultsPage << createResultItem(result, status, hide); } }; appendResult(stats.passed, "passed"s, unsuccessful); appendResult(stats.failed, "failed"s); appendResult(stats.errored, "errored"s); appendResult(stats.ignorePassed, "ignored passed"s, unsuccessful); appendResult(stats.ignoreFailed, "ignored"s, true); resultsPage << "
\n"; return resultsPage.str(); } } // namespace void printStats(const TestStats& stats) { const std::size_t count = stats.testCount(); if (std::size_t passedTests = stats.passed.size()) { printf(ANSI_COLOR_GREEN "%zu passed (%.1lf%%)" ANSI_COLOR_RESET "\n", passedTests, 100.0 * passedTests / count); } if (std::size_t ignorePassedTests = stats.ignorePassed.size()) { printf(ANSI_COLOR_YELLOW "%zu passed but were ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", ignorePassedTests, 100.0 * ignorePassedTests / count); } if (std::size_t ignoreFailedTests = stats.ignoreFailed.size()) { printf(ANSI_COLOR_LIGHT_GRAY "%zu ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", ignoreFailedTests, 100.0 * ignoreFailedTests / count); } if (std::size_t failedTests = stats.failed.size()) { printf(ANSI_COLOR_RED "%zu failed (%.1lf%%)" ANSI_COLOR_RESET "\n", failedTests, 100.0 * failedTests / count); } if (std::size_t erroredTests = stats.errored.size()) { printf(ANSI_COLOR_RED "%zu errored (%.1lf%%)" ANSI_COLOR_RESET "\n", erroredTests, 100.0 * erroredTests / count); } } void writeHTMLResults(const TestStats& stats, const std::string& rootPath, bool shuffle, uint32_t seed) { filesystem::path path = filesystem::path(rootPath) / "index.html"s; try { util::write_file(path.string(), createResultPage(stats, shuffle, seed)); printf("Results at: %s\n", path.string().c_str()); } catch (std::exception&) { printf(ANSI_COLOR_RED "* ERROR can't write result page %s" ANSI_COLOR_RESET "\n", path.string().c_str()); } }