aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorEli Schwartz <eschwartz@archlinux.org>2022-10-28 00:19:17 -0400
committerEli Schwartz <eschwartz@archlinux.org>2022-12-05 15:46:46 -0500
commitd0054f2c3c3497e22069d1efb5b1d985d75fe5ca (patch)
treec1b29688eec0263cd948f45f7d7d5486a5c06de8 /mesonbuild
parent7c9705b801e4ab55732390eebfe896b4051bfafb (diff)
downloadmeson-d0054f2c3c3497e22069d1efb5b1d985d75fe5ca.zip
meson-d0054f2c3c3497e22069d1efb5b1d985d75fe5ca.tar.gz
meson-d0054f2c3c3497e22069d1efb5b1d985d75fe5ca.tar.bz2
mtest: warn on invalid TAP output
In commit a7e458effadbc884eacf34528df3a57b60e43fe3 we stopped erroring out on invalid TAP stream contents, with the rationale that "prove" has become more lenient. A close reading of the TAP spec indicates why, though: > A TAP parser is required to not consider an unknown line as an error but > may optionally choose to capture said line and hand it to the test > harness, which may have custom behavior attached. This is to allow for > forward compatability. Test::Harness silently ignores incorrect lines, > but will become more stringent in the future. TAP::Harness reports TAP > syntax errors at the end of a test run. The goal of treating unknown lines as an error in the TAP parser is not because unknown lines are fine and dandy. The goal is to allow implementing future versions of TAP, and handling it via existing parsers. Since Meson has both a parser and a harness, let's do exactly that -- pass these lines as a distinctive status to the test harness, then have the test harness complain.
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/mtest.py33
1 files changed, 32 insertions, 1 deletions
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index f3f5f26..00812c1 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -275,6 +275,7 @@ TYPE_TAPResult = T.Union['TAPParser.Test',
'TAPParser.Error',
'TAPParser.Version',
'TAPParser.Plan',
+ 'TAPParser.UnknownLine',
'TAPParser.Bailout']
class TAPParser:
@@ -299,6 +300,10 @@ class TAPParser:
class Error(T.NamedTuple):
message: str
+ class UnknownLine(T.NamedTuple):
+ message: str
+ lineno: int
+
class Version(T.NamedTuple):
version: int
@@ -434,6 +439,9 @@ class TAPParser:
else:
yield self.Version(version=self.version)
return
+
+ # unknown syntax
+ yield self.UnknownLine(line, self.lineno)
else:
# end of file
if self.state == self._YAML:
@@ -673,6 +681,11 @@ class ConsoleLogger(TestLogger):
flush=True)
if result.verbose or result.res.is_bad():
self.print_log(harness, result)
+ if result.warnings:
+ print(flush=True)
+ for w in result.warnings:
+ print(w, flush=True)
+ print(flush=True)
if result.verbose or result.res.is_bad():
print(flush=True)
@@ -899,6 +912,7 @@ class TestRun:
self.junit = None # type: T.Optional[et.ElementTree]
self.is_parallel = is_parallel
self.verbose = verbose
+ self.warnings = [] # type: T.List[str]
def start(self, cmd: T.List[str]) -> None:
self.res = TestResult.RUNNING
@@ -1041,9 +1055,13 @@ class TestRunTAP(TestRun):
async def parse(self, harness: 'TestHarness', lines: T.AsyncIterator[str]) -> None:
res = None
+ warnings = [] # type: T.List[TAPParser.UnknownLine]
+ version: int
async for i in TAPParser().parse_async(lines):
- if isinstance(i, TAPParser.Bailout):
+ if isinstance(i, TAPParser.Version):
+ version = i.version
+ elif isinstance(i, TAPParser.Bailout):
res = TestResult.ERROR
harness.log_subtest(self, i.message, res)
elif isinstance(i, TAPParser.Test):
@@ -1051,10 +1069,23 @@ class TestRunTAP(TestRun):
if i.result.is_bad():
res = TestResult.FAIL
harness.log_subtest(self, i.name or f'subtest {i.number}', i.result)
+ elif isinstance(i, TAPParser.UnknownLine):
+ warnings.append(i)
elif isinstance(i, TAPParser.Error):
self.additional_error += 'TAP parsing error: ' + i.message
res = TestResult.ERROR
+ if warnings:
+ unknown = str(mlog.yellow('UNKNOWN'))
+ width = len(str(max(i.lineno for i in warnings)))
+ for w in warnings:
+ self.warnings.append(f'stdout: {w.lineno:{width}}: {unknown}: {w.message}')
+ if version > 13:
+ self.warnings.append('Unknown TAP output lines have been ignored. Please open a feature request to\n'
+ 'implement them, or prefix them with a # if they are not TAP syntax.')
+ else:
+ self.warnings.append(str(mlog.red('ERROR')) + ': Unknown TAP output lines for a supported TAP version.\n'
+ 'This is probably a bug in the test; if they are not TAP syntax, prefix them with a #')
if all(t.result is TestResult.SKIP for t in self.results):
# This includes the case where self.results is empty
res = TestResult.SKIP