From 657621c5547a761936dd17ea3e2113f0cba7e14c Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 15 Aug 2026 10:54:51 +0700 Subject: [PATCH] hil: make the usbtest-cell tests actually run The file was bare module-level pytest functions with no entry point, and nothing in this repo invokes pytest - so `python3 test_hil_usbtest_cell.py` exited 0 having run nothing, and the guard on the skip-accounting fix could never fail. Converted to unittest with a __main__ block, matching its two siblings. A pre-commit hook now runs every test/hil/test_*.py directly. Not via pytest: hil_test.py matches pytest's default discovery glob, so `pytest test/hil/` collects 26 hardware cases and errors on all of them. Verified the hook gates - reintroducing the passed+failed total makes it exit non-zero. --- .pre-commit-config.yaml | 10 +++++ test/hil/test_hil_usbtest_cell.py | 65 +++++++++++++++++-------------- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e87b935dd..4b212160c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,6 +48,16 @@ repos: types_or: [c, header] language: system + # The HIL harness's hardware-free unit tests. Each is run directly rather than through pytest: + # nothing else in the repo invokes pytest, and `pytest test/hil/` would collect hil_test.py's + # hardware cases (they match pytest's default glob) and error on every one. + - id: hil-unit-test + name: HIL harness unit tests + files: ^test/hil/ + entry: sh -c 'for t in test/hil/test_*.py; do python3 "$t" || exit 1; done' + pass_filenames: false + language: system + # - id: build-fuzzer # name: build-fuzzer # files: ^(src/|test/fuzz/) diff --git a/test/hil/test_hil_usbtest_cell.py b/test/hil/test_hil_usbtest_cell.py index ca96552cc..5327bec2d 100644 --- a/test/hil/test_hil_usbtest_cell.py +++ b/test/hil/test_hil_usbtest_cell.py @@ -1,38 +1,45 @@ -"""The usbtest report cell must never render a quirk-skipped run as a full pass.""" +#!/usr/bin/env python3 +"""The usbtest report cell must never render a quirk-skipped run as a full pass. + +unittest (not bare pytest functions) so `python3 test_hil_usbtest_cell.py` actually runs the +assertions: nothing in CI invokes pytest, and `pytest test/hil/` is not a substitute either - +hil_test.py matches pytest's default discovery glob and drags 26 hardware tests into collection. +""" import sys +import unittest from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) import hil_test -def test_full_pass_renders_as_pass(): - data = {'passed': 30, 'failed': 0, 'skipped': 0, 'cases': []} - assert hil_test.usbtest_cell(data) == '✅ 30/30' +class TestUsbtestCell(unittest.TestCase): + def test_full_pass_renders_as_pass(self): + data = {'passed': 30, 'failed': 0, 'skipped': 0, 'cases': []} + self.assertEqual(hil_test.usbtest_cell(data), '✅ 30/30') + + def test_skipped_cases_are_counted_in_the_denominator(self): + """25 ran and passed, 5 were quirk-skipped: the cell must not read 25/25.""" + data = {'passed': 25, 'failed': 0, 'skipped': 5, + 'cases': [{'num': n, 'status': 'SKIP'} for n in (9, 10, 13, 14, 21)]} + cell = hil_test.usbtest_cell(data) + self.assertIn('25/30', cell) + self.assertIn('5 skipped', cell) + self.assertNotIn('25/25', cell) + + def test_skipped_cases_are_not_reported_as_failures(self): + data = {'passed': 24, 'failed': 1, 'skipped': 5, + 'cases': [{'num': n, 'status': 'SKIP'} for n in (9, 10, 13, 14, 21)] + + [{'num': 7, 'status': 'FAIL'}]} + with self.assertRaises(hil_test.TestFail) as cm: + hil_test.usbtest_cell(data) + self.assertIn('cases failed: [7]', str(cm.exception)) + + def test_missing_skipped_key_defaults_to_zero(self): + """Output from a usbtest.py predating the skipped key must still render.""" + self.assertEqual(hil_test.usbtest_cell({'passed': 30, 'failed': 0, 'cases': []}), + '✅ 30/30') -def test_skipped_cases_are_counted_in_the_denominator(): - # 25 ran and passed, 5 were quirk-skipped: the cell must not read 25/25 - data = {'passed': 25, 'failed': 0, 'skipped': 5, - 'cases': [{'num': n, 'status': 'SKIP'} for n in (9, 10, 13, 14, 21)]} - cell = hil_test.usbtest_cell(data) - assert '25/30' in cell - assert '5 skipped' in cell - assert '25/25' not in cell - - -def test_skipped_cases_are_not_reported_as_failures(): - data = {'passed': 24, 'failed': 1, 'skipped': 5, - 'cases': [{'num': n, 'status': 'SKIP'} for n in (9, 10, 13, 14, 21)] - + [{'num': 7, 'status': 'FAIL'}]} - try: - hil_test.usbtest_cell(data) - except hil_test.TestFail as e: - assert 'cases failed: [7]' in str(e) - else: - raise AssertionError('expected TestFail') - - -def test_missing_skipped_key_defaults_to_zero(): - # older usbtest.py output without the key must still render - assert hil_test.usbtest_cell({'passed': 30, 'failed': 0, 'cases': []}) == '✅ 30/30' +if __name__ == '__main__': + unittest.main(verbosity=1)