from __future__ import annotations import sys from pathlib import Path import pytest ROOT = Path(__file__).resolve().parent.parent if str(ROOT) not in sys.path: sys.path.insert(0, str(ROOT)) from cantarire import create_app # noqa: E402 STABLE_READING = { "ok": True, "error": None, "profile": "test-scale", "port": "COM1", "protocol": "mt_sics", "open": True, "value": 250.0, "unit": "g", "stable": True, "stale": False, "overload": False, "age_ms": 120, "measured_at": "2026-10-18T10:00:00.000+03:00", "raw_hex": "53 20 53 20 20 20 20 32 35 30 2E 30", "fields": {}, } class FakeScale: available = True error = None def __init__(self): self.reading = dict(STABLE_READING) self.calls = 0 self.probed = None def profiles(self): return [{"name": "test-scale", "label": "Cântar test", "port": "COM1", "protocol": "mt_sics"}] def read(self, profile_name="", **_kwargs): self.calls += 1 return dict(self.reading) def probe(self, port, baud=9600, framing="8N1", seconds=5.0): self.probed = {"port": port, "baud": baud, "framing": framing, "seconds": seconds} return { "ok": True, "port": port, "settings": f"{port} {baud} {framing}, listen only", "baud": baud, "framing": framing, "seconds": seconds, "error": None, "bytes": 13, "frames": [{"age_ms": 10, "hex": "02 2D 30 20 30 30 30 30 30 30 30 30 30 30 0D", "text": "-0 000000000000", "size": 13}], "guesses": [{"protocol": "toledo_cont", "name": "Toledo Continuous", "kind": "continuous", "count": 2, "value": 12.345, "unit": "kg", "stable": True, "specificity": 3}], } @pytest.fixture() def app(tmp_path): application = create_app({ "TESTING": True, "INSTANCE_DIR": tmp_path, "DATABASE": tmp_path / "test.db", "BRIDGE_CONFIG": tmp_path / "bridge.json", "SIMULATE": "", "AUTO_PRINT": False, "SECRET_KEY": "test", }) application.extensions["scale"] = FakeScale() return application @pytest.fixture() def client(app): return app.test_client() @pytest.fixture() def scale(app): return app.extensions["scale"] def _create_component(client, code: str, name: str, unit: str = "g") -> int: response = client.post("/componente/nou", data={ "code": code, "name": name, "unit": unit, "active": "on", }) assert response.status_code == 302, response.get_data(as_text=True) with client.application.app_context(): from cantarire.repositories import get_component_by_code return get_component_by_code(code)["id"] @pytest.fixture() def fasole(client): return _create_component(client, "FAS", "Fasole") @pytest.fixture() def carne(client): return _create_component(client, "CAR", "Carne") @pytest.fixture() def recipe(client, fasole, carne): response = client.post("/retete/nou", data={ "code": "PF-001", "name": "Fasole cu carne", "unit": "g", "target_weight": "450", "component_1_id": str(fasole), "component_1_target": "250", "component_2_id": str(carne), "component_2_target": "200", "active": "on", }) assert response.status_code == 302, response.get_data(as_text=True) with client.application.app_context(): from cantarire.repositories import list_recipes return list_recipes()[0]