1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 02:47:34 +00:00

LibTest: Provide detailed per-file JSON output with --per-file

This makes test-js style runners dump out output in the same format as
libjs-test262's per-file output.
This commit is contained in:
Ali Mohammad Pur 2022-03-08 07:09:41 +03:30 committed by Linus Groh
parent 3063aedb0c
commit 8b50009e9b
6 changed files with 100 additions and 28 deletions

View file

@ -29,11 +29,12 @@ public:
return s_the;
}
TestRunner(String test_root, bool print_times, bool print_progress, bool print_json)
TestRunner(String test_root, bool print_times, bool print_progress, bool print_json, bool detailed_json = false)
: m_test_root(move(test_root))
, m_print_times(print_times)
, m_print_progress(print_progress)
, m_print_json(print_json)
, m_detailed_json(detailed_json)
{
VERIFY(!s_the);
s_the = this;
@ -47,6 +48,16 @@ public:
bool is_printing_progress() const { return m_print_progress; }
bool needs_detailed_suites() const { return m_detailed_json; }
Vector<Test::Suite> const& suites() const { return *m_suites; }
Vector<Test::Suite>& ensure_suites()
{
if (!m_suites.has_value())
m_suites = Vector<Suite> {};
return *m_suites;
}
protected:
static TestRunner* s_the;
@ -61,9 +72,11 @@ protected:
bool m_print_times;
bool m_print_progress;
bool m_print_json;
bool m_detailed_json;
double m_total_elapsed_time_in_ms { 0 };
Test::Counts m_counts;
Optional<Vector<Test::Suite>> m_suites;
};
inline void cleanup()
@ -223,26 +236,63 @@ inline void TestRunner::print_test_results() const
inline void TestRunner::print_test_results_as_json() const
{
JsonObject suites;
suites.set("failed", m_counts.suites_failed);
suites.set("passed", m_counts.suites_passed);
suites.set("total", m_counts.suites_failed + m_counts.suites_passed);
JsonObject tests;
tests.set("failed", m_counts.tests_failed);
tests.set("passed", m_counts.tests_passed);
tests.set("skipped", m_counts.tests_skipped);
tests.set("total", m_counts.tests_failed + m_counts.tests_passed + m_counts.tests_skipped);
JsonObject results;
results.set("suites", suites);
results.set("tests", tests);
JsonObject root;
root.set("results", results);
root.set("files_total", m_counts.files_total);
root.set("duration", m_total_elapsed_time_in_ms / 1000.0);
if (needs_detailed_suites()) {
auto& suites = this->suites();
u64 duration_us = 0;
JsonObject tests;
for (auto& suite : suites) {
for (auto& case_ : suite.tests) {
duration_us += case_.duration_us;
StringView result_name;
switch (case_.result) {
case Result::Pass:
result_name = "PASSED";
break;
case Result::Fail:
result_name = "FAILED";
break;
case Result::Skip:
result_name = "SKIPPED";
break;
case Result::Crashed:
result_name = "PROCESS_ERROR";
break;
}
auto name = suite.name;
if (name == "__$$TOP_LEVEL$$__"sv)
name = String::empty();
auto path = LexicalPath::relative_path(suite.path, m_test_root);
tests.set(String::formatted("{}/{}::{}", path, name, case_.name), result_name);
}
}
root.set("duration", static_cast<double>(duration_us) / 1000000.);
root.set("results", move(tests));
} else {
JsonObject suites;
suites.set("failed", m_counts.suites_failed);
suites.set("passed", m_counts.suites_passed);
suites.set("total", m_counts.suites_failed + m_counts.suites_passed);
JsonObject tests;
tests.set("failed", m_counts.tests_failed);
tests.set("passed", m_counts.tests_passed);
tests.set("skipped", m_counts.tests_skipped);
tests.set("total", m_counts.tests_failed + m_counts.tests_passed + m_counts.tests_skipped);
JsonObject results;
results.set("suites", suites);
results.set("tests", tests);
root.set("results", results);
root.set("files_total", m_counts.files_total);
root.set("duration", m_total_elapsed_time_in_ms / 1000.0);
}
outln("{}", root.to_string());
}