From 8cfd82f55c0107564bc15faaa4a8e11e4e5eeebd Mon Sep 17 00:00:00 2001 From: shuppy Date: Thu, 7 Aug 2025 21:23:53 +0800 Subject: [PATCH] mach: Allow filtering tests in `mach test-devtools` (#38514) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `mach test-devtools` uses [unittest](https://docs.python.org/3/library/unittest.html) without [unittest.main()](https://docs.python.org/3/library/unittest.html#unittest.main), so we can parse arguments and set up the test runner how we want, but this means there’s currently no way to filter tests on the command line. this patch plumbs the positional arguments (if any) into the TestLoader’s [testNamePatterns](https://docs.python.org/3/library/unittest.html#unittest.TestLoader.testNamePatterns), with extra logic to treat any pattern `pattern` not containing `*` like `*pattern*`. this is the same behaviour as unittest.main() [`-k`](https://docs.python.org/3/library/unittest.html#cmdoption-unittest-k): ``` $ ./mach test-devtools domparser responsexml Running devtools tests... Running 2 tests: - test_source_content_inline_script_with_domparser (servo.devtools_tests.DevtoolsTests.test_source_content_inline_script_with_domparser) - test_source_content_inline_script_with_responsexml (servo.devtools_tests.DevtoolsTests.test_source_content_inline_script_with_responsexml) test_source_content_inline_script_with_domparser (servo.devtools_tests.DevtoolsTests.test_source_content_inline_script_with_domparser) ... ok test_source_content_inline_script_with_responsexml (servo.devtools_tests.DevtoolsTests.test_source_content_inline_script_with_responsexml) ... ok ---------------------------------------------------------------------- Ran 2 tests in 4.055s OK ``` Testing: not really worth automated testing, but tested manually above Fixes: part of #36325 --------- Signed-off-by: Delan Azabani --- python/servo/devtools_tests.py | 18 ++++++++++++++++-- python/servo/testing_commands.py | 5 +++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/python/servo/devtools_tests.py b/python/servo/devtools_tests.py index 825f52eb3b0..556350d73a3 100644 --- a/python/servo/devtools_tests.py +++ b/python/servo/devtools_tests.py @@ -317,9 +317,23 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): return os.path.join(DevtoolsTests.script_path, os.path.join("devtools_tests", path)) -def run_tests(script_path, build_type: BuildType): +def run_tests(script_path, build_type: BuildType, test_names: list[str]): DevtoolsTests.script_path = script_path DevtoolsTests.build_type = build_type verbosity = 1 if logging.getLogger().level >= logging.WARN else 2 - suite = unittest.TestLoader().loadTestsFromTestCase(DevtoolsTests) + loader = unittest.TestLoader() + if test_names: + patterns = [] + # unittest.main() `-k` treats any `pattern` not containing `*` like `*pattern*` + for pattern in test_names: + if "*" in pattern: + patterns.append(pattern) + else: + patterns.append(f"*{pattern}*") + loader.testNamePatterns = patterns + suite = loader.loadTestsFromTestCase(DevtoolsTests) + print(f"Running {suite.countTestCases()} tests:") + for test in suite: + print(f"- {test}") + print() return unittest.TextTestRunner(verbosity=verbosity).run(suite).wasSuccessful() diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index 5fdc3b9b0db..4ed241aea49 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -355,10 +355,11 @@ class MachCommands(CommandBase): return 0 if passed else 1 @Command("test-devtools", description="Run tests for devtools.", category="testing") + @CommandArgument("test_names", nargs=argparse.REMAINDER, help="Only run tests that match these patterns") @CommandBase.common_command_arguments(build_type=True) - def test_devtools(self, build_type: BuildType, **kwargs) -> int: + def test_devtools(self, build_type: BuildType, test_names: list[str], **kwargs) -> int: print("Running devtools tests...") - passed = servo.devtools_tests.run_tests(SCRIPT_PATH, build_type) + passed = servo.devtools_tests.run_tests(SCRIPT_PATH, build_type, test_names) return 0 if passed else 1 @Command(