headless-browser: Allow the -f argument to be used multiple times

A test path is now included if it matches any of the given globs.
This commit is contained in:
Tim Ledbetter 2025-02-04 19:23:11 +00:00 committed by Tim Flynn
commit 39e17e83f9
Notes: github-actions[bot] 2025-02-05 12:27:58 +00:00
5 changed files with 19 additions and 12 deletions

View file

@ -89,7 +89,7 @@ int main(int argc, char** argv)
bool per_file = false; bool per_file = false;
StringView specified_test_root; StringView specified_test_root;
ByteString common_path; ByteString common_path;
ByteString test_glob; Vector<ByteString> test_globs;
Core::ArgsParser args_parser; Core::ArgsParser args_parser;
args_parser.add_option(print_times, "Show duration of each test", "show-time", 't'); args_parser.add_option(print_times, "Show duration of each test", "show-time", 't');
@ -113,7 +113,7 @@ int main(int argc, char** argv)
args_parser.add_option(per_file, "Show detailed per-file results as JSON (implies -j)", "per-file"); args_parser.add_option(per_file, "Show detailed per-file results as JSON (implies -j)", "per-file");
args_parser.add_option(g_collect_on_every_allocation, "Collect garbage after every allocation", "collect-often", 'g'); args_parser.add_option(g_collect_on_every_allocation, "Collect garbage after every allocation", "collect-often", 'g');
args_parser.add_option(JS::Bytecode::g_dump_bytecode, "Dump the bytecode", "dump-bytecode", 'd'); args_parser.add_option(JS::Bytecode::g_dump_bytecode, "Dump the bytecode", "dump-bytecode", 'd');
args_parser.add_option(test_glob, "Only run tests matching the given glob", "filter", 'f', "glob"); args_parser.add_option(test_globs, "Only run tests matching the given glob", "filter", 'f', "glob");
for (auto& entry : g_extra_args) for (auto& entry : g_extra_args)
args_parser.add_option(*entry.key, entry.value.get<0>().characters(), entry.value.get<1>().characters(), entry.value.get<2>()); args_parser.add_option(*entry.key, entry.value.get<0>().characters(), entry.value.get<1>().characters(), entry.value.get<2>());
args_parser.add_positional_argument(specified_test_root, "Tests root directory", "path", Core::ArgsParser::Required::No); args_parser.add_positional_argument(specified_test_root, "Tests root directory", "path", Core::ArgsParser::Required::No);
@ -123,7 +123,10 @@ int main(int argc, char** argv)
if (per_file) if (per_file)
print_json = true; print_json = true;
test_glob = ByteString::formatted("*{}*", test_glob); for (auto& glob : test_globs)
glob = ByteString::formatted("*{}*", glob);
if (test_globs.is_empty())
test_globs.append("*"sv);
if (getenv("DISABLE_DBG_OUTPUT")) { if (getenv("DISABLE_DBG_OUTPUT")) {
AK::set_debug_enabled(false); AK::set_debug_enabled(false);
@ -185,7 +188,7 @@ int main(int argc, char** argv)
} }
Test::JS::TestRunner test_runner(test_root, common_path, print_times, print_progress, print_json, per_file); Test::JS::TestRunner test_runner(test_root, common_path, print_times, print_progress, print_json, per_file);
test_runner.run(test_glob); test_runner.run(test_globs);
g_vm = nullptr; g_vm = nullptr;

View file

@ -42,7 +42,7 @@ public:
virtual ~TestRunner() { s_the = nullptr; } virtual ~TestRunner() { s_the = nullptr; }
virtual void run(ByteString test_glob); virtual void run(ReadonlySpan<ByteString> test_globs);
Test::Counts const& counts() const { return m_counts; } Test::Counts const& counts() const { return m_counts; }
@ -92,12 +92,12 @@ inline void cleanup()
exit(1); exit(1);
} }
inline void TestRunner::run(ByteString test_glob) inline void TestRunner::run(ReadonlySpan<ByteString> test_globs)
{ {
size_t progress_counter = 0; size_t progress_counter = 0;
auto test_paths = get_test_paths(); auto test_paths = get_test_paths();
for (auto& path : test_paths) { for (auto& path : test_paths) {
if (!path.matches(test_glob)) if (!any_of(test_globs, [&](auto& glob) { return path.matches(glob); }))
continue; continue;
++progress_counter; ++progress_counter;
do_run_single_test(path, progress_counter, test_paths.size()); do_run_single_test(path, progress_counter, test_paths.size());

View file

@ -37,7 +37,7 @@ void Application::create_platform_arguments(Core::ArgsParser& args_parser)
args_parser.add_option(test_concurrency, "Maximum number of tests to run at once", "test-concurrency", 'j', "jobs"); args_parser.add_option(test_concurrency, "Maximum number of tests to run at once", "test-concurrency", 'j', "jobs");
args_parser.add_option(python_executable_path, "Path to python3", "python-executable", 'P', "path"); args_parser.add_option(python_executable_path, "Path to python3", "python-executable", 'P', "path");
args_parser.add_option(test_root_path, "Run tests in path", "run-tests", 'R', "test-root-path"); args_parser.add_option(test_root_path, "Run tests in path", "run-tests", 'R', "test-root-path");
args_parser.add_option(test_glob, "Only run tests matching the given glob", "filter", 'f', "glob"); args_parser.add_option(test_globs, "Only run tests matching the given glob", "filter", 'f', "glob");
args_parser.add_option(test_dry_run, "List the tests that would be run, without running them", "dry-run"); args_parser.add_option(test_dry_run, "List the tests that would be run, without running them", "dry-run");
args_parser.add_option(dump_failed_ref_tests, "Dump screenshots of failing ref tests", "dump-failed-ref-tests", 'D'); args_parser.add_option(dump_failed_ref_tests, "Dump screenshots of failing ref tests", "dump-failed-ref-tests", 'D');
args_parser.add_option(dump_gc_graph, "Dump GC graph", "dump-gc-graph", 'G'); args_parser.add_option(dump_gc_graph, "Dump GC graph", "dump-gc-graph", 'G');

View file

@ -58,7 +58,7 @@ public:
size_t test_concurrency { 1 }; size_t test_concurrency { 1 };
ByteString python_executable_path; ByteString python_executable_path;
ByteString test_root_path; ByteString test_root_path;
ByteString test_glob; Vector<ByteString> test_globs;
bool test_dry_run { false }; bool test_dry_run { false };
bool rebaseline { false }; bool rebaseline { false };
u8 verbosity { 0 }; u8 verbosity { 0 };

View file

@ -469,7 +469,11 @@ ErrorOr<void> run_tests(Core::AnonymousBuffer const& theme, Web::DevicePixelSize
TRY(load_test_config(app.test_root_path)); TRY(load_test_config(app.test_root_path));
Vector<Test> tests; Vector<Test> tests;
auto test_glob = ByteString::formatted("*{}*", app.test_glob);
for (auto& glob : app.test_globs)
glob = ByteString::formatted("*{}*", glob);
if (app.test_globs.is_empty())
app.test_globs.append("*"sv);
TRY(collect_dump_tests(app, tests, ByteString::formatted("{}/Layout", app.test_root_path), "."sv, TestMode::Layout)); TRY(collect_dump_tests(app, tests, ByteString::formatted("{}/Layout", app.test_root_path), "."sv, TestMode::Layout));
TRY(collect_dump_tests(app, tests, ByteString::formatted("{}/Text", app.test_root_path), "."sv, TestMode::Text)); TRY(collect_dump_tests(app, tests, ByteString::formatted("{}/Text", app.test_root_path), "."sv, TestMode::Text));
@ -486,7 +490,7 @@ ErrorOr<void> run_tests(Core::AnonymousBuffer const& theme, Web::DevicePixelSize
"*/wpt-import/common/*"sv, "*/wpt-import/common/*"sv,
}; };
bool is_support_file = any_of(support_file_patterns, [&](auto pattern) { return test.input_path.matches(pattern); }); bool is_support_file = any_of(support_file_patterns, [&](auto pattern) { return test.input_path.matches(pattern); });
bool match_glob = test.input_path.matches(test_glob, CaseSensitivity::CaseSensitive); bool match_glob = any_of(app.test_globs, [&](auto const& glob) { return test.relative_path.matches(glob, CaseSensitivity::CaseSensitive); });
return is_support_file || !match_glob; return is_support_file || !match_glob;
}); });
@ -500,7 +504,7 @@ ErrorOr<void> run_tests(Core::AnonymousBuffer const& theme, Web::DevicePixelSize
} }
if (tests.is_empty()) { if (tests.is_empty()) {
if (app.test_glob.is_empty()) if (app.test_globs.is_empty())
return Error::from_string_literal("No tests found"); return Error::from_string_literal("No tests found");
return Error::from_string_literal("No tests found matching filter"); return Error::from_string_literal("No tests found matching filter");
} }