"""Unit tests for custom exception hierarchy and details propagation.""" from exceptions import ( BridgeError, ConfigValidationError, DeviceNotFoundError, OdooAPIError, ParserError, ) def test_bridge_error_str_includes_details(): error = BridgeError("failure", details={"device_id": "dev-1", "code": "E1"}) message = str(error) assert "failure" in message assert "device_id=dev-1" in message assert "code=E1" in message def test_config_validation_error_enriches_context(): error = ConfigValidationError( "invalid value", field="mqtt.port", value=-1, path="/tmp/config.yaml", ) assert error.details["field"] == "mqtt.port" assert error.details["value"] == -1 assert error.details["path"] == "/tmp/config.yaml" def test_odoo_api_error_contains_service_and_status_code(): error = OdooAPIError("request failed", status_code=500, response={"error": "boom"}) assert error.service == "odoo" assert error.details["status_code"] == 500 assert error.details["response"] == {"error": "boom"} def test_device_not_found_error_sets_device_id(): error = DeviceNotFoundError(device_id="device-42") assert error.device_id == "device-42" assert error.details["device_id"] == "device-42" def test_parser_error_extracts_payload_keys(): error = ParserError( "cannot parse", topic="shelly/topic", payload={"apower": 123.4, "voltage": 231.2}, ) assert error.details["topic"] == "shelly/topic" assert sorted(error.details["payload_keys"]) == ["apower", "voltage"]