aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/mtest.py
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2021-01-06 00:05:48 +0000
committerGitHub <noreply@github.com>2021-01-06 00:05:48 +0000
commitc9d9dacdbc9fad31f00f871b24ec6b99a611ff5e (patch)
tree07ea0773d50c41e3e87081e1be6095a7788da9df /mesonbuild/mtest.py
parentf9dd75f213b1c3a7ab397133b6a157ddba511d90 (diff)
parent827fa95de1c619b51457c5a04297b6ce9adc2177 (diff)
downloadmeson-c9d9dacdbc9fad31f00f871b24ec6b99a611ff5e.zip
meson-c9d9dacdbc9fad31f00f871b24ec6b99a611ff5e.tar.gz
meson-c9d9dacdbc9fad31f00f871b24ec6b99a611ff5e.tar.bz2
Merge pull request #7860 from dcbaker/wip/2020-10/rust-module
Add a rust module
Diffstat (limited to 'mesonbuild/mtest.py')
-rw-r--r--mesonbuild/mtest.py73
1 files changed, 56 insertions, 17 deletions
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 7e3ebea..9db271e 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -595,17 +595,17 @@ class JunitBuilder(TestLogger):
'testsuite',
name=suitename,
tests=str(len(test.results)),
- errors=str(sum(1 for r in test.results if r in
+ errors=str(sum(1 for r in test.results.values() if r in
{TestResult.INTERRUPT, TestResult.ERROR})),
- failures=str(sum(1 for r in test.results if r in
+ failures=str(sum(1 for r in test.results.values() if r in
{TestResult.FAIL, TestResult.UNEXPECTEDPASS, TestResult.TIMEOUT})),
- skipped=str(sum(1 for r in test.results if r is TestResult.SKIP)),
+ skipped=str(sum(1 for r in test.results.values() if r is TestResult.SKIP)),
)
- for i, result in enumerate(test.results):
+ for i, result in test.results.items():
# Both name and classname are required. Set them both to the
# number of the test in a TAP test, as TAP doesn't give names.
- testcase = et.SubElement(suite, 'testcase', name=str(i), classname=str(i))
+ testcase = et.SubElement(suite, 'testcase', name=i, classname=i)
if result is TestResult.SKIP:
et.SubElement(testcase, 'skipped')
elif result is TestResult.ERROR:
@@ -666,6 +666,28 @@ class JunitBuilder(TestLogger):
tree.write(f, encoding='utf-8', xml_declaration=True)
+def parse_rust_test(stdout: str) -> T.Dict[str, TestResult]:
+ """Parse the output of rust tests."""
+ res = {} # type; T.Dict[str, TestResult]
+
+ def parse_res(res: str) -> TestResult:
+ if res == 'ok':
+ return TestResult.OK
+ elif res == 'ignored':
+ return TestResult.SKIP
+ elif res == 'FAILED':
+ return TestResult.FAIL
+ raise MesonException('Unsupported output from rust test: {}'.format(res))
+
+ for line in stdout.splitlines():
+ if line.startswith('test ') and not line.startswith('test result'):
+ _, name, _, result = line.split(' ')
+ name = name.replace('::', '.')
+ res[name] = parse_res(result)
+
+ return res
+
+
class TestRun:
TEST_NUM = 0
@@ -675,7 +697,7 @@ class TestRun:
self.test = test
self._num = None # type: T.Optional[int]
self.name = name
- self.results = list() # type: T.List[TestResult]
+ self.results: T.Dict[str, TestResult] = {}
self.returncode = 0
self.starttime = None # type: T.Optional[float]
self.duration = None # type: T.Optional[float]
@@ -713,23 +735,23 @@ class TestRun:
res = TestResult.EXPECTEDFAIL if bool(returncode) else TestResult.UNEXPECTEDPASS
else:
res = TestResult.FAIL if bool(returncode) else TestResult.OK
- self.complete(res, [], returncode, stdo, stde, cmd, **kwargs)
+ self.complete(res, {}, returncode, stdo, stde, cmd, **kwargs)
def complete_tap(self, returncode: int, stdo: str, stde: str, cmd: T.List[str]) -> None:
res = None # type: T.Optional[TestResult]
- results = [] # type: T.List[TestResult]
+ results = {} # type: T.Dict[str, TestResult]
failed = False
- for i in TAPParser(io.StringIO(stdo)).parse():
+ for n, i in enumerate(TAPParser(io.StringIO(stdo)).parse()):
if isinstance(i, TAPParser.Bailout):
- results.append(TestResult.ERROR)
+ results[str(n)] = TestResult.ERROR
failed = True
elif isinstance(i, TAPParser.Test):
- results.append(i.result)
+ results[str(n)] = i.result
if i.result not in {TestResult.OK, TestResult.EXPECTEDFAIL, TestResult.SKIP}:
failed = True
elif isinstance(i, TAPParser.Error):
- results.append(TestResult.ERROR)
+ results[str(n)] = TestResult.ERROR
stde += '\nTAP parsing error: ' + i.message
failed = True
@@ -739,7 +761,7 @@ class TestRun:
if res is None:
# Now determine the overall result of the test based on the outcome of the subcases
- if all(t is TestResult.SKIP for t in results):
+ if all(t is TestResult.SKIP for t in results.values()):
# This includes the case where num_tests is zero
res = TestResult.SKIP
elif self.should_fail:
@@ -749,6 +771,21 @@ class TestRun:
self.complete(res, results, returncode, stdo, stde, cmd)
+ def complete_rust(self, returncode: int, stdo: str, stde: str, cmd: T.List[str]) -> None:
+ results = parse_rust_test(stdo)
+
+ failed = TestResult.FAIL in results.values()
+ # Now determine the overall result of the test based on the outcome of the subcases
+ if all(t is TestResult.SKIP for t in results.values()):
+ # This includes the case where num_tests is zero
+ res = TestResult.SKIP
+ elif self.should_fail:
+ res = TestResult.EXPECTEDFAIL if failed else TestResult.UNEXPECTEDPASS
+ else:
+ res = TestResult.FAIL if failed else TestResult.OK
+
+ self.complete(res, results, returncode, stdo, stde, cmd)
+
@property
def num(self) -> int:
if self._num is None:
@@ -756,13 +793,13 @@ class TestRun:
self._num = TestRun.TEST_NUM
return self._num
- def complete(self, res: TestResult, results: T.List[TestResult],
+ def complete(self, res: TestResult, results: T.Dict[str, TestResult],
returncode: int,
stdo: T.Optional[str], stde: T.Optional[str],
cmd: T.List[str], *, junit: T.Optional[et.ElementTree] = None) -> None:
assert isinstance(res, TestResult)
self.res = res
- self.results = results
+ self.results = results # May be empty
self.returncode = returncode
self.duration = time.time() - self.starttime
self.stdo = stdo
@@ -906,7 +943,7 @@ class SingleTestRunner:
self.runobj.start()
if cmd is None:
skip_stdout = 'Not run because can not execute cross compiled binaries.'
- self.runobj.complete(TestResult.SKIP, [], GNU_SKIP_RETURNCODE, skip_stdout, None, None)
+ self.runobj.complete(TestResult.SKIP, {}, GNU_SKIP_RETURNCODE, skip_stdout, None, None)
else:
wrap = TestHarness.get_wrapper(self.options)
if self.options.gdb:
@@ -1063,12 +1100,14 @@ class SingleTestRunner:
stdo = ""
stde = additional_error
if result:
- self.runobj.complete(result, [], returncode, stdo, stde, cmd)
+ self.runobj.complete(result, {}, returncode, stdo, stde, cmd)
else:
if self.test.protocol is TestProtocol.EXITCODE:
self.runobj.complete_exitcode(returncode, stdo, stde, cmd)
elif self.test.protocol is TestProtocol.GTEST:
self.runobj.complete_gtest(returncode, stdo, stde, cmd)
+ elif self.test.protocol is TestProtocol.RUST:
+ return self.runobj.complete_rust(returncode, stdo, stde, cmd)
else:
if self.options.verbose:
print(stdo, end='')