# Author: cirakg & claude ai # Summary: Tests for tools/gen_products.py (the manifest product rule and the watchdog the job runner assumes). """Tests for tools/gen_products.py, with synthetic device definitions.""" from __future__ import annotations import json from pathlib import Path import gen_products as gp MANIFEST = """ {products} """ def add_device(devices: Path, product: str, api: list[str], memory: int, group: str = gp.WATCH_GROUP) -> None: folder = devices / product folder.mkdir(parents=True) set_watchdog(devices, product, gp.WATCHDOG_LARGE if memory > gp.LARGE_WATCH_MEMORY else gp.WATCHDOG_SMALL) compiler = { "displayName": product.upper(), "webDocDeviceGroup": group, "partNumbers": [{"connectIQVersion": v} for v in api], "appTypes": [{"type": "watchApp", "memoryLimit": memory}, {"type": "glance", "memoryLimit": 65536}], } (folder / "compiler.json").write_text(json.dumps(compiler)) def set_watchdog(devices: Path, product: str, count: int) -> None: (devices / product / "simulator.json").write_text(json.dumps({"watchdogCount": count})) def write_manifest(tmp_path: Path, products: list[str]) -> Path: path = tmp_path / "manifest.xml" path.write_text(MANIFEST.format(products="".join(f'' for p in products))) return path def test_qualifying_products_pass(tmp_path: Path) -> None: devices = tmp_path / "Devices" add_device(devices, "fr70", ["6.0.3"], 786432) add_device(devices, "fr255s", ["5.2.0", "5.2.1"], 524288) assert gp.check(write_manifest(tmp_path, ["fr70", "fr255s"]), devices) == gp.EXIT_OK def test_each_rule_is_enforced(tmp_path: Path) -> None: devices = tmp_path / "Devices" add_device(devices, "old", ["4.2.0", "5.0.0"], 786432) # one firmware variant below 5.0 add_device(devices, "small", ["6.0.0"], 131072) add_device(devices, "bike", ["5.1.0"], 786432, group="Edge") manifest = write_manifest(tmp_path, ["old", "small", "bike"]) assert gp.check(manifest, devices) == gp.EXIT_UNQUALIFIED def test_missing_device_files(tmp_path: Path) -> None: devices = tmp_path / "Devices" devices.mkdir() assert gp.check(write_manifest(tmp_path, ["ghost"]), devices) == gp.EXIT_MISSING def test_problem_messages() -> None: device = gp.Device("x", "X", "Edge", (4, 2, 0), 131072, 120000) assert device.problems() == [ "group is 'Edge', not 'Watches/Wearables'", "API 4.2.0 is below 5.0.0", "watch apps get 128 KB, below 512 KB", ] def test_watchdog_must_match_the_job_runner(tmp_path: Path) -> None: devices = tmp_path / "Devices" add_device(devices, "big_slow", ["6.0.0"], 786432) set_watchdog(devices, "big_slow", 120000) # would run 2 steps on 120,000 add_device(devices, "small_fast", ["6.0.0"], 524288) set_watchdog(devices, "small_fast", 240000) # fine: 1 step, more room assert gp.check(write_manifest(tmp_path, ["small_fast"]), devices) == gp.EXIT_OK assert gp.check(write_manifest(tmp_path, ["big_slow"]), devices) == gp.EXIT_UNQUALIFIED problems = gp.load_device(devices, "big_slow").problems() assert problems == [ "watchdog allows 120000 bytecodes per event; the job runner needs 240000 at 768 KB (change Jobs.stepsPerTick)" ]