"""GUI 功能自检(offscreen 无窗口): 事务入表/地址过滤/暂停滚动/波形喂数/ CSV 导出池/固件统计行/配置往返 ==================================================================== 不依赖硬件与串口, 直接驱动 Window 的事件处理函数; 改 main.py 后建议重跑。 用法: python selftest_gui.py (全部通过退出码 0) """ import os import sys os.environ['QT_QPA_PLATFORM'] = 'offscreen' sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from PySide6.QtWidgets import QApplication import i2cdec import main as m from i2cdec import Transaction fails = [] def check(name, got, want): ok = got == want print(('PASS' if ok else 'FAIL'), name, '->', repr(got)[:120], '' if ok else f'(期望 {want!r})') if not ok: fails.append(name) app = QApplication(sys.argv) win = m.Window() win.show() T = Transaction # 1) 事务入表 + 全量池 tr1 = T(t0_us=100, t1_us=200, addr7=0x32, read=False, acks=(True, True), data=b'\xff\x60', ended='stop') tr2 = T(t0_us=900, t1_us=1100, addr7=0x50, read=True, acks=(True, False), data=b'\x12', ended='stop') win._paused = False for tr in (tr1, tr2): win._on_trans(tr) check('表格行数', win.table.rowCount(), 2) check('导出池数量', len(win.transactions), 2) check('事务计数', win._trans_total, 2) check('地址列', win.table.item(0, 3).text(), '0x32') check('RW 列', win.table.item(1, 4).text(), 'R') check('ACK 列', win.table.item(0, 5).text(), 'AA') check('数据列', win.table.item(0, 6).text(), 'FF 60') check('收尾列', win.table.item(0, 7).text(), 'STOP') # 2) 地址过滤: 只留 0x32; 非法过滤项被忽略 win.ed_filter.setText('32 zz') win._on_trans(tr2) check('过滤生效(0x50 不入表)', win.table.rowCount(), 2) check('计数仍累计', win._trans_total, 3) win.ed_filter.setText('') win._on_trans(tr2) check('清过滤后入表', win.table.rowCount(), 3) # 3) 地址 NAK 标红 / 未收尾标橙(前景色判断) tr_nak = T(t0_us=1, t1_us=2, addr7=0x10, read=False, acks=(False,), data=b'', ended='stop') tr_cut = T(t0_us=3, t1_us=9, addr7=0x11, read=False, acks=(True,), data=b'', ended='cut') win._on_trans(tr_nak) win._on_trans(tr_cut) r_nak = win.table.rowCount() - 2 check('地址 NAK 前景红色', win.table.item(r_nak, 5).foreground().color().name(), '#e0564c') check('cut 收尾前景橙色', win.table.item(r_nak + 1, 7).foreground().color().name(), '#e08a2e') # 4) 长事务截断显示 + tooltip 全量 tr_long = T(t0_us=1, t1_us=2, addr7=0x2a, read=False, acks=(True,) * 20, data=bytes(range(20)), ended='stop') win._on_trans(tr_long) r = win.table.rowCount() - 1 check('长数据显示截断省略', win.table.item(r, 6).text().endswith('…'), True) check('长数据 tooltip 全量', win.table.item(r, 6).toolTip() == tr_long.data_hex(), True) # 5) 暂停滚动: 不再 scrollToBottom, 但行照加 win._toggle_pause() check('暂停按钮文案', win.btn_pause.text(), '继续滚动') win._on_trans(tr1) check('暂停时行照加', win.table.rowCount() >= 6, True) win._toggle_pause() # 6) 表格行数上限: 批量灌 5100 条, 顶行被裁 win._clear_table() for i in range(5100): win._on_trans(T(t0_us=i, t1_us=i + 1, addr7=0x01, read=False, acks=(True,), data=b'', ended='stop')) check('表格行数封顶', win.table.rowCount(), m.TABLE_CAP) check('导出池保留全部( 0, True) win._toggle_demo() check('演示停止', not win._demo_timer.isActive(), True) win.close() app.quit() print() if fails: print(f'共 {len(fails)} 项失败:', ', '.join(fails)) sys.exit(1) print('全部通过')