mtest: wildcard selection

Allow the use of wildcards (e.g. *) to match test names in `meson test`.

Raise an error is given test name does not match any test.

Optimize the search by looping through the list of tests only once.
pull/11818/head
Charles Brunet 2 years ago committed by Eli Schwartz
parent 11521c6db7
commit e7b9dfac98
  1. 6
      docs/markdown/Commands.md
  2. 21
      docs/markdown/Unit-tests.md
  3. 9
      docs/markdown/snippets/test_name_filters.md
  4. 46
      mesonbuild/mtest.py
  5. 24
      unittests/allplatformstests.py

@ -281,6 +281,12 @@ Run tests for the configure Meson project.
See [the unit test documentation](Unit-tests.md) for more info.
Since *1.2.0* you can use wildcards in *args* for test names.
For example, "bas*" will match all test with names beginning with "bas".
Since *1.2.0* it is an error to provide a test name or wildcard that
does not match any test.
#### Examples:
Run tests for the project:

@ -153,6 +153,27 @@ Specify test(s) by name like:
$ meson test A D
```
You can run tests from specific (sub)project:
```console
$ meson test (sub)project_name:
```
or a specific test in a specific project:
```console
$ meson test (sub)project_name:test_name
```
Since version *1.2.0*, you can use wildcards in project
and test names. For instance, to run all tests beginning with
"foo" and all tests from projects beginning with "bar":
```console
$ meson test "foo*" "bar*:"
```
Tests belonging to a suite `suite` can be run as follows
```console

@ -0,0 +1,9 @@
## Wildcards in list of tests to run
The `meson test` command now accepts wildcards in the list of test names.
For example `meson test basic*` will run all tests whose name begins
with "basic".
meson will report an error if the given test name does not match any
existing test. meson will log a warning if two redundant test names
are given (for example if you give both "proj:basic" and "proj:").

@ -19,6 +19,7 @@ from pathlib import Path
from collections import deque
from contextlib import suppress
from copy import deepcopy
from fnmatch import fnmatch
import argparse
import asyncio
import datetime
@ -1859,17 +1860,48 @@ class TestHarness:
run all tests with that name across all subprojects, which is
identical to "meson test foo1"
'''
patterns: T.Dict[T.Tuple[str, str], bool] = {}
for arg in self.options.args:
# Replace empty components by wildcards:
# '' -> '*:*'
# 'name' -> '*:name'
# ':name' -> '*:name'
# 'proj:' -> 'proj:*'
if ':' in arg:
subproj, name = arg.split(':', maxsplit=1)
if name == '':
name = '*'
if subproj == '': # in case arg was ':'
subproj = '*'
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
subproj, name = '*', arg
patterns[(subproj, name)] = False
for t in tests:
# For each test, find the first matching pattern
# and mark it as used. yield the matching tests.
for subproj, name in list(patterns):
if fnmatch(t.project_name, subproj) and fnmatch(t.name, name):
patterns[(subproj, name)] = True
yield t
break
for (subproj, name), was_used in patterns.items():
if not was_used:
# For each unused pattern...
arg = f'{subproj}:{name}'
for t in tests:
# ... if it matches a test, then it wasn't used because another
# pattern matched the same test before.
# Report it as a warning.
if fnmatch(t.project_name, subproj) and fnmatch(t.name, name):
mlog.warning(f'{arg} test name is redundant and was not used')
break
else:
# If the pattern doesn't match any test,
# report it as an error. We don't want the `test` command to
# succeed on an invalid pattern.
raise MesonException(f'{arg} test name does not match any test')
def get_tests(self) -> T.List[TestSerialisation]:
if not self.tests:

@ -818,6 +818,30 @@ class AllPlatformTests(BasePlatformTests):
o = self._run(self.mtest_command + ['--list', '--no-rebuild'])
self.assertNotIn('Regenerating build files.', o)
def test_unexisting_test_name(self):
testdir = os.path.join(self.unit_test_dir, '4 suite selection')
self.init(testdir)
self.build()
self.assertRaises(subprocess.CalledProcessError, self._run, self.mtest_command + ['notatest'])
def test_select_test_using_wildcards(self):
testdir = os.path.join(self.unit_test_dir, '4 suite selection')
self.init(testdir)
self.build()
o = self._run(self.mtest_command + ['--list', 'mainprj*'])
self.assertIn('mainprj-failing_test', o)
self.assertIn('mainprj-successful_test_no_suite', o)
self.assertNotIn('subprj', o)
o = self._run(self.mtest_command + ['--list', '*succ*', 'subprjm*:'])
self.assertIn('mainprj-successful_test_no_suite', o)
self.assertIn('subprjmix-failing_test', o)
self.assertIn('subprjmix-successful_test', o)
self.assertIn('subprjsucc-successful_test_no_suite', o)
self.assertNotIn('subprjfail-failing_test', o)
def test_build_by_default(self):
testdir = os.path.join(self.common_test_dir, '129 build by default')
self.init(testdir)

Loading…
Cancel
Save