summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbheek Chauhan <nirbheek@centricular.com>2020-08-13 21:35:31 +0530
committerJussi Pakkanen <jpakkane@gmail.com>2020-10-13 19:01:15 +0300
commit55cf399ff8b9c15300f26dd1a46045dda7d49f98 (patch)
treef0091f06afbd07c800306ea2a1237897e3e6f897
parentdccff1f2bcf6e7b8e42fa7bea63b8532ad29b43a (diff)
downloadmeson-55cf399ff8b9c15300f26dd1a46045dda7d49f98.tar.gz
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.
-rw-r--r--docs/markdown/snippets/mtest_test_list_subprojects.md18
-rw-r--r--mesonbuild/interpreter.py13
-rw-r--r--mesonbuild/mtest.py29
3 files changed, 53 insertions, 7 deletions
diff --git a/docs/markdown/snippets/mtest_test_list_subprojects.md b/docs/markdown/snippets/mtest_test_list_subprojects.md
new file mode 100644
index 000000000..a8dbf4c89
--- /dev/null
+++ b/docs/markdown/snippets/mtest_test_list_subprojects.md
@@ -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:
+```
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index ca1411e4a..be19af359 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -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'])
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index caf403922..a5c2dda21 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -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.')