mtest: Allow filtering tests by subproject

You could always specify a list of tests to run by passing the names as
arguments to `meson test`. If there were multiple tests with that name (in the
same project or different subprojects), all of them would be run. Now you can:

1. Run all tests with the specified name from a specific subproject: `meson test subprojname:testname`
1. Run all tests defined in a specific subproject: `meson test subprojectname:`

Also forbid ':' in test names. We already forbid this elsewhere, so
should not be a big deal.
pull/7841/head
Nirbheek Chauhan 5 years ago committed by Jussi Pakkanen
parent dccff1f2bc
commit 55cf399ff8
  1. 18
      docs/markdown/snippets/mtest_test_list_subprojects.md
  2. 13
      mesonbuild/interpreter.py
  3. 29
      mesonbuild/mtest.py

@ -0,0 +1,18 @@
## `meson test` can now filter tests by subproject
You could always specify a list of tests to run by passing the names as
arguments to `meson test`. If there were multiple tests with that name (in the
same project or different subprojects), all of them would be run. Now you can:
1. Run all tests with the specified name from a specific subproject: `meson test subprojname:testname`
1. Run all tests defined in a specific subproject: `meson test subprojectname:`
As before, these can all be specified multiple times and mixed:
```sh
# Run:
# * All tests called 'name1' or 'name2' and
# * All tests called 'name3' in subproject 'bar' and
# * All tests in subproject 'foo'
$ meson test name1 name2 bar:name3 foo:
```

@ -4074,8 +4074,13 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
def add_test(self, node, args, kwargs, is_base_test):
if len(args) != 2:
raise InterpreterException('test expects 2 arguments, {} given'.format(len(args)))
if not isinstance(args[0], str):
name = args[0]
if not isinstance(name, str):
raise InterpreterException('First argument of test must be a string.')
if ':' in name:
mlog.deprecation('":" is not allowed in test name "{}", it has been replaced with "_"'.format(name),
location=node)
name = name.replace(':', '_')
exe = args[1]
if not isinstance(exe, (ExecutableHolder, JarHolder, ExternalProgramHolder)):
if isinstance(exe, mesonlib.File):
@ -4120,14 +4125,14 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
priority = kwargs.get('priority', 0)
if not isinstance(priority, int):
raise InterpreterException('Keyword argument priority must be an integer.')
t = Test(args[0], prj, suite, exe.held_object, depends, par, cmd_args,
t = Test(name, prj, suite, exe.held_object, depends, par, cmd_args,
env, should_fail, timeout, workdir, protocol, priority)
if is_base_test:
self.build.tests.append(t)
mlog.debug('Adding test', mlog.bold(args[0], True))
mlog.debug('Adding test', mlog.bold(name, True))
else:
self.build.benchmarks.append(t)
mlog.debug('Adding benchmark', mlog.bold(args[0], True))
mlog.debug('Adding benchmark', mlog.bold(name, True))
@FeatureNewKwargs('install_headers', '0.47.0', ['install_mode'])
@permittedKwargs(permitted_kwargs['install_headers'])

@ -124,7 +124,9 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
parser.add_argument('--test-args', default=[], type=split_args,
help='Arguments to pass to the specified test(s) or all tests')
parser.add_argument('args', nargs='*',
help='Optional list of tests to run')
help='Optional list of test names to run. "testname" to run all tests with that name, '
'"subprojname:testname" to specifically run "testname" from "subprojname", '
'"subprojname:" to run all tests defined by "subprojname".')
def returncode_to_status(retcode: int) -> str:
@ -1039,6 +1041,28 @@ class TestHarness:
TestHarness.test_in_suites(test, self.options.include_suites)) and not
TestHarness.test_in_suites(test, self.options.exclude_suites))
def tests_from_args(self, tests: T.List[TestSerialisation]) -> T.Generator[TestSerialisation, None, None]:
'''
Allow specifying test names like "meson test foo1 foo2", where test('foo1', ...)
Also support specifying the subproject to run tests from like
"meson test subproj:" (all tests inside subproj) or "meson test subproj:foo1"
to run foo1 inside subproj. Coincidentally also "meson test :foo1" to
run all tests with that name across all subprojects, which is
identical to "meson test foo1"
'''
for arg in self.options.args:
if ':' in arg:
subproj, name = arg.split(':', maxsplit=1)
else:
subproj, name = '', arg
for t in tests:
if subproj and t.project_name != subproj:
continue
if name and t.name != name:
continue
yield t
def get_tests(self) -> T.List[TestSerialisation]:
if not self.tests:
print('No tests defined.')
@ -1052,9 +1076,8 @@ class TestHarness:
else:
tests = self.tests
# allow specifying test names like "meson test foo1 foo2", where test('foo1', ...)
if self.options.args:
tests = [t for t in tests if t.name in self.options.args]
tests = list(self.tests_from_args(tests))
if not tests:
print('No suitable tests defined.')

Loading…
Cancel
Save