Files
panda/tests/misra/misra_failfast.py
Adeeb Shihadeh 175f1a581a add fail-fast MISRA addon for mutation tests
The new misra_failfast.py wrapper patches misra.py's reportError to
sys.exit(1) on the first real violation, handling cppcheck's inline
and macro suppressions to avoid false positives on clean code.
Also removes sampling (all 12 tests run in ~38s with xdist) and
adds board/crypto and board/certs to ignored mutation paths since
they're only included from bootstub.c.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:32:50 -08:00

47 lines
1.7 KiB
Python

#!/usr/bin/env python3
"""Wrapper around cppcheck's misra.py that exits on first violation.
Used by mutation tests to fail fast — we only need to know if ANY
violation exists, not enumerate them all. This saves ~10s per test
by killing the 54MB XML dump parsing early.
"""
import sys
# cppcheck prepends its addons/ dir to sys.path, so these are directly importable
import cppcheckdata
import misra
_original_reportError = misra.MisraChecker.reportError
def _failfast_reportError(self, location, num1, num2):
ruleNum = num1 * 100 + num2
# misra's own suppression checks
if self.isRuleGloballySuppressed(ruleNum):
return
if self.settings.verify:
return _original_reportError(self, location, num1, num2)
if self.isRuleSuppressed(location.file, location.linenr, ruleNum):
return _original_reportError(self, location, num1, num2)
errorId = 'misra-c2012-%d.%d' % (num1, num2)
# cppcheck's own suppression checks (file-pattern, line, block).
# with --cli these are normally applied AFTER the addon, so we check here.
if cppcheckdata.is_suppressed(location, '', errorId):
return _original_reportError(self, location, num1, num2)
# cppcheck-suppress-macro: suppresses a rule for all expansions of a macro.
# is_suppressed doesn't handle type="macro", so check manually.
if getattr(location, 'macroName', None):
for s in cppcheckdata.current_dumpfile_suppressions:
if s.suppressionType == 'macro' and s.errorId == errorId:
return _original_reportError(self, location, num1, num2)
# real violation — report it then bail out
_original_reportError(self, location, num1, num2)
sys.exit(1)
misra.MisraChecker.reportError = _failfast_reportError
misra.main()