summaryrefslogtreecommitdiff
path: root/tools/testing/kunit/kunit_parser.py
diff options
context:
space:
mode:
authorDavid Gow <david@davidgow.net>2026-06-06 09:38:17 +0800
committerShuah Khan <skhan@linuxfoundation.org>2026-06-07 19:50:06 -0600
commitbfd73e009d02b6f4500e60970dafaa65940be8ad (patch)
treee3ffb5adcc81dc033892fc6465a102263e5c30a0 /tools/testing/kunit/kunit_parser.py
parent5c1553dd5db306d84d539f84fa184d4694d6d050 (diff)
kunit: tool: Parse and print the reason tests are skipped
When a KUnit test (or other KTAP test) is skipped, a "skip reason" can be provided. kunit.py has never done anything with this, ignoring anything included in the KTAP output after the 'SKIP' directive. Since we have it, and it's used, print it in a nice friendly yellow in parentheses after a skipped test's name. (And, by parsing it, it can be included in the JUnit results as well.) Link: https://lore.kernel.org/r/20260606013827.240790-1-david@davidgow.net Signed-off-by: David Gow <david@davidgow.net> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Diffstat (limited to 'tools/testing/kunit/kunit_parser.py')
-rw-r--r--tools/testing/kunit/kunit_parser.py15
1 files changed, 10 insertions, 5 deletions
diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index 0e1d2f4985eb..7a021517f58b 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -44,11 +44,12 @@ class Test:
self.subtests = [] # type: List[Test]
self.log = [] # type: List[str]
self.counts = TestCounts()
+ self.skip_reason = ''
def __str__(self) -> str:
"""Returns string representation of a Test class object."""
return (f'Test({self.status}, {self.name}, {self.expected_count}, '
- f'{self.subtests}, {self.log}, {self.counts})')
+ f'{self.subtests}, {self.log}, {self.counts}, {self.skip_reason})')
def __repr__(self) -> str:
"""Returns string representation of a Test class object."""
@@ -352,9 +353,9 @@ def parse_test_plan(lines: LineStream, test: Test) -> bool:
lines.pop()
return True
-TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?([^#]*)( # .*)?$')
+TEST_RESULT = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(:?- )?([^#]*)( # .*)?$')
-TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(- )?(.*) # SKIP ?(.*)$')
+TEST_RESULT_SKIP = re.compile(r'^\s*(ok|not ok) ([0-9]+) ?(:?- )?(.*) # SKIP ?(.*)$')
def peek_test_name_match(lines: LineStream, test: Test) -> bool:
"""
@@ -418,7 +419,7 @@ def parse_test_result(lines: LineStream, test: Test,
# Set name of test object
if skip_match:
- test.name = skip_match.group(4) or skip_match.group(5)
+ test.name = skip_match.group(4)
else:
test.name = match.group(4)
@@ -431,6 +432,7 @@ def parse_test_result(lines: LineStream, test: Test,
status = match.group(1)
if skip_match:
test.status = TestStatus.SKIPPED
+ test.skip_reason = skip_match.group(5) or ''
elif status == 'ok':
test.status = TestStatus.SUCCESS
else:
@@ -539,7 +541,10 @@ def format_test_result(test: Test, printer: Printer) -> str:
if test.status == TestStatus.SUCCESS:
return printer.green('[PASSED] ') + test.name
if test.status == TestStatus.SKIPPED:
- return printer.yellow('[SKIPPED] ') + test.name
+ skip_message = printer.yellow('[SKIPPED] ') + test.name
+ if test.skip_reason != '':
+ skip_message += printer.yellow(' (' + test.skip_reason + ')')
+ return skip_message
if test.status == TestStatus.NO_TESTS:
return printer.yellow('[NO TESTS RUN] ') + test.name
if test.status == TestStatus.TEST_CRASHED: