# Author: cirakg & claude ai # Summary: Tests for the UI flow driver's pure parts: key layout, JSON lookup, the app-log reader, barcode reading. from __future__ import annotations import json import threading import time from pathlib import Path import pytest import segno import ui_flow from PIL import Image def write_sim(tmp_path: Path, config: dict[str, object]) -> Path: (tmp_path / "simulator.json").write_text(json.dumps(config), encoding="utf-8") return tmp_path def test_load_keys_gives_button_centres(tmp_path: Path) -> None: device = write_sim( tmp_path, { "keys": [ {"id": "enter", "behavior": "onSelect", "location": {"x": 10, "y": 20, "width": 30, "height": 40}}, { "id": "menu", "behavior": "onMenu", "isHold": True, "location": {"x": 0, "y": 0, "width": 2, "height": 2}, }, {"id": "start", "location": {"x": 5, "y": 5, "width": 10, "height": 10}}, ] }, ) keys = ui_flow.load_keys(device) assert keys["enter"] == ui_flow.Key(25, 40, "onSelect", False) assert keys["menu"].hold assert keys["start"].behavior == "" def test_find_key_searches_nested_structures() -> None: data = {"display": {"isTouch": True}, "glance": [{"contentArea": {"x": 1}}]} assert ui_flow.find_key(data, "isTouch") is True assert ui_flow.find_key(data, "contentArea") == {"x": 1} assert ui_flow.find_key(data, "missing") is None def test_app_log_waits_only_for_lines_after_the_mark(tmp_path: Path) -> None: log_path = tmp_path / "app.log" log_path.write_text("DIAG shown list\n", encoding="utf-8") log = ui_flow.AppLog(log_path) assert log.wait_for(r"DIAG shown list\s*$", 1).group(0).startswith("DIAG shown list") log.set_mark() def append_later() -> None: time.sleep(0.2) with log_path.open("a", encoding="utf-8") as f: f.write("DIAG shown otp\n") writer = threading.Thread(target=append_later) writer.start() assert log.wait_for(r"DIAG shown otp", 3) writer.join() with pytest.raises(ui_flow.FlowError): log.wait_for(r"DIAG shown list", 0.3) # only before the mark def test_app_log_latest_returns_the_last_match(tmp_path: Path) -> None: log_path = tmp_path / "app.log" log_path.write_text("DIAG list_focus y=10\nother\nDIAG list_focus y=42\n", encoding="utf-8") match = ui_flow.AppLog(log_path).latest(r"DIAG list_focus y=(\d+)") assert match is not None and match.group(1) == "42" assert ui_flow.AppLog(tmp_path / "missing.log").latest("x") is None def test_barcodes_on_reads_a_drawn_code(tmp_path: Path) -> None: path = tmp_path / "qr.png" segno.make("OTPW stress", error="m").save(str(path), scale=4, border=4) screen = Image.open(path).convert("RGB") assert ui_flow.barcodes_on(screen) == ["OTPW stress"] assert ui_flow.barcodes_on(Image.new("RGB", (100, 100), "white")) == []