Skip to content

Commit 04bfc48

Browse files
committed
more unit tests
1 parent 88fc7c6 commit 04bfc48

2 files changed

Lines changed: 161 additions & 40 deletions

File tree

open-codegen/opengen/templates/c/example_optimizer_c_bindings.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ int main(void) {
4848
int i;
4949

5050
/* parameters */
51-
double p[{{meta.optimizer_name|upper}}_NUM_PARAMETERS] = {2.0, 10.0};
51+
double p[{{meta.optimizer_name|upper}}_NUM_PARAMETERS] = {0};
5252

5353
/* initial guess */
5454
double u[{{meta.optimizer_name|upper}}_NUM_DECISION_VARIABLES] = {0};

open-codegen/test/test.py

Lines changed: 160 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,8 @@ def setUpSolverError(cls):
304304
.with_open_version(local_path=RustBuildTestCase.get_open_local_absolute_path()) \
305305
.with_build_directory(RustBuildTestCase.TEST_DIR) \
306306
.with_build_mode(og.config.BuildConfiguration.DEBUG_MODE) \
307-
.with_tcp_interface_config(tcp_interface_config=tcp_config)
307+
.with_tcp_interface_config(tcp_interface_config=tcp_config) \
308+
.with_build_c_bindings()
308309
og.builder.OpEnOptimizerBuilder(problem,
309310
metadata=meta,
310311
build_configuration=build_config,
@@ -791,48 +792,168 @@ def test_rust_build_parametric_halfspace(self):
791792
self.assertTrue(sum([u[i] * c[i] for i in range(5)]) - b <= eps)
792793
self.assertTrue(-sum([u[i] * c[i] for i in range(5)]) + b <= eps)
793794

795+
@staticmethod
796+
def rebuild_generated_staticlib(optimizer_name):
797+
optimizer_dir = os.path.join(RustBuildTestCase.TEST_DIR, optimizer_name)
798+
process = subprocess.Popen(
799+
["cargo", "build"],
800+
cwd=optimizer_dir,
801+
stdout=subprocess.PIPE,
802+
stderr=subprocess.PIPE,
803+
)
804+
_stdout, stderr = process.communicate()
805+
return process.returncode, stderr.decode()
806+
794807
@staticmethod
795808
def c_bindings_helper(optimizer_name):
796-
p = subprocess.Popen(["/usr/bin/gcc",
797-
RustBuildTestCase.TEST_DIR + "/" + optimizer_name + "/example_optimizer.c",
798-
"-I" + RustBuildTestCase.TEST_DIR + "/" + optimizer_name,
799-
"-pthread",
800-
RustBuildTestCase.TEST_DIR + "/" + optimizer_name +
801-
"/target/debug/lib" + optimizer_name + ".a",
802-
"-lm",
803-
"-ldl",
804-
"-std=c99",
805-
"-o",
806-
RustBuildTestCase.TEST_DIR + "/" + optimizer_name + "/optimizer"],
807-
stdout=subprocess.PIPE,
808-
stderr=subprocess.PIPE)
809-
810-
# Make sure it compiles
811-
p.communicate()
812-
rc1 = p.returncode
813-
814-
# Run the optimizer
815-
p = subprocess.Popen([RustBuildTestCase.TEST_DIR + "/" + optimizer_name + "/optimizer"],
816-
stdout=subprocess.DEVNULL)
817-
p.communicate()
818-
rc2 = p.returncode
819-
820-
return rc1, rc2
809+
compile_process = subprocess.Popen(
810+
["/usr/bin/gcc",
811+
RustBuildTestCase.TEST_DIR + "/" + optimizer_name + "/example_optimizer.c",
812+
"-I" + RustBuildTestCase.TEST_DIR + "/" + optimizer_name,
813+
"-pthread",
814+
RustBuildTestCase.TEST_DIR + "/" + optimizer_name +
815+
"/target/debug/lib" + optimizer_name + ".a",
816+
"-lm",
817+
"-ldl",
818+
"-std=c99",
819+
"-o",
820+
RustBuildTestCase.TEST_DIR + "/" + optimizer_name + "/optimizer"],
821+
stdout=subprocess.PIPE,
822+
stderr=subprocess.PIPE)
823+
824+
compile_stdout, compile_stderr = compile_process.communicate()
825+
826+
run_stdout = b""
827+
run_stderr = b""
828+
run_returncode = None
829+
if compile_process.returncode == 0:
830+
run_process = subprocess.Popen(
831+
[RustBuildTestCase.TEST_DIR + "/" + optimizer_name + "/optimizer"],
832+
stdout=subprocess.PIPE,
833+
stderr=subprocess.PIPE)
834+
run_stdout, run_stderr = run_process.communicate()
835+
run_returncode = run_process.returncode
836+
837+
return {
838+
"compile_returncode": compile_process.returncode,
839+
"compile_stdout": compile_stdout.decode(),
840+
"compile_stderr": compile_stderr.decode(),
841+
"run_returncode": run_returncode,
842+
"run_stdout": run_stdout.decode(),
843+
"run_stderr": run_stderr.decode(),
844+
}
845+
846+
@staticmethod
847+
def patch_c_bindings_example_parameter_initializer(optimizer_name, replacement_line):
848+
example_file = os.path.join(
849+
RustBuildTestCase.TEST_DIR, optimizer_name, "example_optimizer.c")
850+
with open(example_file, "r", encoding="utf-8") as fh:
851+
example_source = fh.read()
852+
853+
original_line = None
854+
for line in example_source.splitlines():
855+
if "double p[" in line and "= {" in line:
856+
original_line = line
857+
break
858+
859+
if original_line is None:
860+
raise RuntimeError("Could not locate parameter initializer in example_optimizer.c")
861+
862+
with open(example_file, "w", encoding="utf-8") as fh:
863+
fh.write(example_source.replace(original_line, replacement_line, 1))
864+
865+
return original_line
866+
867+
@staticmethod
868+
def c_bindings_cmake_helper(optimizer_name):
869+
cmake_executable = shutil.which("cmake")
870+
if cmake_executable is None:
871+
raise unittest.SkipTest("cmake is not available in PATH")
872+
873+
optimizer_dir = os.path.join(RustBuildTestCase.TEST_DIR, optimizer_name)
874+
build_dir = os.path.join(optimizer_dir, "cmake-build-test")
875+
if os.path.isdir(build_dir):
876+
shutil.rmtree(build_dir)
877+
os.makedirs(build_dir)
878+
879+
configure_process = subprocess.Popen(
880+
[cmake_executable, ".."],
881+
cwd=build_dir,
882+
stdout=subprocess.PIPE,
883+
stderr=subprocess.PIPE,
884+
)
885+
configure_stdout, configure_stderr = configure_process.communicate()
886+
887+
build_stdout = b""
888+
build_stderr = b""
889+
build_returncode = None
890+
if configure_process.returncode == 0:
891+
build_process = subprocess.Popen(
892+
[cmake_executable, "--build", "."],
893+
cwd=build_dir,
894+
stdout=subprocess.PIPE,
895+
stderr=subprocess.PIPE,
896+
)
897+
build_stdout, build_stderr = build_process.communicate()
898+
build_returncode = build_process.returncode
899+
900+
return {
901+
"configure_returncode": configure_process.returncode,
902+
"configure_stdout": configure_stdout.decode(),
903+
"configure_stderr": configure_stderr.decode(),
904+
"build_returncode": build_returncode,
905+
"build_stdout": build_stdout.decode(),
906+
"build_stderr": build_stderr.decode(),
907+
}
821908

822909
def test_c_bindings(self):
823-
rc1, rc2 = RustBuildTestCase.c_bindings_helper(
824-
optimizer_name="only_f1")
825-
self.assertEqual(0, rc1)
826-
self.assertEqual(0, rc2)
827-
828-
rc1, rc2 = RustBuildTestCase.c_bindings_helper(
829-
optimizer_name="only_f2")
830-
self.assertEqual(0, rc1)
831-
self.assertEqual(0, rc2)
832-
833-
rc1, rc2 = RustBuildTestCase.c_bindings_helper(optimizer_name="plain")
834-
self.assertEqual(0, rc1)
835-
self.assertEqual(0, rc2)
910+
result = RustBuildTestCase.c_bindings_helper(optimizer_name="only_f1")
911+
self.assertEqual(0, result["compile_returncode"], msg=result["compile_stderr"])
912+
self.assertEqual(0, result["run_returncode"], msg=result["run_stderr"])
913+
self.assertIn("Converged", result["run_stdout"])
914+
self.assertIn("exit status : 0", result["run_stdout"])
915+
self.assertIn("error code : 0", result["run_stdout"])
916+
917+
result = RustBuildTestCase.c_bindings_helper(optimizer_name="only_f2")
918+
self.assertEqual(0, result["compile_returncode"], msg=result["compile_stderr"])
919+
self.assertIn("Converged", result["run_stdout"])
920+
self.assertEqual(0, result["run_returncode"], msg=result["run_stderr"])
921+
self.assertIn("exit status : 0", result["run_stdout"])
922+
self.assertIn("error code : 0", result["run_stdout"])
923+
924+
result = RustBuildTestCase.c_bindings_helper(optimizer_name="plain")
925+
self.assertIn("Converged", result["run_stdout"])
926+
self.assertEqual(0, result["compile_returncode"], msg=result["compile_stderr"])
927+
self.assertEqual(0, result["run_returncode"], msg=result["run_stderr"])
928+
self.assertIn("exit status : 0", result["run_stdout"])
929+
self.assertIn("error code : 0", result["run_stdout"])
930+
931+
def test_c_bindings_error_path(self):
932+
rebuild_rc, rebuild_stderr = RustBuildTestCase.rebuild_generated_staticlib(
933+
optimizer_name="solver_error")
934+
self.assertEqual(0, rebuild_rc, msg=rebuild_stderr)
935+
936+
original_line = RustBuildTestCase.patch_c_bindings_example_parameter_initializer(
937+
optimizer_name="solver_error",
938+
replacement_line=" double p[SOLVER_ERROR_NUM_PARAMETERS] = {-1.0};")
939+
try:
940+
result = RustBuildTestCase.c_bindings_helper(optimizer_name="solver_error")
941+
finally:
942+
RustBuildTestCase.patch_c_bindings_example_parameter_initializer(
943+
optimizer_name="solver_error",
944+
replacement_line=original_line)
945+
self.assertEqual(0, result["compile_returncode"], msg=result["compile_stderr"])
946+
self.assertNotEqual(0, result["run_returncode"])
947+
self.assertIn("error code : 2000", result["run_stdout"])
948+
self.assertIn("forced solver error for TCP test", result["run_stdout"])
949+
self.assertIn(
950+
"Solver returned an error; solution vector is not printed.",
951+
result["run_stderr"])
952+
953+
def test_c_bindings_cmake_example_builds(self):
954+
result = RustBuildTestCase.c_bindings_cmake_helper(optimizer_name="plain")
955+
self.assertEqual(0, result["configure_returncode"], msg=result["configure_stderr"])
956+
self.assertEqual(0, result["build_returncode"], msg=result["build_stderr"])
836957

837958
def test_tcp_generated_server_builds(self):
838959
tcp_iface_dir = os.path.join(

0 commit comments

Comments
 (0)