完善建模交互、组件图标与系统协议
This commit is contained in:
1 parent
456c29b3b6
commit
6572defaa4
66 files changed
+10067
-4163
No files matched your search
@@ -0,0 +1,200 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import replace
|
||||
import unittest
|
||||
|
||||
from app.main import compile_system_xml_network
|
||||
from app.system_xml import validate_system_xml_document
|
||||
|
||||
|
||||
def physical_system_xml() -> str:
|
||||
return """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<System schemaVersion="3" unitSystem="SI">
|
||||
<Simulation tStart="1" tStop="5" sampleStep="0.2" maxStep="0.01" method="BDF"/>
|
||||
<Components>
|
||||
<Component id="cylinder_1" type="cylinder" modelVersion="1.0.0">
|
||||
<Parameter name="volume" value="0.01"/>
|
||||
<Parameter name="p0" value="35000000"/>
|
||||
<Parameter name="T0" value="300"/>
|
||||
</Component>
|
||||
<Component id="tank_1" type="tank" modelVersion="1.0.0">
|
||||
<Parameter name="volume" value="0.1"/>
|
||||
<Parameter name="p0" value="100000"/>
|
||||
<Parameter name="T0" value="300"/>
|
||||
</Component>
|
||||
</Components>
|
||||
<Connections>
|
||||
<Connection>
|
||||
<Endpoint component="cylinder_1" port="port_b"/>
|
||||
<Endpoint component="tank_1" port="port_a"/>
|
||||
</Connection>
|
||||
</Connections>
|
||||
</System>
|
||||
"""
|
||||
|
||||
|
||||
def issue_codes(xml: str) -> set[str]:
|
||||
return {issue.code for issue in validate_system_xml_document(xml).issues}
|
||||
|
||||
|
||||
class SystemXmlV3Tests(unittest.TestCase):
|
||||
def test_minimal_execution_model_is_valid(self) -> None:
|
||||
report = validate_system_xml_document(physical_system_xml())
|
||||
|
||||
self.assertTrue(report.valid)
|
||||
self.assertEqual(report.issues, ())
|
||||
assert report.document is not None
|
||||
self.assertEqual(report.document.connections[0].id, "connection_1")
|
||||
model = report.document.as_model_data()
|
||||
self.assertEqual(model["name"], "untitled")
|
||||
self.assertEqual(model["simulation"]["sample_step"], 0.2)
|
||||
self.assertEqual(model["components"][0]["model_version"], "1.0.0")
|
||||
|
||||
def test_editor_and_port_snapshot_fields_are_rejected(self) -> None:
|
||||
xml = physical_system_xml().replace(
|
||||
'modelVersion="1.0.0">',
|
||||
'modelVersion="1.0.0" x="10">\n <Port name="port_b"/>',
|
||||
1,
|
||||
)
|
||||
|
||||
report = validate_system_xml_document(xml)
|
||||
|
||||
self.assertFalse(report.valid)
|
||||
self.assertIsNone(report.document)
|
||||
self.assertTrue(all(issue.layer == "schema" for issue in report.issues))
|
||||
|
||||
def test_model_version_is_checked_against_registry(self) -> None:
|
||||
xml = physical_system_xml().replace(
|
||||
'type="cylinder" modelVersion="1.0.0"',
|
||||
'type="cylinder" modelVersion="9.9.9"',
|
||||
)
|
||||
|
||||
self.assertIn("COMPONENT_MODEL_VERSION_MISMATCH", issue_codes(xml))
|
||||
|
||||
def test_direct_compiler_defends_the_model_version_contract(self) -> None:
|
||||
report = validate_system_xml_document(physical_system_xml())
|
||||
assert report.document is not None
|
||||
first = replace(
|
||||
report.document.components[0],
|
||||
model_version="9.9.9",
|
||||
)
|
||||
document = replace(
|
||||
report.document,
|
||||
components=(first, *report.document.components[1:]),
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(ValueError, "expected '1.0.0'"):
|
||||
compile_system_xml_network(document)
|
||||
|
||||
def test_component_cannot_connect_two_of_its_own_ports(self) -> None:
|
||||
xml = """<System schemaVersion="3" unitSystem="SI">
|
||||
<Simulation tStart="0" tStop="1" sampleStep="0.1" maxStep="0.01" method="BDF"/>
|
||||
<Components>
|
||||
<Component id="pipe_1" type="pipe" modelVersion="1.0.0">
|
||||
<Parameter name="length" value="1"/>
|
||||
<Parameter name="diameter" value="0.02"/>
|
||||
<Parameter name="lambda_darcy" value="0.02"/>
|
||||
<Parameter name="p0" value="100000"/>
|
||||
<Parameter name="T0" value="300"/>
|
||||
</Component>
|
||||
</Components>
|
||||
<Connections>
|
||||
<Connection>
|
||||
<Endpoint component="pipe_1" port="port_a"/>
|
||||
<Endpoint component="pipe_1" port="port_b"/>
|
||||
</Connection>
|
||||
</Connections>
|
||||
</System>"""
|
||||
|
||||
self.assertIn("CONNECTION_SELF_REFERENCE", issue_codes(xml))
|
||||
|
||||
def test_signal_direction_is_derived_from_registered_ports(self) -> None:
|
||||
xml = """<System schemaVersion="3" unitSystem="SI">
|
||||
<Simulation tStart="0" tStop="1" sampleStep="0.1" maxStep="0.01" method="BDF"/>
|
||||
<Components>
|
||||
<Component id="step_1" type="amesim_step0" modelVersion="0.1.0">
|
||||
<Parameter name="initial" value="0"/>
|
||||
<Parameter name="final" value="1"/>
|
||||
<Parameter name="time" value="0"/>
|
||||
</Component>
|
||||
<Component id="step_2" type="amesim_step0" modelVersion="0.1.0">
|
||||
<Parameter name="initial" value="0"/>
|
||||
<Parameter name="final" value="1"/>
|
||||
<Parameter name="time" value="0"/>
|
||||
</Component>
|
||||
</Components>
|
||||
<Connections>
|
||||
<Connection id="signal_1">
|
||||
<Endpoint component="step_1" port="out"/>
|
||||
<Endpoint component="step_2" port="out"/>
|
||||
</Connection>
|
||||
</Connections>
|
||||
</System>"""
|
||||
|
||||
self.assertIn("SIGNAL_PORT_ROLES_INVALID", issue_codes(xml))
|
||||
|
||||
def test_signal_input_rejects_multiple_drivers_but_output_may_fan_out(self) -> None:
|
||||
components = """
|
||||
<Component id="step_1" type="amesim_step0" modelVersion="0.1.0">
|
||||
<Parameter name="initial" value="0"/>
|
||||
<Parameter name="final" value="1"/>
|
||||
<Parameter name="time" value="0"/>
|
||||
</Component>
|
||||
<Component id="step_2" type="amesim_step0" modelVersion="0.1.0">
|
||||
<Parameter name="initial" value="1"/>
|
||||
<Parameter name="final" value="0"/>
|
||||
<Parameter name="time" value="0"/>
|
||||
</Component>
|
||||
<Component id="force_1" type="amesim_forc" modelVersion="0.2.0">
|
||||
<Parameter name="direction" value="1"/>
|
||||
</Component>
|
||||
<Component id="force_2" type="amesim_forc" modelVersion="0.2.0">
|
||||
<Parameter name="direction" value="1"/>
|
||||
</Component>"""
|
||||
|
||||
def signal_xml(connections: str) -> str:
|
||||
return f"""<System schemaVersion="3" unitSystem="SI">
|
||||
<Simulation tStart="0" tStop="1" sampleStep="0.1" maxStep="0.01" method="BDF"/>
|
||||
<Components>{components}
|
||||
</Components>
|
||||
<Connections>{connections}
|
||||
</Connections>
|
||||
</System>"""
|
||||
|
||||
multiple_drivers = signal_xml("""
|
||||
<Connection id="signal_1">
|
||||
<Endpoint component="step_1" port="out"/>
|
||||
<Endpoint component="force_1" port="res"/>
|
||||
</Connection>
|
||||
<Connection id="signal_2">
|
||||
<Endpoint component="step_2" port="out"/>
|
||||
<Endpoint component="force_1" port="res"/>
|
||||
</Connection>""")
|
||||
fan_out = signal_xml("""
|
||||
<Connection id="signal_1">
|
||||
<Endpoint component="step_1" port="out"/>
|
||||
<Endpoint component="force_1" port="res"/>
|
||||
</Connection>
|
||||
<Connection id="signal_2">
|
||||
<Endpoint component="step_1" port="out"/>
|
||||
<Endpoint component="force_2" port="res"/>
|
||||
</Connection>""")
|
||||
|
||||
self.assertIn(
|
||||
"SIGNAL_INPUT_MULTIPLE_DRIVERS",
|
||||
issue_codes(multiple_drivers),
|
||||
)
|
||||
self.assertTrue(validate_system_xml_document(fan_out).valid)
|
||||
|
||||
def test_v2_step_name_is_not_accepted(self) -> None:
|
||||
xml = physical_system_xml().replace('sampleStep="0.2"', 'step="0.2"')
|
||||
|
||||
report = validate_system_xml_document(xml)
|
||||
|
||||
self.assertFalse(report.valid)
|
||||
self.assertIsNone(report.document)
|
||||
self.assertIn("XSD_VALIDATION_ERROR", issue_codes(xml))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user