#include "posix.h" #include #include #include "args.h" #include "backend/output.h" #include "buf_size.h" #include "lang/serial.h" #include "log.h" #include "platform/filesystem.h" #include "platform/mem.h" #include "platform/path.h" #include "platform/run_cmd.h" #include "tests.h" static enum iteration_result run_test(struct workspace *wk, void *_ctx, uint32_t t) { struct obj *test = get_obj(wk, t); uint32_t cmdline; make_obj(wk, &cmdline, obj_array); obj_array_push(wk, cmdline, test->dat.test.exe); if (test->dat.test.args) { uint32_t test_args; if (!arr_to_args(wk, test->dat.test.args, &test_args)) { return ir_err; } obj_array_extend(wk, cmdline, test_args); } const char *argv[MAX_ARGS]; char *const *envp = NULL; if (!join_args_argv(wk, argv, MAX_ARGS, cmdline)) { LOG_E("failed to prepare arguments"); return ir_err; } if (!env_to_envp(wk, 0, &envp, test->dat.test.env, 0)) { LOG_E("failed to prepare environment"); return ir_err; } enum iteration_result ret = ir_err; struct run_cmd_ctx cmd_ctx = { 0 }; if (!run_cmd(&cmd_ctx, get_cstr(wk, test->dat.test.exe), argv, envp)) { LOG_E("test command failed: %s", cmd_ctx.err_msg); goto ret; } if (cmd_ctx.status && !test->dat.test.should_fail) { LOG_E("%s - failed (%d)", get_cstr(wk, test->dat.test.name), cmd_ctx.status); LOG_E("stdout: '%s'", cmd_ctx.out); LOG_E("stderr: '%s'", cmd_ctx.err); goto ret; } else { LOG_I("%s - success (%d)", get_cstr(wk, test->dat.test.name), cmd_ctx.status); } ret = ir_cont; ret: run_cmd_ctx_destroy(&cmd_ctx); return ret; } static enum iteration_result run_project_tests(struct workspace *wk, void *_ctx, uint32_t proj_name, uint32_t tests) { LOG_I("running tests for project '%s'", get_cstr(wk, proj_name)); if (!obj_array_foreach(wk, tests, NULL, run_test)) { return ir_err; } return ir_cont; } bool tests_run(const char *build_dir) { bool ret = false; char tests_src[PATH_MAX], private[PATH_MAX], build_root[PATH_MAX]; if (!path_make_absolute(build_root, PATH_MAX, build_dir)) { return false; } else if (!path_join(private, PATH_MAX, build_root, output_path.private_dir)) { return false; } else if (!path_join(tests_src, PATH_MAX, private, output_path.tests)) { return false; } FILE *f; if (!(f = fs_fopen(tests_src, "r"))) { return false; } struct workspace wk; workspace_init_bare(&wk); uint32_t tests_dict; if (!serial_load(&wk, &tests_dict, f)) { LOG_E("invalid tests file"); goto ret; } else if (!fs_fclose(f)) { goto ret; } else if (!path_chdir(build_root)) { goto ret; } else if (!obj_dict_foreach(&wk, tests_dict, NULL, run_project_tests)) { goto ret; } ret = true; ret: workspace_destroy_bare(&wk); return ret; }