From 41c022791c0dfb382c28346b3bc228096e54d6d6 Mon Sep 17 00:00:00 2001 From: Montana Date: Fri, 18 Sep 2026 08:09:51 -0700 Subject: [PATCH] fix(bindings): prevent empty-model dereference in Janus representation --- Python/src/pyJanus.cpp | 8 ++--- Python/tests/test_janus_representation.py | 39 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 Python/tests/test_janus_representation.py diff --git a/Python/src/pyJanus.cpp b/Python/src/pyJanus.cpp index 4310d6c..947067f 100644 --- a/Python/src/pyJanus.cpp +++ b/Python/src/pyJanus.cpp @@ -51,19 +51,19 @@ void init_Janus(py::module_ &m) .def_property_readonly("xml_filename", &Janus::getXmlFileName) .def("__repr__", - [](Janus &self) + [](const Janus &self) { std::ostringstream out; - out << "Janus(xml_filename='" << self.getXmlFileName() << ")" + out << "Janus(xml_filename='" << self.getXmlFileName() << "')" << " at JanusInstance<" - << self.getVariableDef().front().getJanusInstance() << ">"; + << &self << ">"; return out.str(); }) .def("__str__", [](const Janus &self) { std::ostringstream out; - out << "Janus(xml_filename='" << self.getXmlFileName() << ")"; + out << "Janus(xml_filename='" << self.getXmlFileName() << "')"; return out.str(); }); } diff --git a/Python/tests/test_janus_representation.py b/Python/tests/test_janus_representation.py new file mode 100644 index 0000000..8a37ed7 --- /dev/null +++ b/Python/tests/test_janus_representation.py @@ -0,0 +1,39 @@ +import os +import re +import subprocess +import sys + +import pyJanus + + +def test_empty_janus_repr(): + # Isolate the call so a native crash is reported as a test failure instead + # of terminating the entire test suite. + result = subprocess.run( + [sys.executable, "-c", "import pyJanus; print(repr(pyJanus.Janus()))"], + capture_output=True, + text=True, + timeout=30, + ) + + assert result.returncode == 0, result.stderr + assert re.fullmatch( + r"Janus\(xml_filename=''\) at JanusInstance<[^<>\s]+>\n", + result.stdout, + ) + + +def test_empty_janus_str(): + text = str(pyJanus.Janus()) + assert text == "Janus(xml_filename='')" + + +def test_loaded_janus_representation(): + xml_path = f"{os.path.dirname(__file__)}/../../Examples/CombinedExample.xml" + janus = pyJanus.Janus(xml_path) + expected = f"Janus(xml_filename='{janus.xml_filename}')" + variable = janus.get_variabledef("angleOfAttack") + instance = repr(variable).split(" from ", 1)[1] + + assert str(janus) == expected + assert repr(janus) == f"{expected} at {instance}"