from __future__ import annotations import json from pathlib import Path import unittest from app.main import get_component_catalog from app.simulation.registry import ( COMPONENT_MODEL_REGISTRY, validate_component_registries, ) class ComponentCatalogTests(unittest.TestCase): def setUp(self) -> None: self.catalog = get_component_catalog() self.libraries = { library["id"]: library for library in self.catalog["libraries"] } self.library = self.libraries["experimental"] self.components = { component["modelType"]: component for library in self.catalog["libraries"] for component in library["components"] } def test_experimental_library_is_exposed_as_temporary(self) -> None: self.assertEqual(self.catalog["schemaVersion"], 1) self.assertEqual(self.library["id"], "experimental") self.assertEqual(self.library["label"], "临时测试组件库") self.assertEqual(self.library["version"], "0.1.0") self.assertTrue(self.library["temporary"]) self.assertEqual( self.library["sourcePackage"], "app.simulation.components.experimental", ) self.assertEqual( [category["id"] for category in self.library["categories"]], ["storage", "flow", "junctions"], ) def test_amesim_library_exposes_pneumatic_models(self) -> None: library = self.libraries["amesim"] components = { component["modelType"]: component for component in library["components"] } self.assertEqual(library["label"], "AMESim 组件库") self.assertEqual([category["id"] for category in library["categories"]], ["storage", "flow", "junctions", "boundary"]) self.assertEqual(set(components), {"amesim_pnpl01", "amesim_pnch023", "amesim_pnor001", "amesim_pnvo001_fixed", "amesim_pnl00r", "amesim_pn3node2", "amesim_p4node2"}) self.assertEqual( [port["name"] for port in components["amesim_p4node2"]["ports"]], ["port_1", "port_2", "port_3", "port_4"], ) self.assertEqual(components["amesim_pnpl01"]["category"]["id"], "boundary") self.assertEqual([port["name"] for port in components["amesim_pnpl01"]["ports"]], ["port_1"]) pnch_parameters = { parameter["name"]: parameter for parameter in components["amesim_pnch023"]["parameters"] } self.assertEqual(components["amesim_pnch023"]["category"]["id"], "storage") self.assertEqual(pnch_parameters["cvol"]["quantity"], "volume") self.assertEqual(pnch_parameters["kth"]["quantity"], "heat_transfer_coefficient") pnor_parameters = { parameter["name"]: parameter for parameter in components["amesim_pnor001"]["parameters"] } self.assertEqual(components["amesim_pnor001"]["category"]["id"], "flow") self.assertEqual(pnor_parameters["area"]["quantity"], "area") self.assertEqual(pnor_parameters["area"]["unit"], "m2") pnvo_parameters = { parameter["name"]: parameter for parameter in components["amesim_pnvo001_fixed"]["parameters"] } self.assertEqual(components["amesim_pnvo001_fixed"]["category"]["id"], "flow") self.assertEqual(pnvo_parameters["opening"]["maximum"], 1.0) self.assertEqual([port["name"] for port in components["amesim_pnvo001_fixed"]["ports"]], ["port_2", "port_3"]) pnl_parameters = { parameter["name"]: parameter for parameter in components["amesim_pnl00r"]["parameters"] } self.assertEqual(components["amesim_pnl00r"]["category"]["id"], "flow") self.assertEqual(pnl_parameters["diam"]["quantity"], "length") self.assertEqual(pnl_parameters["le"]["unit"], "m") def test_every_registered_component_is_in_the_catalog(self) -> None: self.assertEqual( set(self.components), set(COMPONENT_MODEL_REGISTRY), ) def test_catalog_reuses_model_parameter_contracts(self) -> None: cylinder = self.components["cylinder"] parameters = { parameter["name"]: parameter for parameter in cylinder["parameters"] } self.assertEqual(cylinder["label"], "气瓶") self.assertEqual(cylinder["modelVersion"], "1.0.0") self.assertEqual(parameters["volume"]["default"], 0.01) self.assertEqual(parameters["volume"]["quantity"], "volume") self.assertEqual(parameters["p0"]["unit"], "Pa") self.assertTrue(parameters["p0"]["minimumExclusive"]) def test_catalog_adds_port_layout_without_changing_physical_contract(self) -> None: tee_ports = { port["name"]: port for port in self.components["tee"]["ports"] } self.assertEqual(tee_ports["port_in"]["side"], "left") self.assertEqual(tee_ports["port_out1"]["side"], "right") self.assertEqual(tee_ports["port_out2"]["side"], "right") self.assertEqual(tee_ports["port_in"]["kind"], "physical") self.assertEqual(tee_ports["port_in"]["domain"], "pneumatic") self.assertEqual(tee_ports["port_in"]["nominalRole"], "bidirectional") def test_registry_can_repeat_discovery_and_validation(self) -> None: validate_component_registries() def test_catalog_schema_is_committed_and_targets_version_one(self) -> None: schema_path = ( Path(__file__).resolve().parent.parent / "schemas" / "component-catalog-v1.schema.json" ) schema = json.loads(schema_path.read_text(encoding="utf-8")) self.assertEqual(schema["properties"]["schemaVersion"]["const"], 1) self.assertIn("modelVersion", schema["$defs"]["component"]["required"]) self.assertIn("version", schema["$defs"]["library"]["required"]) if __name__ == "__main__": unittest.main()