summaryrefslogtreecommitdiff
path: root/tools/ui_flow.py
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-20 02:43:08 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-20 02:43:08 +0200
commitfa9c695256de1c7fe007ba5d6bb9b28b1deb5a5a (patch)
treebd418bc860349833d5a19c4af6bb8a61666477ca /tools/ui_flow.py
parent59255b1a55a81ba2b5de967eefced11910597b48 (diff)
test(codes): compare with zxing-cpp reference rows and decode encoder output and screenshots
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/ui_flow.py')
-rw-r--r--tools/ui_flow.py29
1 files changed, 27 insertions, 2 deletions
diff --git a/tools/ui_flow.py b/tools/ui_flow.py
index 3e82231..82e5d65 100644
--- a/tools/ui_flow.py
+++ b/tools/ui_flow.py
@@ -23,7 +23,8 @@ The flow covers: the results of an Aegis import sent through the settings
form (the fixture sets the form, as the phone would), the list, a TOTP entry, a HOTP entry and its next code, the
PIN screen, a wrong PIN, a correct PIN opening a locked entry, auto-lock
closing it, the menu, the About screen (watches with buttons; touch-only
-menus have no focus to move) and the lockout after 5 wrong PINs.
+menus have no focus to move), the lockout after 5 wrong PINs, and an EAN-13
+code whose screenshot must decode with zxing-cpp (README 12.4).
Each screenshot is compared with test/golden/<device>/<screen>.png like
sim_screenshot.py does (or saved there with --approve).
@@ -43,6 +44,7 @@ from dataclasses import dataclass
from pathlib import Path
import sim_screenshot as shots
+import zxingcpp
EXIT_OK, EXIT_DIFFERENT, EXIT_FLOW = 0, 1, 2
SCREEN_TIMEOUT_S = 20.0
@@ -57,6 +59,7 @@ FIXTURE_PIN = "123456" # source/app/Fixtures.mc
WRONG_PIN = "000000"
FAILURES_UNTIL_WAIT = 5 # source/storage/Lockout.mc: the 5th failure starts a delay
SELECTOR_OK = 10 # source/ui/PinView.mc: selector positions 0-9, then OK
+GYM_CARD = "5901234123457" # source/app/Fixtures.mc: EAN-13 with its check digit
class FlowError(Exception):
@@ -295,7 +298,7 @@ class Flow:
"""Call before an input whose result `expect` should wait for."""
self.log.set_mark()
- def shot(self, name: str) -> None:
+ def shot(self, name: str, expect_code: str | None = None) -> None:
raw = self.sim.capture(name)
out = self.out / f"{name}.png"
label = f"{self.sim.device_dir.name}/{name}"
@@ -305,6 +308,14 @@ class Flow:
print(f"[{label}] {err}")
self.results[name] = EXIT_DIFFERENT
return
+ if expect_code is not None:
+ # README 12.4 check 3: the code on the screenshot must decode.
+ read = [r.text for r in zxingcpp.read_barcodes(screen)]
+ if expect_code not in read:
+ print(f"[{label}] the barcode didn't decode to {expect_code!r}: read {read}")
+ self.results[name] = EXIT_DIFFERENT
+ return
+ print(f"[{label}] barcode decodes to {expect_code!r}")
golden = self.golden / f"{name}.png"
if self.approve:
shots.save_png(screen, golden, f"Approved simulator screen '{name}' of {self.sim.device_dir.name}")
@@ -414,6 +425,19 @@ def flow_lockout(f: Flow) -> None:
f.shot("pin_wait")
+def flow_code(f: Flow) -> None:
+ """The EAN-13 gym card (index 6): its screenshot must decode."""
+ f.act()
+ f.back() # leave the waiting PIN screen
+ f.expect("list")
+ for _ in range(4): # Bank (2) to the gym card (6)
+ f.next()
+ f.act()
+ f.open_focused_row()
+ f.expect("code")
+ f.shot("code", expect_code=GYM_CARD)
+
+
def run_flow(f: Flow) -> None:
"""The scripted session; see the module docstring."""
flow_import(f)
@@ -421,6 +445,7 @@ def run_flow(f: Flow) -> None:
flow_locked_entry(f)
flow_menu(f)
flow_lockout(f)
+ flow_code(f)
def find_key(data: object, key: str) -> object: