Files
SystemSimulationApp/tests/test_system_xml_v3.py

201 lines
7.0 KiB
Python

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()