chore(core/test): improve python unit test class-level skipping
What changed, and why it matters
This commit is a minor internal improvement to the Python unit-test helper used in Trezor's firmware testing. It lets developers mark an entire test class as skipped rather than only individual test methods, and adds yellow coloring for skipped tests in console output. There is no change to device firmware, cryptography, wallet operations, or any user-facing security behavior.
No security action needed. Treat as ordinary test-infrastructure maintenance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change modifies core/tests/unittest.py, a small custom unittest-like runner for the embedded Python test suite. It refactors the skip() decorator so that when applied to a class it returns a synthetic TestCase subclass whose test methods all raise SkipTest. It also extracts test-case iteration into iter_test_cases() and adds a SKIPPED_COLOR ANSI escape for output formatting. No runtime firmware code, crypto, storage, or communication protocols are touched.
Changed components
core/tests/unittest.pyInspect captured patch +24 / −6
diff --git a/core/tests/unittest.py b/core/tests/unittest.py
index 32e76c8e..2bb672fe 100644
--- a/core/tests/unittest.py
+++ b/core/tests/unittest.py
@@ -5,6 +5,7 @@ from trezor.utils import ensure
DEFAULT_COLOR = "\033[0m"
ERROR_COLOR = "\033[31m"
OK_COLOR = "\033[32m"
+SKIPPED_COLOR = "\033[33m"
class SkipTest(Exception):
@@ -189,11 +190,23 @@ class TestCase:
def skip(msg):
- def _decor(fun):
- # We just replace original fun with _inner
+
+ def _decor(obj):
+ # Function skip
def _inner(self):
raise SkipTest(msg)
+ # Class skip
+ if isinstance(obj, type):
+
+ class _SkipClass(TestCase):
+ pass
+
+ for name in iter_test_cases(obj):
+ setattr(_SkipClass, name, _inner)
+ _SkipClass.__qualname__ = obj.__qualname__
+ return _SkipClass
+
return _inner
return _decor
@@ -235,6 +248,12 @@ class TestResult:
generator_type = type((lambda: (yield))())
+def iter_test_cases(obj):
+ for name in dir(obj):
+ if name.startswith("test"):
+ yield name
+
+
def run_class(c, test_result):
o = c()
set_up_class = getattr(o, "setUpClass", lambda: None)
@@ -244,9 +263,8 @@ def run_class(c, test_result):
print("class", c.__qualname__)
try:
set_up_class()
- for name in dir(o):
- if name.startswith("test"):
- run_test_method(o, name, set_up, tear_down, test_result)
+ for name in iter_test_cases(o):
+ run_test_method(o, name, set_up, tear_down, test_result)
finally:
tear_down_class()
@@ -269,7 +287,7 @@ def run_test_method(o, name, set_up, tear_down, test_result):
tear_down()
print(f"{OK_COLOR} ok{DEFAULT_COLOR}")
except SkipTest as e:
- print(" skipped:", e.args[0])
+ print(f"{SKIPPED_COLOR} skipped:{DEFAULT_COLOR}", e.args[0])
test_result.skippedNum += 1
except AssertionError as e:
print(f"{ERROR_COLOR} failed{DEFAULT_COLOR}")
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.