207 lines
10 KiB
Python
207 lines
10 KiB
Python
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", "signals", "mechanical"])
|
|
self.assertEqual(set(components), {"amesim_pnpl01", "amesim_step0", "amesim_ud00", "amesim_f000", "amesim_forc", "amesim_mecmas21", "amesim_lstp00a", "amesim_lmechn1", "amesim_pnch023", "amesim_pnch012", "amesim_pnor001", "amesim_pnvo001_fixed", "amesim_pnvo001", "amesim_pnl00r", "amesim_pnl0001", "amesim_pnl0002", "amesim_pnl0003", "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")
|
|
|
|
pnch012_parameters = {
|
|
parameter["name"]: parameter
|
|
for parameter in components["amesim_pnch012"]["parameters"]
|
|
}
|
|
self.assertEqual(components["amesim_pnch012"]["category"]["id"], "storage")
|
|
self.assertEqual([port["name"] for port in components["amesim_pnch012"]["ports"]], ["port_1", "port_2", "port_3", "port_4"])
|
|
self.assertEqual(pnch012_parameters["cvol0"]["quantity"], "volume")
|
|
self.assertEqual(pnch012_parameters["dvol1"]["unit"], "m3/s")
|
|
|
|
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"])
|
|
|
|
self.assertEqual(components["amesim_step0"]["category"]["id"], "signals")
|
|
self.assertEqual([port["name"] for port in components["amesim_step0"]["ports"]], ["out"])
|
|
ud00_parameters = {
|
|
parameter["name"]: parameter
|
|
for parameter in components["amesim_ud00"]["parameters"]
|
|
}
|
|
self.assertEqual(components["amesim_ud00"]["category"]["id"], "signals")
|
|
self.assertEqual([port["name"] for port in components["amesim_ud00"]["ports"]], ["out"])
|
|
self.assertEqual(ud00_parameters["tstart"]["quantity"], "time")
|
|
self.assertEqual(ud00_parameters["nstages"]["maximum"], 8.0)
|
|
self.assertEqual(components["amesim_f000"]["category"]["id"], "mechanical")
|
|
self.assertEqual([port["name"] for port in components["amesim_f000"]["ports"]], ["port_1"])
|
|
self.assertEqual(components["amesim_f000"]["ports"][0]["domain"], "mechanical")
|
|
self.assertEqual(components["amesim_forc"]["category"]["id"], "mechanical")
|
|
self.assertEqual([port["name"] for port in components["amesim_forc"]["ports"]], ["res", "port_2"])
|
|
self.assertEqual(components["amesim_forc"]["ports"][1]["domain"], "mechanical")
|
|
mecmas_parameters = {
|
|
parameter["name"]: parameter
|
|
for parameter in components["amesim_mecmas21"]["parameters"]
|
|
}
|
|
self.assertEqual(components["amesim_mecmas21"]["category"]["id"], "mechanical")
|
|
self.assertEqual([port["name"] for port in components["amesim_mecmas21"]["ports"]], ["port_1", "port_2"])
|
|
self.assertEqual(mecmas_parameters["mass"]["unit"], "kg")
|
|
self.assertEqual(mecmas_parameters["Kbmin"]["unit"], "N/m")
|
|
lstp_parameters = {
|
|
parameter["name"]: parameter
|
|
for parameter in components["amesim_lstp00a"]["parameters"]
|
|
}
|
|
self.assertEqual(components["amesim_lstp00a"]["category"]["id"], "mechanical")
|
|
self.assertEqual([port["name"] for port in components["amesim_lstp00a"]["ports"]], ["port_1", "port_2"])
|
|
self.assertEqual(lstp_parameters["gap0"]["unit"], "m")
|
|
self.assertEqual(lstp_parameters["kcont"]["unit"], "N/m")
|
|
lmechn_parameters = {
|
|
parameter["name"]: parameter
|
|
for parameter in components["amesim_lmechn1"]["parameters"]
|
|
}
|
|
self.assertEqual(components["amesim_lmechn1"]["category"]["id"], "mechanical")
|
|
self.assertEqual([port["name"] for port in components["amesim_lmechn1"]["ports"]], [f"port_{index}" for index in range(1, 10)])
|
|
self.assertEqual(lmechn_parameters["v1"]["maximum"], 8.0)
|
|
self.assertEqual(components["amesim_pnvo001"]["category"]["id"], "flow")
|
|
self.assertEqual([port["name"] for port in components["amesim_pnvo001"]["ports"]], ["res", "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")
|
|
|
|
pnl0001_parameters = {
|
|
parameter["name"]: parameter
|
|
for parameter in components["amesim_pnl0001"]["parameters"]
|
|
}
|
|
self.assertEqual(components["amesim_pnl0001"]["category"]["id"], "flow")
|
|
self.assertEqual(pnl0001_parameters["kth"]["quantity"], "heat_transfer_coefficient")
|
|
self.assertEqual(pnl0001_parameters["p0"]["unit"], "Pa")
|
|
|
|
self.assertEqual(components["amesim_pnl0002"]["category"]["id"], "flow")
|
|
self.assertEqual(components["amesim_pnl0003"]["category"]["id"], "flow")
|
|
pnl0003_parameters = {
|
|
parameter["name"]: parameter
|
|
for parameter in components["amesim_pnl0003"]["parameters"]
|
|
}
|
|
self.assertEqual(pnl0003_parameters["p1_0"]["unit"], "Pa")
|
|
self.assertEqual(pnl0003_parameters["T2_0"]["quantity"], "temperature")
|
|
|
|
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()
|