From aac8695694ea06b1d6892cccc5d0c20163b1191f Mon Sep 17 00:00:00 2001 From: yadavchiragg Date: Fri, 13 Nov 2026 08:32:20 +0530 Subject: [PATCH] fix(mkconcore): copy MATLAB literal helper files into generated studies --- mkconcore.py | 8 ++++ tests/test_matlab_runtime_files.py | 66 ++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/test_matlab_runtime_files.py diff --git a/mkconcore.py b/mkconcore.py index a1f44ef..a7cd94d 100644 --- a/mkconcore.py +++ b/mkconcore.py @@ -732,6 +732,14 @@ def cleanup_script_files(): with open(outdir+"/src/concore_oport.m","w") as fcopy: fcopy.write(fsource.read()) fsource.close() + fsource = open(CONCOREPATH+"/concore_literal_eval.m") + with open(outdir+"/src/concore_literal_eval.m","w") as fcopy: fcopy.write(fsource.read()) + fsource.close() + + fsource = open(CONCOREPATH+"/concore_literal_serialize.m") + with open(outdir+"/src/concore_literal_serialize.m","w") as fcopy: fcopy.write(fsource.read()) + fsource.close() + if concoretype=="docker": fsource = open(CONCOREPATH+"/import_concoredocker.m") else: diff --git a/tests/test_matlab_runtime_files.py b/tests/test_matlab_runtime_files.py new file mode 100644 index 0000000..99513e5 --- /dev/null +++ b/tests/test_matlab_runtime_files.py @@ -0,0 +1,66 @@ +"""Generated MATLAB/Octave studies must ship every runtime file they call. + +concore_read.m, concore_write.m and concore_initval.m call +concore_literal_eval / concore_literal_serialize. mkconcore.py copies the +runtime .m files one by one, and these two helpers used to be missing from +the generated src/ folder, so a MATLAB node failed on its first read/write. +""" + +import re +import subprocess +import sys +from pathlib import Path + +import pytest + +REPO_ROOT = Path(__file__).resolve().parent.parent +GRAPH = REPO_ROOT / "demo" / "sampleM.graphml" +HELPERS = ("concore_literal_eval.m", "concore_literal_serialize.m") + + +def _generate(tmp_path, concoretype): + out = tmp_path / f"out_{concoretype}" + result = subprocess.run( + [ + sys.executable, + str(REPO_ROOT / "mkconcore.py"), + str(GRAPH), + str(REPO_ROOT / "demo"), + str(out), + concoretype, + ], + capture_output=True, + text=True, + cwd=str(REPO_ROOT), + ) + assert result.returncode == 0, result.stderr + return out + + +@pytest.mark.parametrize("concoretype", ["posix", "windows", "docker"]) +def test_literal_helpers_are_copied(tmp_path, concoretype): + src = _generate(tmp_path, concoretype) / "src" + for name in HELPERS: + assert (src / name).is_file(), f"{name} missing from generated src/" + + +@pytest.mark.parametrize("concoretype", ["posix", "windows", "docker"]) +def test_every_concore_function_called_is_present(tmp_path, concoretype): + """Any concore_* function referenced by a copied runtime file must exist.""" + src = _generate(tmp_path, concoretype) / "src" + available = {p.stem for p in src.glob("concore_*.m")} + missing = set() + for runtime_file in src.glob("concore_*.m"): + text = runtime_file.read_text() + for called in re.findall(r"\bconcore_[a-z_]+\b", text): + if called not in available and called != runtime_file.stem: + missing.add((runtime_file.name, called)) + assert not missing, f"runtime files call functions that were not copied: {missing}" + + +@pytest.mark.parametrize("concoretype", ["posix", "windows"]) +def test_build_script_copies_helpers_into_node_folders(tmp_path, concoretype): + """The build script must use a glob (not a fixed list) so helpers reach nodes.""" + out = _generate(tmp_path, concoretype) + script = out / ("build.bat" if concoretype == "windows" else "build") + assert "concore_*.m" in script.read_text()