"""Tests del agregado raĆ­z Project.""" from __future__ import annotations import pytest from pydantic import ValidationError from vmssailor.core import ( Bus, BusRole, CardInstance, Equipment, PermissiveRule, Project, Protocol, ShipCoord, SystemId, Tag, Topology, UnitSI, Vessel, ) from vmssailor.core.permissive import Condition def test_project_stats(sample_project: Project) -> None: stats = sample_project.stats() assert stats["systems"] == 1 assert stats["equipment"] == 1 assert stats["tags"] == 1 assert stats["tags_with_alarms"] == 1 assert stats["buses"] == 1 assert stats["cards"] == 1 def test_project_equipment_requires_enabled_system( minimal_vessel: Vessel, sample_topology: Topology ) -> None: eq = Equipment( id="eq", model_ref="m", tag_prefix="X", display_name="x", location=ShipCoord(x_pp=5.0, y_cl=0.0, z_bl=1.0), system_id=SystemId.WATERMAKER, # NO en systems_enabled ) with pytest.raises(ValidationError): Project( id="p", name="p", vessel=minimal_vessel, systems_enabled=[SystemId.MAIN_ENGINE], equipment=[eq], topology=sample_topology, ) def test_project_tag_equipment_id_must_exist( minimal_vessel: Vessel, sample_topology: Topology, sample_equipment: Equipment ) -> None: with pytest.raises(ValidationError): Project( id="p", name="p", vessel=minimal_vessel, systems_enabled=[SystemId.MAIN_ENGINE], equipment=[sample_equipment], tags=[ Tag( id="GHOST.X", equipment_id="ghost_eq", # no existe unit_si=UnitSI.BAR, protocol=Protocol.MODBUS_RTU, address=1, ) ], topology=sample_topology, ) def test_project_tag_binding_must_reference_existing_card( minimal_vessel: Vessel, ) -> None: from vmssailor.core import ChannelType, SignalType, TagBinding b = Bus(id="bm", name="bm", protocol=Protocol.MODBUS_RTU, physical_port="COM3") c = CardInstance( id="card_001", slot_number=1, bus_id="bm", bus_role=BusRole.MODBUS_SLAVE, modbus_address=1, ) topo = Topology(buses=[b], cards=[c]) eq = Equipment( id="eq", model_ref="m", tag_prefix="X", display_name="x", location=ShipCoord(x_pp=5.0, y_cl=0.0, z_bl=1.0), system_id=SystemId.MAIN_ENGINE, ) bad_tag = Tag( id="X.PRESS", equipment_id="eq", unit_si=UnitSI.BAR, protocol=Protocol.MODBUS_RTU, physical_binding=TagBinding( card_id="ghost_card", channel_type=ChannelType.AI, channel_number=1, signal_type=SignalType.SIG_4_20_MA, ), ) with pytest.raises(ValidationError): Project( id="p", name="p", vessel=minimal_vessel, systems_enabled=[SystemId.MAIN_ENGINE], equipment=[eq], tags=[bad_tag], topology=topo, ) def test_project_permissive_condition_must_reference_existing_tag( sample_project: Project, ) -> None: bad_rule = PermissiveRule( id="bad", action_id="DO_X", conditions=[Condition(tag_ref="GHOST.TAG", operator=">", threshold=1.0)], ) with pytest.raises(ValidationError): Project( id=sample_project.id, name=sample_project.name, vessel=sample_project.vessel, systems_enabled=sample_project.systems_enabled, equipment=sample_project.equipment, tags=sample_project.tags, topology=sample_project.topology, permissive_rules=[bad_rule], ) def test_project_helpers(sample_project: Project) -> None: eq = sample_project.equipment_by_id("eq_me_port") assert eq is not None assert eq.tag_prefix == "ME_PORT" tag = sample_project.tag_by_id("ME_PORT.OIL_PRESS") assert tag is not None tags_eq = sample_project.tags_for_equipment("eq_me_port") assert len(tags_eq) == 1 tags_sys = sample_project.tags_for_system(SystemId.MAIN_ENGINE) assert len(tags_sys) == 1 def test_project_touch_updates_timestamp(sample_project: Project) -> None: original = sample_project.updated_at sample_project.touch() assert sample_project.updated_at >= original def test_project_equipment_unique_tag_prefix(minimal_vessel: Vessel) -> None: e1 = Equipment( id="e1", model_ref="m", tag_prefix="ME", display_name="A", location=ShipCoord(x_pp=1, y_cl=0, z_bl=0), system_id=SystemId.MAIN_ENGINE, ) e2 = Equipment( id="e2", model_ref="m", tag_prefix="ME", # mismo prefix display_name="B", location=ShipCoord(x_pp=2, y_cl=0, z_bl=0), system_id=SystemId.MAIN_ENGINE, ) with pytest.raises(ValidationError): Project( id="p", name="p", vessel=minimal_vessel, systems_enabled=[SystemId.MAIN_ENGINE], equipment=[e1, e2], ) def test_project_equipment_deck_must_exist(minimal_vessel: Vessel) -> None: eq = Equipment( id="eq", model_ref="m", tag_prefix="X", display_name="x", location=ShipCoord(x_pp=1, y_cl=0, z_bl=0), deck_id="non_existent_deck", system_id=SystemId.MAIN_ENGINE, ) with pytest.raises(ValidationError): Project( id="p", name="p", vessel=minimal_vessel, systems_enabled=[SystemId.MAIN_ENGINE], equipment=[eq], )