diff --git a/Libraries/LibTest/JavaScriptTestRunnerMain.cpp b/Libraries/LibTest/JavaScriptTestRunnerMain.cpp index 875661cccbd..3d135eb5f0c 100644 --- a/Libraries/LibTest/JavaScriptTestRunnerMain.cpp +++ b/Libraries/LibTest/JavaScriptTestRunnerMain.cpp @@ -89,7 +89,7 @@ int main(int argc, char** argv) bool per_file = false; StringView specified_test_root; ByteString common_path; - ByteString test_glob; + Vector test_globs; Core::ArgsParser args_parser; 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(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(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) 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); @@ -123,7 +123,10 @@ int main(int argc, char** argv) if (per_file) 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")) { 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_runner.run(test_glob); + test_runner.run(test_globs); g_vm = nullptr; diff --git a/Libraries/LibTest/TestRunner.h b/Libraries/LibTest/TestRunner.h index 216973b41ed..7719809f84f 100644 --- a/Libraries/LibTest/TestRunner.h +++ b/Libraries/LibTest/TestRunner.h @@ -42,7 +42,7 @@ public: virtual ~TestRunner() { s_the = nullptr; } - virtual void run(ByteString test_glob); + virtual void run(ReadonlySpan test_globs); Test::Counts const& counts() const { return m_counts; } @@ -92,12 +92,12 @@ inline void cleanup() exit(1); } -inline void TestRunner::run(ByteString test_glob) +inline void TestRunner::run(ReadonlySpan test_globs) { size_t progress_counter = 0; auto test_paths = get_test_paths(); for (auto& path : test_paths) { - if (!path.matches(test_glob)) + if (!any_of(test_globs, [&](auto& glob) { return path.matches(glob); })) continue; ++progress_counter; do_run_single_test(path, progress_counter, test_paths.size()); diff --git a/UI/Headless/Application.cpp b/UI/Headless/Application.cpp index cd1103825d2..a6382867475 100644 --- a/UI/Headless/Application.cpp +++ b/UI/Headless/Application.cpp @@ -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(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_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(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'); diff --git a/UI/Headless/Application.h b/UI/Headless/Application.h index 7ac5874004a..9640235a715 100644 --- a/UI/Headless/Application.h +++ b/UI/Headless/Application.h @@ -58,7 +58,7 @@ public: size_t test_concurrency { 1 }; ByteString python_executable_path; ByteString test_root_path; - ByteString test_glob; + Vector test_globs; bool test_dry_run { false }; bool rebaseline { false }; u8 verbosity { 0 }; diff --git a/UI/Headless/Test.cpp b/UI/Headless/Test.cpp index 01e471a9420..48b3f8bfc30 100644 --- a/UI/Headless/Test.cpp +++ b/UI/Headless/Test.cpp @@ -469,7 +469,11 @@ ErrorOr run_tests(Core::AnonymousBuffer const& theme, Web::DevicePixelSize TRY(load_test_config(app.test_root_path)); Vector 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("{}/Text", app.test_root_path), "."sv, TestMode::Text)); @@ -486,7 +490,7 @@ ErrorOr run_tests(Core::AnonymousBuffer const& theme, Web::DevicePixelSize "*/wpt-import/common/*"sv, }; 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; }); @@ -500,7 +504,7 @@ ErrorOr run_tests(Core::AnonymousBuffer const& theme, Web::DevicePixelSize } 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 matching filter"); }