diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | tests/include/testing.h | 46 | ||||
| -rw-r--r-- | tests/setup.sh | 4 | ||||
| -rw-r--r-- | tests/test_artifactory.c | 15 | ||||
| -rw-r--r-- | tests/test_conda.c | 30 | ||||
| -rw-r--r-- | tests/test_docker.c | 2 | ||||
| -rw-r--r-- | tests/test_download.c | 3 | ||||
| -rw-r--r-- | tests/test_environment.c | 4 | ||||
| -rw-r--r-- | tests/test_ini.c | 18 | ||||
| -rw-r--r-- | tests/test_junitxml.c | 4 | ||||
| -rw-r--r-- | tests/test_multiprocessing.c | 48 | ||||
| -rw-r--r-- | tests/test_recipe.c | 2 | ||||
| -rw-r--r-- | tests/test_relocation.c | 13 | ||||
| -rw-r--r-- | tests/test_str.c | 22 | ||||
| -rw-r--r-- | tests/test_strlist.c | 20 | ||||
| -rw-r--r-- | tests/test_system.c | 4 | ||||
| -rw-r--r-- | tests/test_template.c | 51 | ||||
| -rw-r--r-- | tests/test_tests.c | 52 | ||||
| -rw-r--r-- | tests/test_utils.c | 44 | ||||
| -rw-r--r-- | tests/test_version_compare.c | 172 | ||||
| -rw-r--r-- | tests/test_wheel.c | 276 | ||||
| -rw-r--r-- | tests/test_wheelinfo.c | 91 |
22 files changed, 757 insertions, 178 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2b09e9e..26c4250 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -17,7 +17,10 @@ if (BASH_PROGRAM AND TESTS_RT) file(REAL_PATH ${rt_file} rt_name) string(REGEX REPLACE ${ext_pattern} "" rt_name ${rt_file}) add_test (${rt_name} ${BASH_PROGRAM} ${rt_file}) - endforeach() + set_property(TEST ${rt_name} + PROPERTY ENVIRONMENT "GIT_CEILING_DIRECTORIES=${CMAKE_BINARY_DIR}" + ) +endforeach() endif() foreach(source_file ${source_files}) @@ -30,6 +33,9 @@ foreach(source_file ${source_files}) elseif (CMAKE_C_COMPILER_ID STREQUAL "MSVC") target_compile_options(${test_executable} PRIVATE ${win_cflags} ${win_msvc_cflags}) endif() + if (TESTS_VERBOSE) + target_compile_definitions(${test_executable} PRIVATE STASIS_TEST_VERBOSE=1) + endif () target_include_directories(${test_executable} PRIVATE ${core_INCLUDE} ${delivery_INCLUDE} @@ -41,10 +47,12 @@ foreach(source_file ${source_files}) add_test(${test_executable} ${test_executable}) set_tests_properties(${test_executable} PROPERTIES - TIMEOUT 240) + TIMEOUT 600) set_tests_properties(${test_executable} PROPERTIES SKIP_RETURN_CODE 127) set_property(TEST ${test_executable} - PROPERTY ENVIRONMENT "STASIS_SYSCONFDIR=${CMAKE_SOURCE_DIR}") + PROPERTY ENVIRONMENT "STASIS_SYSCONFDIR=${CMAKE_SOURCE_DIR}" + PROPERTY ENVIRONMENT "GIT_CEILING_DIRECTORIES=${CMAKE_BINARY_DIR}" + ) endforeach() diff --git a/tests/include/testing.h b/tests/include/testing.h index ab24115..d11398c 100644 --- a/tests/include/testing.h +++ b/tests/include/testing.h @@ -9,6 +9,15 @@ #define __FILE_NAME__ __FILE__ #endif +#ifdef STASIS_TEST_VERBOSE +#define STASIS_TEST_MSG(MSG, ...) do { \ +fprintf(stderr, "%s:%d:%s(): ", path_basename(__FILE__), __LINE__, __FUNCTION__); \ +fprintf(stderr, MSG LINE_SEP, __VA_ARGS__); \ +} while (0) +#else +#define STASIS_TEST_MSG(MSG, ...) do {} while (0) +#endif + typedef void(STASIS_TEST_FUNC)(); struct stasis_test_result_t { const char *filename; @@ -48,32 +57,39 @@ inline void stasis_testing_record_result_summary() { size_t failed = 0; size_t skipped = 0; size_t passed = 0; - int do_message; + int do_message = 0; + int do_reason = 0; static char status_msg[255] = {0}; for (size_t i = 0; i < stasis_test_results_i; i++) { if (stasis_test_results[i].status && stasis_test_results[i].skip) { strcpy(status_msg, "SKIP"); do_message = 1; + do_reason = 1; skipped++; } else if (!stasis_test_results[i].status) { strcpy(status_msg, "FAIL"); do_message = 1; + do_reason = 1; failed++; } else { +#ifdef STASIS_TEST_VERBOSE + do_message = 1; +#endif strcpy(status_msg, "PASS"); - do_message = 0; passed++; } - fprintf(stdout, "[%s] %s:%d :: %s() => %s", - status_msg, - stasis_test_results[i].filename, - stasis_test_results[i].lineno, - stasis_test_results[i].funcname, - stasis_test_results[i].msg_assertion); if (do_message) { - fprintf(stdout, "\n \\_ %s", stasis_test_results[i].msg_reason); + fprintf(stdout, "[%s] %s:%d :: %s() => %s", + status_msg, + stasis_test_results[i].filename, + stasis_test_results[i].lineno, + stasis_test_results[i].funcname, + stasis_test_results[i].msg_assertion); + if (do_reason) { + fprintf(stdout, "\n \\_ %s", stasis_test_results[i].msg_reason); + } + fprintf(stdout, "\n"); } - fprintf(stdout, "\n"); } fprintf(stdout, "\n[UNIT] %zu tests passed, %zu tests failed, %zu tests skipped out of %zu\n", passed, failed, skipped, stasis_test_results_i); } @@ -106,8 +122,7 @@ inline char *stasis_testing_read_ascii(const char *filename) { } inline int stasis_testing_write_ascii(const char *filename, const char *data) { - FILE *fp; - fp = fopen(filename, "w+"); + FILE *fp = fopen(filename, "w+"); if (!fp) { perror(filename); return -1; @@ -199,6 +214,7 @@ inline void stasis_testing_teardown_workspace() { SYSERROR("%s", "Unable to determine current working directory"); \ exit(1); \ } \ + LOG_LEVEL = LOG_LEVEL_DEBUG; \ atexit(stasis_testing_record_result_summary); \ atexit(stasis_testing_teardown_workspace); \ stasis_testing_setup_workspace(); \ @@ -208,7 +224,7 @@ inline void stasis_testing_teardown_workspace() { #define STASIS_ASSERT(COND, REASON) do { \ stasis_testing_record_result((struct stasis_test_result_t) { \ .filename = __FILE_NAME__, \ - .funcname = __FUNCTION__, \ + .funcname = __func__, \ .lineno = __LINE__, \ .status = (COND), \ .msg_assertion = "ASSERT(" #COND ")", \ @@ -218,7 +234,7 @@ inline void stasis_testing_teardown_workspace() { #define STASIS_ASSERT_FATAL(COND, REASON) do { \ stasis_testing_record_result((struct stasis_test_result_t) { \ .filename = __FILE_NAME__, \ - .funcname = __FUNCTION__, \ + .funcname = __func__, \ .lineno = __LINE__, \ .status = (COND), \ .msg_assertion = "ASSERT FATAL (" #COND ")", \ @@ -232,7 +248,7 @@ inline void stasis_testing_teardown_workspace() { #define STASIS_SKIP_IF(COND, REASON) do { \ stasis_testing_record_result((struct stasis_test_result_t) { \ .filename = __FILE_NAME__, \ - .funcname = __FUNCTION__, \ + .funcname = __func__, \ .lineno = __LINE__, \ .status = true, \ .skip = (COND), \ diff --git a/tests/setup.sh b/tests/setup.sh index 7e38cf9..bce2fbd 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -78,7 +78,7 @@ teardown_workspace() { install_stasis() { pushd "$BUILD_DIR" - if ! cmake -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" -DCMAKE_BUILD_TYPE=Debug "${TOPDIR}"/../..; then + if ! cmake -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" -DCMAKE_BUILD_TYPE=Debug -DDEBUG_MESSAGES=ON "${TOPDIR}"/../..; then echo "cmake failed" >&2 return 1 fi @@ -109,7 +109,7 @@ STASIS_TEST_RESULT_SKIP=0 run_command() { local logfile="$(mktemp).log" local cmd="${@}" - local lines_on_error=100 + local lines_on_error=1000 /bin/echo "Testing: $cmd " $cmd &>"$logfile" diff --git a/tests/test_artifactory.c b/tests/test_artifactory.c index 4af7eec..7090fa6 100644 --- a/tests/test_artifactory.c +++ b/tests/test_artifactory.c @@ -15,14 +15,14 @@ const char *gbuild_num = "1"; static int jfrog_cli_rt_build_delete(struct JFRT_Auth *auth, char *build_name, char *build_num) { char cmd[STASIS_BUFSIZ]; memset(cmd, 0, sizeof(cmd)); - snprintf(cmd, sizeof(cmd) - 1, "--build \"%s/%s\"", build_name, build_num); + snprintf(cmd, sizeof(cmd), "--build \"%s/%s\"", build_name, build_num); return jfrog_cli(auth, "rt", "delete", cmd); } static int jfrog_cli_rt_delete(struct JFRT_Auth *auth, char *pattern) { char cmd[STASIS_BUFSIZ]; memset(cmd, 0, sizeof(cmd)); - snprintf(cmd, sizeof(cmd) - 1, "\"%s\"", pattern); + snprintf(cmd, sizeof(cmd), "\"%s\"", pattern); return jfrog_cli(auth, "rt", "delete", cmd); } @@ -60,7 +60,7 @@ void test_jfrog_cli_rt_download() { char *filename = "empty_file_upload.txt"; char path[PATH_MAX] = {0}; - sprintf(path, "%s/%s", getenv("STASIS_JF_REPO"), filename); + snprintf(path, sizeof(path), "%s/%s", getenv("STASIS_JF_REPO"), filename); STASIS_ASSERT(jfrog_cli_rt_download(&gauth, &dl, filename, ".") == 0, "jf download failed"); STASIS_ASSERT(jfrog_cli_rt_delete(&gauth, path) == 0, "jf delete test artifact failed"); } @@ -93,15 +93,15 @@ int main(int argc, char *argv[]) { } char path[PATH_MAX] = {0}; - sprintf(path, "%s/bin:%s", ctx.storage.tools_dir, getenv("PATH")); + snprintf(path, sizeof(path), "%s/bin:%s", ctx.storage.tools_dir, getenv("PATH")); setenv("PATH", path, 1); // The default config contains the URL information to download jfrog-cli char cfg_path[PATH_MAX] = {0}; if (strstr(sysconfdir, "..")) { - sprintf(cfg_path, "%s/%s/stasis.ini", basedir, sysconfdir); + snprintf(cfg_path, sizeof(cfg_path), "%s/%s/stasis.ini", basedir, sysconfdir); } else { - sprintf(cfg_path, "%s/stasis.ini", sysconfdir); + snprintf(cfg_path, sizeof(cfg_path), "%s/stasis.ini", sysconfdir); } ctx._stasis_ini_fp.cfg = ini_open(cfg_path); if (!ctx._stasis_ini_fp.cfg) { @@ -115,7 +115,8 @@ int main(int argc, char *argv[]) { // Skip this suite if we're not configured to use it if (jfrt_auth_init(&gauth)) { - SYSERROR("%s", "Not configured to test Artifactory. Skipping."); + SYSERROR("Not configured to test Artifactory. Skipping."); + guard_free(basedir); return STASIS_TEST_SUITE_SKIP; } guard_free(basedir); diff --git a/tests/test_conda.c b/tests/test_conda.c index 4d437e4..bbbef3c 100644 --- a/tests/test_conda.c +++ b/tests/test_conda.c @@ -18,10 +18,10 @@ void test_micromamba() { int result; }; struct testcase tc[] = { - {.mminfo = {.micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "info", .result = 0}, - {.mminfo = {.micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "env list", .result = 0}, - {.mminfo = {.micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "run python -V", .result = 0}, - {.mminfo = {.micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "no_such_option", .result = 109}, + {.mminfo = {.download_dir = cwd_workspace, .micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "info", .result = 0}, + {.mminfo = {.download_dir = cwd_workspace, .micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "env list", .result = 0}, + {.mminfo = {.download_dir = cwd_workspace, .micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "run python3 -V", .result = 0}, + {.mminfo = {.download_dir = cwd_workspace, .micromamba_prefix = mm_prefix, .conda_prefix = c_prefix}, .cmd = "no_such_option", .result = 109}, }; for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { @@ -31,7 +31,7 @@ void test_micromamba() { result = result >> 8; } STASIS_ASSERT(result == item->result, "unexpected exit value"); - SYSERROR("micromamba command: '%s' (returned: %d)", item->cmd, result); + SYSDEBUG("micromamba command: '%s' (returned: %d)", item->cmd, result); } } @@ -40,7 +40,7 @@ struct Delivery ctx; void test_conda_installation() { char *install_url = calloc(255, sizeof(install_url)); - delivery_get_conda_installer_url(&ctx, install_url); + delivery_get_conda_installer_url(&ctx, install_url, PATH_MAX); delivery_get_conda_installer(&ctx, install_url); delivery_install_conda(ctx.conda.installer_path, ctx.storage.conda_install_prefix); @@ -92,7 +92,7 @@ void test_conda_exec() { void test_python_exec() { const char *python_system_path = find_program("python3"); char python_path[PATH_MAX]; - sprintf(python_path, "%s/bin/python3", ctx.storage.conda_install_prefix); + snprintf(python_path, sizeof(python_path), "%s/bin/python3", ctx.storage.conda_install_prefix); STASIS_ASSERT(strcmp(python_path, python_system_path ? python_system_path : "/not/found") == 0, "conda is not configured correctly."); STASIS_ASSERT(python_exec("-V") == 0, "python is broken"); @@ -110,13 +110,13 @@ void test_conda_setup_headless() { void test_conda_env_create_from_uri() { const char *url = "https://ssb.stsci.edu/jhunk/stasis_test/test_conda_env_create_from_uri.yml"; - char *name = strdup(__FUNCTION__); + char *name = strdup(__func__); STASIS_ASSERT(conda_env_create_from_uri(name, (char *) url, "3.11") == 0, "creating an environment from a remote source failed"); free(name); } void test_conda_env_create_export_remove() { - char *name = strdup(__FUNCTION__); + char *name = strdup(__func__); STASIS_ASSERT(conda_env_create(name, "3", "fitsverify") == 0, "unable to create a simple environment"); STASIS_ASSERT(conda_env_export(name, ".", name) == 0, "unable to export an environment"); STASIS_ASSERT(conda_env_remove(name) == 0, "unable to remove an environment"); @@ -143,14 +143,14 @@ void test_pip_index_provides() { }; for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { struct testcase *test = &tc[i]; - int result = pkg_index_provides(PKG_USE_PIP, test->pindex, test->name); + int result = pkg_index_provides(PKG_USE_PIP, test->pindex, test->name, "."); STASIS_ASSERT(result == test->expected, "Unexpected result"); if (PKG_INDEX_PROVIDES_FAILED(result)) { - fprintf(stderr, "error: %s\n", pkg_index_provides_strerror(result)); + SYSERROR("%s", pkg_index_provides_strerror(result)); } else if (result == PKG_NOT_FOUND) { - fprintf(stderr, "package not found: '%s'\n", test->name); + SYSERROR("package not found: '%s'", test->name); } else { - printf("package found: '%s'\n", test->name); + SYSDEBUG("package found: '%s'", test->name); } } } @@ -175,7 +175,7 @@ void test_conda_provides() { for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { struct testcase *test = &tc[i]; - int result = pkg_index_provides(PKG_USE_CONDA, NULL, test->name); + int result = pkg_index_provides(PKG_USE_CONDA, NULL, test->name, "."); printf("%s returned %d, expecting %d\n", test->name, result, test->expected); STASIS_ASSERT(result == test->expected, "Unexpected result"); } @@ -208,7 +208,7 @@ int main(int argc, char *argv[]) { char ws[] = "workspace_XXXXXX"; if (!mkdtemp(ws)) { - perror("mkdtemp"); + SYSERROR("unable to mkdtemp: %s", strerror(errno)); exit(1); } getcwd(cwd_start, sizeof(cwd_start) - 1); diff --git a/tests/test_docker.c b/tests/test_docker.c index d60522f..b0cf381 100644 --- a/tests/test_docker.c +++ b/tests/test_docker.c @@ -41,7 +41,7 @@ void test_docker_build_and_script_and_save() { if (!pushd("test_docker_build")) { stasis_testing_write_ascii("Dockerfile", dockerfile_contents); STASIS_ASSERT(docker_build(".", "-t test_docker_build", cap_suite.build) == 0, "docker build test failed"); - STASIS_ASSERT(docker_script("test_docker_build", "uname -a", 0) == 0, "simple docker container script execution failed"); + STASIS_ASSERT(docker_script("test_docker_build", "--rm", "uname -a", 0) == 0, "simple docker container script execution failed"); STASIS_ASSERT(docker_save("test_docker_build", ".", STASIS_DOCKER_IMAGE_COMPRESSION) == 0, "saving a simple image failed"); STASIS_ASSERT(docker_exec("load < test_docker_build.tar.*", 0) == 0, "loading a simple image failed"); docker_exec("image rm -f test_docker_build", 0); diff --git a/tests/test_download.c b/tests/test_download.c index 714e614..6ace119 100644 --- a/tests/test_download.c +++ b/tests/test_download.c @@ -21,7 +21,7 @@ void test_download() { for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { const char *filename = "output.txt"; - char errmsg[BUFSIZ] = {0}; + char errmsg[STASIS_BUFSIZ] = {0}; char *errmsg_p = errmsg; long http_code = download((char *) tc[i].url, filename, &errmsg_p); if (tc[i].errmsg) { @@ -33,7 +33,6 @@ void test_download() { } STASIS_ASSERT(http_code == tc[i].http_code, "expecting non-error HTTP code"); - //char **data = file_readlines(filename, 0, 100, NULL); char *data = stasis_testing_read_ascii(filename); if (http_code >= 0) { STASIS_ASSERT(data != NULL, "data should not be null"); diff --git a/tests/test_environment.c b/tests/test_environment.c index 4f36883..72a938d 100644 --- a/tests/test_environment.c +++ b/tests/test_environment.c @@ -56,9 +56,9 @@ void test_runtime() { STASIS_ASSERT(strcmp(global_custom_value, custom_value) == 0, "local and global CUSTOM_KEY variable are supposed to be identical"); guard_free(custom_value); - char output_truth[BUFSIZ] = {0}; + char output_truth[STASIS_BUFSIZ] = {0}; char *your_path = runtime_get(env, "PATH"); - sprintf(output_truth, "Your PATH is '%s'.", your_path); + snprintf(output_truth, sizeof(output_truth), "Your PATH is '%s'.", your_path); guard_free(your_path); char *output_expanded = runtime_expand_var(env, "Your PATH is '${PATH}'."); diff --git a/tests/test_ini.c b/tests/test_ini.c index e4a7808..3070806 100644 --- a/tests/test_ini.c +++ b/tests/test_ini.c @@ -195,6 +195,23 @@ void test_ini_getval_wrappers() { ini_free(&ini); } +void test_ini_getall() { + const char *filename = "ini_open.ini"; + struct INIFILE *ini = NULL; + const char *data = "[default]\nhello=world!\nthis=is a test\nx=1\ny=0\n"; + + stasis_testing_write_ascii(filename, data); + ini = ini_open(filename); + STASIS_ASSERT_FATAL(ini != NULL, "failed to open ini file"); + + const struct INIData *d = NULL; + while ((d = ini_getall(ini, "default")) != NULL) { + STASIS_ASSERT(d->key != NULL, "INIData key should not be NULL"); + STASIS_ASSERT(d->value != NULL, "INIData key should not be NULL"); + } + ini_free(&ini); +} + int main(int argc, char *argv[]) { STASIS_TEST_BEGIN_MAIN(); STASIS_TEST_FUNC *tests[] = { @@ -204,6 +221,7 @@ int main(int argc, char *argv[]) { test_ini_has_key, test_ini_setval_getval, test_ini_getval_wrappers, + test_ini_getall, }; STASIS_TEST_RUN(tests); STASIS_TEST_END_MAIN(); diff --git a/tests/test_junitxml.c b/tests/test_junitxml.c index 362cb32..0bbbefb 100644 --- a/tests/test_junitxml.c +++ b/tests/test_junitxml.c @@ -4,7 +4,7 @@ void test_junitxml_testsuite_read() { struct JUNIT_Testsuite *testsuite; char datafile[PATH_MAX] = {0}; - snprintf(datafile, sizeof(datafile) - 1, "%s/result.xml", TEST_DATA_DIR); + snprintf(datafile, sizeof(datafile), "%s/result.xml", TEST_DATA_DIR); STASIS_ASSERT_FATAL((testsuite = junitxml_testsuite_read(datafile)) != NULL, "failed to load testsuite data"); STASIS_ASSERT(testsuite->name != NULL, "Test suite must be named"); @@ -48,7 +48,7 @@ void test_junitxml_testsuite_read() { void test_junitxml_testsuite_read_error() { struct JUNIT_Testsuite *testsuite; char datafile[PATH_MAX] = {0}; - snprintf(datafile, sizeof(datafile) - 1, "%s/result_error.xml", TEST_DATA_DIR); + snprintf(datafile, sizeof(datafile), "%s/result_error.xml", TEST_DATA_DIR); STASIS_ASSERT_FATAL((testsuite = junitxml_testsuite_read(datafile)) != NULL, "failed to load testsuite data"); STASIS_ASSERT(testsuite->name != NULL, "test suite must be named"); diff --git a/tests/test_multiprocessing.c b/tests/test_multiprocessing.c index 7c9d695..767a9e0 100644 --- a/tests/test_multiprocessing.c +++ b/tests/test_multiprocessing.c @@ -65,7 +65,7 @@ void test_mp_task() { for (size_t i = 0; i < sizeof(commands) / sizeof(*commands); i++) { struct MultiProcessingTask *task; char task_name[100] = {0}; - sprintf(task_name, "mytask%zu", i); + snprintf(task_name, sizeof(task_name), "mytask%zu", i); STASIS_ASSERT_FATAL((task = mp_pool_task(pool, task_name, NULL, commands[i])) != NULL, "Task should not be NULL"); STASIS_ASSERT(task->pid == MP_POOL_PID_UNUSED, "PID should be non-zero at this point"); STASIS_ASSERT(task->parent_pid == MP_POOL_PID_UNUSED, "Parent PID should be non-zero"); @@ -137,7 +137,7 @@ void test_mp_fail_fast() { for (size_t i = 0; i < sizeof(commands_ff) / sizeof(*commands_ff); i++) { char *command = commands_ff[i]; char taskname[100] = {0}; - snprintf(taskname, sizeof(taskname) - 1, "task_%03zu", i); + snprintf(taskname, sizeof(taskname), "task_%03zu", i); STASIS_ASSERT(mp_pool_task(p, taskname, NULL, (char *) command) != NULL, "Failed to queue task"); } @@ -161,7 +161,7 @@ void test_mp_fail_fast() { if (task->status == 0) result.total_status_success++; if (task->pid == MP_POOL_PID_UNUSED && task->status == MP_POOL_TASK_STATUS_INITIAL) result.total_unused++; } - fprintf(stderr, "total_status_fail = %d\ntotal_status_success = %d\ntotal_signaled = %d\ntotal_unused = %d\n", + STASIS_TEST_MSG("\ntotal_status_fail = %d\ntotal_status_success = %d\ntotal_signaled = %d\ntotal_unused = %d", result.total_status_fail, result.total_status_success, result.total_signaled, result.total_unused); STASIS_ASSERT(result.total_status_fail, "Should have failures"); STASIS_ASSERT(result.total_status_success, "Should have successes"); @@ -171,6 +171,43 @@ void test_mp_fail_fast() { mp_pool_free(&p); } +static void test_mp_timeout() { + struct MultiProcessingPool *p = NULL; + p = mp_pool_init("timeout", "timeoutlogs"); + p->status_interval = 1; + struct MultiProcessingTask *task = mp_pool_task(p, "timeout", NULL, "sleep 5"); + int timeout = 3; + task->timeout = timeout; + mp_pool_join(p, 1, 0); + STASIS_ASSERT((task->time_data.duration >= (double) timeout && task->time_data.duration < (double) timeout + 1), "Timeout occurred out of desired range"); + mp_pool_show_summary(p); + mp_pool_free(&p); +} + +static void test_mp_seconds_to_human_readable() { + const struct testcase { + int seconds; + const char *expected; + } tc[] = { + {.seconds = -1, "-1s"}, + {.seconds = 0, "0s"}, + {.seconds = 10, "10s"}, + {.seconds = 20, "20s"}, + {.seconds = 30, "30s"}, + {.seconds = 60, "1m 0s"}, + {.seconds = 125, "2m 5s"}, + {.seconds = 3600, "1h 0m 0s"}, + {.seconds = 86399, "23h 59m 59s"}, + {.seconds = 86400, "24h 0m 0s"}, + }; + for (size_t i = 0; i < sizeof(tc) / sizeof(tc[0]); i++) { + char result[255] = {0}; + seconds_to_human_readable(tc[i].seconds, result, sizeof(result)); + STASIS_TEST_MSG("seconds=%d, expected: %s, got: %s", tc[i].seconds, tc[i].expected, result); + STASIS_ASSERT(strcmp(result, tc[i].expected) == 0, "bad output"); + } +} + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static void *pool_container(void *data) { char *commands_sc[] = { @@ -212,8 +249,13 @@ int main(int argc, char *argv[]) { test_mp_pool_free, test_mp_pool_workflow, test_mp_fail_fast, + test_mp_timeout, + test_mp_seconds_to_human_readable, test_mp_stop_continue }; + + globals.task_timeout = 60; + STASIS_TEST_RUN(tests); STASIS_TEST_END_MAIN(); } diff --git a/tests/test_recipe.c b/tests/test_recipe.c index fc7cc78..3ea21ce 100644 --- a/tests/test_recipe.c +++ b/tests/test_recipe.c @@ -4,7 +4,7 @@ static void make_local_recipe(const char *localdir) { char path[PATH_MAX] = {0}; - sprintf(path, "./%s", localdir); + snprintf(path, sizeof(path), "./%s", localdir); mkdir(path, 0755); if (!pushd(path)) { touch("meta.yaml"); diff --git a/tests/test_relocation.c b/tests/test_relocation.c index a6c33f2..891e346 100644 --- a/tests/test_relocation.c +++ b/tests/test_relocation.c @@ -13,10 +13,14 @@ void test_replace_text() { for (size_t i = 0; i < sizeof(targets) / sizeof(*targets); i += 2) { const char *target = targets[i]; const char *expected = targets[i + 1]; - char input[BUFSIZ] = {0}; - strcpy(input, test_string); + char input[STASIS_BUFSIZ] = {0}; + strncpy(input, test_string, sizeof(input) - 1); + input[sizeof(input) - 1] = '\0'; + printf("input: %s\n", input); + printf("target: %s\n", target); STASIS_ASSERT(replace_text(input, target, "^^^", 0) == 0, "string replacement failed"); + printf("result: %s\n\n", input); STASIS_ASSERT(strcmp(input, expected) == 0, "unexpected replacement"); } @@ -36,16 +40,19 @@ void test_file_replace_text() { STASIS_ASSERT(file_replace_text(filename, target, "^^^", 0) == 0, "string replacement failed"); } else { STASIS_ASSERT(false, "failed to open file for writing"); + fclose(fp); return; } - char input[BUFSIZ] = {0}; + char input[STASIS_BUFSIZ] = {0}; fp = fopen(filename, "r"); if (fp) { fread(input, sizeof(*input), sizeof(input), fp); STASIS_ASSERT(strcmp(input, expected) == 0, "unexpected replacement"); + fclose(fp); } else { STASIS_ASSERT(false, "failed to open file for reading"); + fclose(fp); return; } } diff --git a/tests/test_str.c b/tests/test_str.c index ad0c07a..09d8809 100644 --- a/tests/test_str.c +++ b/tests/test_str.c @@ -6,16 +6,17 @@ void test_to_short_version() { const char *expected; }; - struct testcase tc[] = { - {.data = "1.2.3", .expected = "123"}, + const struct testcase tc[] = { + {.data = "1.2.3", .expected = "12"}, {.data = "py3.12", .expected = "py312"}, - {.data = "generic-1.2.3", .expected = "generic-123"}, + {.data = "generic-1.2.3", .expected = "generic-12"}, {.data = "nothing to do", .expected = "nothing to do"}, }; for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { char *result = to_short_version(tc[i].data); STASIS_ASSERT_FATAL(result != NULL, "should not be NULL"); + //printf("%s[%zu], result: %s, expected: %s\n", __FUNCTION__, i, result, tc[i].expected); STASIS_ASSERT(strcmp(result, tc[i].expected) == 0, "unexpected result"); guard_free(result); } @@ -36,7 +37,8 @@ void test_tolower_s() { for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { char input[100] = {0}; - strcpy(input, tc[i].data); + strncpy(input, tc[i].data, sizeof(input) - 1); + input[sizeof(input) - 1] = '\0'; tolower_s(input); STASIS_ASSERT(strcmp(input, tc[i].expected) == 0, "unexpected result"); } @@ -316,9 +318,9 @@ void test_lstrip() { STASIS_ASSERT(lstrip(NULL) == NULL, "incorrect return type"); for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { char *buf = calloc(255, sizeof(*buf)); - char *result; - strcpy(buf, tc[i].data); - result = lstrip(buf); + strncpy(buf, tc[i].data, 254); + buf[254] = '\0'; + char *result = lstrip(buf); STASIS_ASSERT(strcmp(result ? result : "", tc[i].expected) == 0, "incorrect strip-from-left"); guard_free(buf); } @@ -341,9 +343,9 @@ void test_strip() { STASIS_ASSERT(strip(NULL) == NULL, "incorrect return type"); for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { char *buf = calloc(255, sizeof(*buf)); - char *result; - strcpy(buf, tc[i].data); - result = strip(buf); + strncpy(buf, tc[i].data, 254); + buf[254] = '\0'; + char *result = strip(buf); STASIS_ASSERT(strcmp(result ? result : "", tc[i].expected) == 0, "incorrect strip-from-right"); guard_free(buf); } diff --git a/tests/test_strlist.c b/tests/test_strlist.c index ce38ff6..38343f4 100644 --- a/tests/test_strlist.c +++ b/tests/test_strlist.c @@ -115,6 +115,7 @@ void test_strlist_append_file() { const char *local_filename = "test_strlist_append_file.txt"; struct testcase tc[] = { + {.origin = "https://this-will-never-work.tld/remote.txt", .expected = (const char *[]){NULL}}, {.origin = "https://ssb.stsci.edu/jhunk/stasis_test/test_strlist_append_file_from_remote.txt", .expected = expected}, {.origin = local_filename, .expected = expected}, }; @@ -141,10 +142,10 @@ void test_strlist_append_file() { const char *left; const char *right; left = strlist_item(list, z); - right = expected[z]; + right = tc[i].expected[z]; STASIS_ASSERT(strcmp(left, right) == 0, "file content is different than expected"); } - STASIS_ASSERT(strcmp_array((const char **) list->data, expected) == 0, "file contents does not match expected values"); + STASIS_ASSERT(strcmp_array((const char **) list->data, tc[i].expected) == 0, "file contents does not match expected values"); guard_strlist_free(&list); } } @@ -199,6 +200,20 @@ void test_strlist_append_tokenize() { guard_strlist_free(&list); } +void test_strlist_appendf() { + const char *fmt = "%c %s %d"; + struct StrList *list; + list = strlist_init(); + const int len = strlist_appendf(NULL, fmt, 'a', "abc", strlen(fmt)); + STASIS_ASSERT(strlist_appendf(&list, fmt, 'a', "abc", strlen(fmt)) == len, "length of formatted string should be 7"); + const char *item = strlist_item(list, 0); + STASIS_ASSERT(item != NULL, "valid pointer expected, item should not be NULL"); + STASIS_ASSERT(strncmp(item, "a", 1) == 0, "first character should be 'a'"); + STASIS_ASSERT(strncmp(item + 2, "abc", 3) == 0, "string should be 'abc'"); + STASIS_ASSERT(strncmp(item + 6, "8", 1) == 0, "length of the raw format should be 8"); + guard_strlist_free(&list); +} + void test_strlist_copy() { struct StrList *list = strlist_init(); struct StrList *list_copy; @@ -627,6 +642,7 @@ void test_strlist_item_as_long_double() { int main(int argc, char *argv[]) { STASIS_TEST_BEGIN_MAIN(); STASIS_TEST_FUNC *tests[] = { + test_strlist_appendf, test_strlist_init, test_strlist_free, test_strlist_append, diff --git a/tests/test_system.c b/tests/test_system.c index 2271e13..cdef618 100644 --- a/tests/test_system.c +++ b/tests/test_system.c @@ -4,7 +4,7 @@ static int ascii_file_contains(const char *filename, const char *value) { int result = -1; char *contents = stasis_testing_read_ascii(filename); if (!contents) { - perror(filename); + SYSERROR("unable to read %s: %s", filename, strerror(errno)); return result; } result = strcmp(contents, value) == 0; @@ -54,7 +54,7 @@ void test_shell_safe_verify_restrictions() { char cmd[PATH_MAX] = {0}; memset(&proc, 0, sizeof(proc)); - sprintf(cmd, "true%c false", invalid_chars[i]); + snprintf(cmd, sizeof(cmd), "true%c false", invalid_chars[i]); shell_safe(&proc, cmd); STASIS_ASSERT(proc.returncode == -1, "expected a negative result due to intentional error"); } diff --git a/tests/test_template.c b/tests/test_template.c index 596c2b7..3efb142 100644 --- a/tests/test_template.c +++ b/tests/test_template.c @@ -10,8 +10,9 @@ static int adder(struct tplfunc_frame *frame, void *result) { int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10); int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10); char **ptr = (char **) result; - *ptr = calloc(100, sizeof(*ptr)); - sprintf(*ptr, "%d", a + b); + const size_t sz = 100; + *ptr = calloc(sz, sizeof(*ptr)); + snprintf(*ptr, sz, "%d", a + b); return 0; } @@ -19,8 +20,9 @@ static int subtractor(struct tplfunc_frame *frame, void *result) { int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10); int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10); char **ptr = (char **) result; - *ptr = calloc(100, sizeof(*ptr)); - sprintf(*ptr, "%d", a - b); + const size_t sz = 100; + *ptr = calloc(sz, sizeof(*ptr)); + snprintf(*ptr, sz, "%d", a - b); return 0; } @@ -28,8 +30,9 @@ static int multiplier(struct tplfunc_frame *frame, void *result) { int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10); int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10); char **ptr = (char **) result; - *ptr = calloc(100, sizeof(*ptr)); - sprintf(*ptr, "%d", a * b); + const size_t sz = 100; + *ptr = calloc(sz, sizeof(*ptr)); + snprintf(*ptr, sz, "%d", a * b); return 0; } @@ -37,8 +40,9 @@ static int divider(struct tplfunc_frame *frame, void *result) { int a = (int) strtol(frame->argv[0].t_char_ptr, NULL, 10); int b = (int) strtol(frame->argv[1].t_char_ptr, NULL, 10); char **ptr = (char **) result; - *ptr = calloc(100, sizeof(*ptr)); - sprintf(*ptr, "%d", a / b); + size_t sz = 100; + *ptr = calloc(sz, sizeof(*ptr)); + snprintf(*ptr, sz, "%d", a / b); return 0; } @@ -57,6 +61,19 @@ void test_tpl_workflow() { STASIS_ASSERT(strcmp(result, "Hello environment!") == 0, "environment variable content mismatch"); guard_free(result); unsetenv("HELLO"); + + const char *message_file = "message.txt"; + char message_fmt[] = "They wanted a {{ hello_message }} " + "So we gave them a {{ hello_message }}"; + const char *message_expected = "They wanted a Hello world! " + "So we gave them a Hello world!"; + const int state = tpl_render_to_file(message_fmt, message_file); + STASIS_ASSERT_FATAL(state == 0, "failed to write rendered string to file"); + char *message_contents = stasis_testing_read_ascii(message_file); + STASIS_ASSERT(strcmp(message_contents, message_expected) == 0, "message in file does not match original message"); + guard_free(message_contents); + remove(message_file); + guard_free(data); } @@ -68,6 +85,8 @@ void test_tpl_register() { STASIS_ASSERT(tpl_pool_used == (used_before_register + 1), "tpl_register did not increment allocation counter"); STASIS_ASSERT(tpl_pool[used_before_register] != NULL, "register did not allocate a tpl_item record in the pool"); + const char *message = tpl_getval("hello_message"); + STASIS_ASSERT(strcmp(message, "Hello world!") == 0, "stored message corrupt"); free(data); } @@ -76,7 +95,7 @@ void test_tpl_register_func() { struct testcase { const char *key; int argc; - void *func; + tplfunc *func; }; struct testcase tc[] = { {.key = "add", .argc = 2, .func = &adder}, @@ -92,25 +111,25 @@ void test_tpl_register_func() { char *result = NULL; result = tpl_render("{{ func:add(0,3) }}"); - STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3"); + STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "add: Answer was not 3"); guard_free(result); result = tpl_render("{{ func:add(1,2) }}"); - STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3"); + STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "add: Answer was not 3"); guard_free(result); result = tpl_render("{{ func:sub(6,3) }}"); - STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3"); + STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "sub: was not 3"); guard_free(result); result = tpl_render("{{ func:sub(4,1) }}"); - STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3"); + STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "sub: Answer was not 3"); guard_free(result); result = tpl_render("{{ func:mul(1, 3) }}"); - STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3"); + STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "mul: Answer was not 3"); guard_free(result); result = tpl_render("{{ func:div(6,2) }}"); - STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3"); + STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "div: Answer was not 3"); guard_free(result); result = tpl_render("{{ func:div(3,1) }}"); - STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "Answer was not 3"); + STASIS_ASSERT(result != NULL && strcmp(result, "3") == 0, "div: Answer was not 3"); guard_free(result); } diff --git a/tests/test_tests.c b/tests/test_tests.c new file mode 100644 index 0000000..0f6d7ca --- /dev/null +++ b/tests/test_tests.c @@ -0,0 +1,52 @@ +#include "delivery.h" +#include "testing.h" + +static struct Test *mock_test(const int ident) { + struct Test *test = test_init(); + if (asprintf(&test->name, "test_%d", ident) < 0) { + return NULL; + } + return test; +} + +void test_tests() { + const int initial = TEST_NUM_ALLOC_INITIAL; + const int balloon = initial * 10; + struct Tests *tests = tests_init(initial); + STASIS_ASSERT_FATAL(tests != NULL, "tests structure allocation failed"); + STASIS_ASSERT(tests->num_alloc == (size_t) initial, "incorrect number of records initialized"); + STASIS_ASSERT(tests->num_used == 0, "incorrect number of records used"); + + for (int i = 0; i < balloon; i++) { + struct Test *test = mock_test(i); + if (!test) { + SYSERROR("unable to allocate memory for test %d", i); + return; + } + tests_add(tests, test); + } + + size_t errors = 0; + for (int i = 0; i < initial * 10; i++) { + struct Test *test = tests->test[i]; + if (!test) { + errors++; + continue; + } + if (!test->name) { + errors++; + } + } + STASIS_ASSERT(errors == 0, "no errors should be detected in test->name member"); + + tests_free(&tests); +} + +int main(int argc, char *argv[]) { + STASIS_TEST_BEGIN_MAIN(); + STASIS_TEST_FUNC *tests[] = { + test_tests, + }; + STASIS_TEST_RUN(tests); + STASIS_TEST_END_MAIN(); +}
\ No newline at end of file diff --git a/tests/test_utils.c b/tests/test_utils.c index 0e2eb7b..696e7ff 100644 --- a/tests/test_utils.c +++ b/tests/test_utils.c @@ -65,12 +65,14 @@ void test_fix_tox_conf() { if (fp) { fprintf(fp, "%s", data); fclose(fp); - STASIS_ASSERT(fix_tox_conf(filename, &result) == 0, "fix_tox_conf failed"); + STASIS_ASSERT(fix_tox_conf(filename, &result, PATH_MAX) == 0, "fix_tox_conf failed"); } else { STASIS_ASSERT(false, "writing mock tox.ini failed"); } char **lines = file_readlines(result, 0, 0, NULL); + STASIS_ASSERT_FATAL(lines != NULL, "lines array should not be NULL"); + STASIS_ASSERT_FATAL(result != NULL, "result should not be NULL"); STASIS_ASSERT(strstr_array(lines, expected) != NULL, "{posargs} not found in result"); guard_array_free(lines); @@ -103,7 +105,7 @@ void test_xml_pretty_print_in_place() { } fp = fopen(filename, "r"); - char buf[BUFSIZ] = {0}; + char buf[STASIS_BUFSIZ] = {0}; if (fread(buf, sizeof(*buf), sizeof(buf) - 1, fp) < 1) { STASIS_ASSERT(false, "failed to consume formatted xml file contents"); } @@ -129,7 +131,7 @@ void test_isempty_dir() { STASIS_ASSERT(isempty_dir(dname) > 0, "empty directory went undetected"); char path[PATH_MAX]; - sprintf(path, "%s/file.txt", dname); + snprintf(path, sizeof(path), "%s/file.txt", dname); touch(path); STASIS_ASSERT(isempty_dir(dname) == 0, "populated directory went undetected"); @@ -147,7 +149,9 @@ void test_xmkstemp() { char buf[100] = {0}; tempfp = fopen(tempfile, "r"); - fgets(buf, sizeof(buf) - 1, tempfp); + const char *line = fgets(buf, sizeof(buf) - 1, tempfp); + STASIS_ASSERT_FATAL(line != NULL, "file should contain data written earlier"); + STASIS_ASSERT(strcmp(line, buf) == 0, "file should contain the correct data"); fclose(tempfp); STASIS_ASSERT(strcmp(buf, data) == 0, "data written to temp file is incorrect"); @@ -193,7 +197,7 @@ void test_git_clone_and_describe() { // initialize a bare repo so we can clone it char init_cmd[PATH_MAX]; - sprintf(init_cmd, "git init --bare %s", repo_git); + snprintf(init_cmd, sizeof(init_cmd), "git init --bare %s", repo_git); system(init_cmd); // clone the bare repo @@ -213,17 +217,21 @@ void test_git_clone_and_describe() { // test git_describe is functional char *taginfo_none = git_describe("."); STASIS_ASSERT(taginfo_none != NULL, "should be a git hash, not NULL"); + puts(taginfo_none); + STASIS_ASSERT(is_git_sha(taginfo_none) == true, "not a git hash"); system("git tag -a 1.0.0 -m Mock"); system("git push --tags origin"); - char *taginfo = git_describe("."); + const char *taginfo = git_describe("."); + puts(taginfo); STASIS_ASSERT(taginfo != NULL, "should be 1.0.0, not NULL"); - STASIS_ASSERT(strcmp(taginfo, "1.0.0") == 0, "just-created tag was not described correctly"); + STASIS_ASSERT(startswith(taginfo, "1.0.0") == true, "just-created tag was not described correctly"); chdir(".."); char *taginfo_outer = git_describe(repo); + puts(taginfo_outer); STASIS_ASSERT(taginfo_outer != NULL, "should be 1.0.0, not NULL"); - STASIS_ASSERT(strcmp(taginfo_outer, "1.0.0") == 0, "just-created tag was not described correctly (out-of-dir invocation)"); + STASIS_ASSERT(startswith(taginfo_outer, "1.0.0") == true, "just-created tag was not described correctly (out-of-dir invocation)"); char *taginfo_bad = git_describe("abc1234_not_here_or_there"); STASIS_ASSERT(taginfo_bad == NULL, "a repository that shouldn't exist... exists and has a tag."); @@ -268,11 +276,12 @@ void test_file_readlines() { const char *data = "I am\na file\nwith multiple lines\nsee?\n"; FILE *fp = fopen(filename, "w"); if (!fp) { - perror(filename); + SYSERROR("unable to open file: %s, %s", filename, strerror(errno)); return; } if (fwrite(data, sizeof(*data), strlen(data), fp) != strlen(data)) { perror("short write"); + fclose(fp); return; } fclose(fp); @@ -304,7 +313,8 @@ void test_path_dirname() { const char *input = data[i]; const char *expected = data[i + 1]; char tmp[PATH_MAX] = {0}; - strcpy(tmp, input); + strncpy(tmp, input, sizeof(tmp) - 1); + tmp[sizeof(tmp) - 1] = '\0'; char *result = path_dirname(tmp); STASIS_ASSERT(strcmp(expected, result) == 0, NULL); @@ -325,8 +335,7 @@ void test_path_basename() { } void test_expandpath() { - char *home; - + char *home = NULL; const char *homes[] = { "HOME", "USERPROFILE", @@ -337,10 +346,11 @@ void test_expandpath() { break; } } + STASIS_ASSERT_FATAL(home != NULL, "cannot expand without knowing the user's home directory path"); char path[PATH_MAX] = {0}; - strcat(path, "~"); - strcat(path, DIR_SEP); + strncat(path, "~", sizeof(path) - strlen(path) - 1); + strncat(path, DIR_SEP, sizeof(path) - strlen(path) - 1); char *expanded = expandpath(path); STASIS_ASSERT(startswith(expanded, home) > 0, expanded); @@ -362,10 +372,10 @@ void test_rmtree() { for (size_t i = 0; i < sizeof(tree) / sizeof(*tree); i++) { char path[PATH_MAX]; char mockfile[PATH_MAX + 10]; - sprintf(path, "%s/%s", root, tree[i]); - sprintf(mockfile, "%s/%zu.txt", path, i); + snprintf(path, sizeof(path), "%s/%s", root, tree[i]); + snprintf(mockfile, sizeof(mockfile), "%s/%zu.txt", path, i); if (mkdir(path, 0755)) { - perror(path); + SYSERROR("mkdir failed: %s, %s", path, strerror(errno)); STASIS_ASSERT(false, NULL); } touch(mockfile); diff --git a/tests/test_version_compare.c b/tests/test_version_compare.c new file mode 100644 index 0000000..2a3458f --- /dev/null +++ b/tests/test_version_compare.c @@ -0,0 +1,172 @@ +#include "testing.h" +#include "version_compare.h" + +struct TestCase_version_compare { + char *a, *op, *b; + int expected; +}; + +struct TestCase_version_compare test_cases_version_compare[] = { + {"0", "=", "0", 1}, + {"0", "<", "1",1}, + {"0", "<=", "1",1}, + {"0", ">", "1",0}, + {"0", ">=", "1",0}, + {"0", "!=", "1",1}, + + {"1a", "=", "1b", 0}, + {"1a", "<", "1b", 1}, + {"1a", "<=", "1b", 1}, + {"1a", ">", "1b", 0}, + {"1a", ">=", "1b", 0}, + {"1a", "!=", "1b", 1}, + + {"1.0", "=", "1.0.0", 1}, + {"1.0", "<", "1.0.0", 0}, + {"1.0", "<=", "1.0.0", 1}, + {"1.0", ">", "1.0.0", 0}, + {"1.0", ">=", "1.0.0", 1}, + {"1.0", "!=", "1.0.0", 0}, + + {"1.0rc1", "=", "1.0.0", 0}, + {"1.0rc1", "<", "1.0.0", 1}, + {"1.0rc1", "<=", "1.0.0", 1}, + {"1.0rc1", ">", "1.0.0", 0}, + {"1.0rc1", ">=", "1.0.0", 0}, + {"1.0rc1", "!=", "1.0.0", 1}, + + {"1.0rc1", "=", "1.0.0rc1", 1}, + {"1.0rc1", "<", "1.0.0rc1", 0}, + {"1.0rc1", "<=", "1.0.0rc1", 1}, + {"1.0rc1", ">", "1.0.0rc1", 0}, + {"1.0rc1", ">=", "1.0.0rc1", 1}, + {"1.0rc1", "!=", "1.0.0rc1", 0}, + + {"1.0rc1", "=", "1.0.0dev1", 0}, + {"1.0rc1", "<", "1.0.0dev1", 0}, + {"1.0rc1", "<=", "1.0.0dev1", 0}, + {"1.0rc1", ">", "1.0.0dev1", 1}, + {"1.0rc1", ">=", "1.0.0dev1", 1}, + {"1.0rc1", "!=", "1.0.0dev1", 1}, + + {"1.0post1", "=", "1.0.0dev1", 0}, + {"1.0post1", "<", "1.0.0dev1", 0}, + {"1.0post1", "<=", "1.0.0dev1", 0}, + {"1.0post1", ">", "1.0.0dev1", 1}, + {"1.0post1", ">=", "1.0.0dev1", 1}, + {"1.0post1", "!=", "1.0.0dev1", 1}, + + {"1.0post1", "=", "1.0.0", 0}, + {"1.0post1", "<", "1.0.0", 0}, + {"1.0post1", "<=", "1.0.0", 0}, + {"1.0post1", ">", "1.0.0", 1}, + {"1.0post1", ">=", "1.0.0", 1}, + {"1.0post1", "!=", "1.0.0", 1}, + + {"1.0dev1", "=", "1.0.0dev1", 1}, + {"1.0dev1", "<", "1.0.0dev1", 0}, + {"1.0dev1", "<=", "1.0.0dev1", 1}, + {"1.0dev1", ">", "1.0.0dev1", 0}, + {"1.0dev1", ">=", "1.0.0dev1", 1}, + {"1.0dev1", "!=", "1.0.0dev1", 0}, + + {"1.0a", "=", "1.0.0", 0}, + {"1.0a", "<", "1.0.0", 0}, + {"1.0a", "<=", "1.0.0", 0}, + {"1.0a", ">", "1.0.0", 1}, + {"1.0a", ">=", "1.0.0", 1}, + {"1.0a", "!=", "1.0.0", 1}, + + {"1.0.3", "=", "2.0.0", 0}, + {"1.0.3", "<", "2.0.0", 1}, + {"1.0.3", "<=", "2.0.0", 1}, + {"1.0.3", ">", "2.0.0", 0}, + {"1.0.3", ">=", "2.0.0", 0}, + {"1.0.3", "!=", "2.0.0", 1}, + + {"2022.1", "=", "2022.4", 0}, + {"2022.1", "<", "2022.4", 1}, + {"2022.1", "<=", "2022.4", 1}, + {"2022.1", ">", "2022.4", 0}, + {"2022.1", ">=", "2022.4", 0}, + {"2022.1", "!=", "2022.4", 1}, + + {"1:2022.1", "=", "2022.4", 0}, + {"1:2022.1", "<", "2022.4", 1}, + {"1:2022.1", "<=", "2022.4", 1}, + {"1:2022.1", ">", "2022.4", 0}, + {"1:2022.1", ">=", "2022.4", 0}, + {"1:2022.1", "!=", "2022.4", 1}, + + {"1:2022.1", "=", "2:2022.4", 0}, + {"1:2022.1", "<", "2:2022.4", 1}, + {"1:2022.1", "<=", "2:2022.4", 1}, + {"1:2022.1", ">", "2:2022.4", 0}, + {"1:2022.1", ">=", "2:2022.4", 0}, + {"1:2022.1", "!=", "2:2022.4", 1}, + + {"2:2022.4", "=", "1:2022.1", 0}, + {"2:2022.4", "<", "1:2022.1", 0}, + {"2:2022.4", "<=", "1:2022.1", 0}, + {"2:2022.4", ">", "1:2022.1", 1}, + {"2:2022.4", ">=", "1:2022.1", 1}, + {"2:2022.4", "!=", "1:2022.1", 1}, + + {"2022.1", "=", "2:2022.1", 0}, + {"2022.1", "<", "2:2022.1", 1}, + {"2022.1", "<=", "2:2022.1", 1}, + {"2022.1", ">", "2:2022.1", 0}, + {"2022.1", ">=", "2:2022.1", 0}, + {"2022.1", "!=", "2:2022.1", 1}, + + {"2022.4", "=", "2022.1", 0}, + {"2022.4", "<", "2022.1", 0}, + {"2022.4", "<=", "2022.1", 0}, + {"2022.4", ">", "2022.1", 1}, + {"2022.4", ">=", "2022.1", 1}, + {"2022.4", "!=", "2022.1", 1}, + + // Error cases + {NULL, "", "", -1}, + {"", NULL, "", -1}, + {"", "", NULL, -1}, + {NULL, NULL, NULL, -1}, + {"", "=", "", -1}, + {" ", "=", " ", -1}, + {"a", "", "a", -1}, + {"a", "", "b", -1}, + {"a", "@", "b", -1}, +}; + +void run_cases_version_compare(void) { + const size_t size = sizeof(test_cases_version_compare) / sizeof(test_cases_version_compare[0]); + for (size_t i = 0; i < size; i++) { + int result = 0; + const struct TestCase_version_compare *test = &test_cases_version_compare[i]; + const int op = version_parse_operator(test->op); + result = version_compare(op, test->a, test->b); + STASIS_ASSERT(test->expected == result, "unexpected result"); + + fprintf(stderr, "'%s' '%s' '%s' is %s (%d)", + test->a ? test->a : "NULL", + test->op ? test->op : "NULL", + test->b ? test->b : "NULL", + result == test->expected ? "EXPECTED" : "UNEXPECTED", + result); + if (test->expected != result) { + fprintf(stderr, " [FAILED: got %d, expected %d]\n", result, test->expected); + } else { + puts(""); + } + } +} + +int main(void) { + STASIS_TEST_BEGIN_MAIN(); + STASIS_TEST_FUNC *tests[] = { + run_cases_version_compare, + }; + STASIS_TEST_RUN(tests); + + STASIS_TEST_END_MAIN(); +} diff --git a/tests/test_wheel.c b/tests/test_wheel.c index 6818b22..e486b05 100644 --- a/tests/test_wheel.c +++ b/tests/test_wheel.c @@ -1,91 +1,217 @@ +#include "conda.h" +#include "delivery.h" #include "testing.h" +#include "str.h" #include "wheel.h" -void test_get_wheel_file() { - struct testcase { - const char *filename; - struct Wheel expected; - }; - struct testcase tc[] = { - { - // Test for "build tags" - .filename = "btpackage-1.2.3-mytag-py2.py3-none-any.whl", - .expected = { - .file_name = "btpackage-1.2.3-mytag-py2.py3-none-any.whl", - .version = "1.2.3", - .distribution = "btpackage", - .build_tag = "mytag", - .platform_tag = "any", - .python_tag = "py2.py3", - .abi_tag = "none", - .path_name = ".", - } - }, - { - // Test for universal package format - .filename = "anypackage-1.2.3-py2.py3-none-any.whl", - .expected = { - .file_name = "anypackage-1.2.3-py2.py3-none-any.whl", - .version = "1.2.3", - .distribution = "anypackage", - .build_tag = NULL, - .platform_tag = "any", - .python_tag = "py2.py3", - .abi_tag = "none", - .path_name = ".", - } - }, - { - // Test for binary package format - .filename = "binpackage-1.2.3-cp311-cp311-linux_x86_64.whl", - .expected = { - .file_name = "binpackage-1.2.3-cp311-cp311-linux_x86_64.whl", - .version = "1.2.3", - .distribution = "binpackage", - .build_tag = NULL, - .platform_tag = "linux_x86_64", - .python_tag = "cp311", - .abi_tag = "cp311", - .path_name = ".", - } - }, - }; +char cwd_start[PATH_MAX]; +char cwd_workspace[PATH_MAX]; +int conda_is_installed = 0; +static char conda_prefix[PATH_MAX] = {0}; +struct Delivery ctx; +static const char *testpkg_filename = "testpkg/dist/testpkg-1.0.0-py3-none-any.whl"; + + +static void test_wheel_package() { + const char *filename = testpkg_filename; + struct Wheel *wheel = NULL; + int state = wheel_package(&wheel, filename); + STASIS_ASSERT(state != WHEEL_PACKAGE_E_ALLOC, "Cannot fail to allocate memory for package structure"); + STASIS_ASSERT(state != WHEEL_PACKAGE_E_GET, "Cannot fail to parse wheel"); + STASIS_ASSERT(state != WHEEL_PACKAGE_E_GET_METADATA, "Cannot fail to read wheel metadata"); + STASIS_ASSERT(state != WHEEL_PACKAGE_E_GET_RECORDS, "Cannot fail reading wheel path records"); + STASIS_ASSERT(state != WHEEL_PACKAGE_E_GET_ENTRY_POINT, "Cannot fail reading wheel entry points"); + STASIS_ASSERT(state == WHEEL_PACKAGE_E_SUCCESS, "Wheel file should be usable"); + STASIS_ASSERT(wheel != NULL, "wheel cannot be NULL"); + STASIS_ASSERT(wheel != NULL, "wheel_package failed to initialize wheel struct"); + STASIS_ASSERT(wheel->record != NULL, "Record cannot be NULL"); + STASIS_ASSERT(wheel->num_record > 0, "Record count cannot be zero"); + STASIS_ASSERT(wheel->tag != NULL, "Package tag list cannot be NULL"); + STASIS_ASSERT(wheel->generator != NULL, "Generator field cannot be NULL"); + STASIS_ASSERT(wheel->top_level != NULL, "Top level directory name cannot be NULL"); + STASIS_ASSERT(wheel->wheel_version != NULL, "Wheel version cannot be NULL"); + STASIS_ASSERT(wheel->metadata != NULL, "Metadata cannot be NULL"); + STASIS_ASSERT(wheel->metadata->name != NULL, "Metadata::name cannot be NULL"); + STASIS_ASSERT(wheel->metadata->version != NULL, "Metadata::version cannot be NULL"); + STASIS_ASSERT(wheel->metadata->metadata_version != NULL, "Metadata::version (of metadata) cannot be NULL"); + + // Implied test against key/id getters. If wheel_show_info segfaults, that functionality is broken. + STASIS_ASSERT(wheel_show_info(wheel) == 0, "wheel_show_info should never fail. Enum(s) might be out of sync with META_*_KEYS array(s)"); + + // Get data from DIST + const struct WheelValue dist_version = wheel_get_value_by_name(wheel, WHEEL_FROM_DIST, "Wheel-Version"); + STASIS_ASSERT(dist_version.type == WHEELVAL_STR, "Wheel dist version value must be a string"); + STASIS_ASSERT_FATAL(dist_version.data != NULL, "Wheel dist version value must not be NULL"); + STASIS_ASSERT(dist_version.count != 0, "Wheel value must be populated"); + + // Get data from METADATA + const struct WheelValue meta_name = wheel_get_value_by_name(wheel, WHEEL_FROM_METADATA, "Metadata-Version"); + STASIS_ASSERT(meta_name.type == WHEELVAL_STR, "Wheel metadata version value must be a string"); + STASIS_ASSERT_FATAL(meta_name.data != NULL, "Wheel metadata version value must not be NULL"); + STASIS_ASSERT(meta_name.count != 0, "Wheel metadata version value must be populated"); + + wheel_package_free(&wheel); + STASIS_ASSERT(wheel == NULL, "wheel struct should be NULL after free"); +} + +static void mock_python_package() { + const char *pyproject_toml_data = "[build-system]\n" + "requires = [\"setuptools >= 77.0.3\"]\n" + "build-backend = \"setuptools.build_meta\"\n" + "\n" + "[project]\n" + "name = \"testpkg\"\n" + "version = \"1.0.0\"\n" + "authors = [{name = \"STASIS Team\", email = \"stasis@not-a-real-domain.tld\"}]\n" + "description = \"A STASIS test package\"\n" + "readme = \"README.md\"\n" + "license = \"BSD-3-Clause\"\n" + "classifiers = [\"Programming Language :: Python :: 3\"]\n" + "\n" + "[project.urls]\n" + "Homepage = \"https://not-a-real-address.tld\"\n" + "Documentation = \"https://not-a-real-address.tld/docs\"\n" + "Repository = \"https://not-a-real-address.tld/repo.git\"\n" + "Issues = \"https://not-a-real-address.tld/tracker\"\n" + "Changelog = \"https://not-a-real-address.tld/changes\"\n"; + const char *readme = "# testpkg\n\nThis is a test package, for testing.\n"; - struct Wheel *doesnotexist = get_wheel_info("doesnotexist", "doesnotexist-0.0.1-py2.py3-none-any.whl", (char *[]) {"not", NULL}, WHEEL_MATCH_ANY); - STASIS_ASSERT(doesnotexist == NULL, "returned non-NULL on error"); - - for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { - struct testcase *test = &tc[i]; - struct Wheel *wheel = get_wheel_info(".", test->expected.distribution, (char *[]) {(char *) test->expected.version, NULL}, WHEEL_MATCH_ANY); - STASIS_ASSERT(wheel != NULL, "result should not be NULL!"); - STASIS_ASSERT(wheel->file_name && strcmp(wheel->file_name, test->expected.file_name) == 0, "mismatched file name"); - STASIS_ASSERT(wheel->version && strcmp(wheel->version, test->expected.version) == 0, "mismatched version"); - STASIS_ASSERT(wheel->distribution && strcmp(wheel->distribution, test->expected.distribution) == 0, "mismatched distribution (package name)"); - STASIS_ASSERT(wheel->platform_tag && strcmp(wheel->platform_tag, test->expected.platform_tag) == 0, "mismatched platform tag ([platform]_[architecture])"); - STASIS_ASSERT(wheel->python_tag && strcmp(wheel->python_tag, test->expected.python_tag) == 0, "mismatched python tag (python version)"); - STASIS_ASSERT(wheel->abi_tag && strcmp(wheel->abi_tag, test->expected.abi_tag) == 0, "mismatched abi tag (python compatibility version)"); - if (wheel->build_tag) { - STASIS_ASSERT(strcmp(wheel->build_tag, test->expected.build_tag) == 0, - "mismatched build tag (optional arbitrary string)"); - } - wheel_free(&wheel); + mkdir("testpkg", 0755); + mkdir("testpkg/src", 0755); + mkdir("testpkg/src/testpkg", 0755); + if (touch("testpkg/src/testpkg/__init__.py")) { + SYSERROR("unable to write __init__.py"); + exit(1); + } + if (touch("testpkg/README.md")) { + SYSERROR("unable to write README.md"); + exit(1); + } + if (stasis_testing_write_ascii("testpkg/pyproject.toml", pyproject_toml_data)) { + SYSERROR("unable to write pyproject.toml"); + exit(1); + } + if (stasis_testing_write_ascii("testpkg/README.md", readme)) { + SYSERROR("unable to write readme"); + exit(1); + } + if (pip_exec("install build")) { + SYSERROR("unable to install build tool using pip"); + exit(1); + } + if (python_exec("-m build -w ./testpkg")) { + SYSERROR("unable build test package"); + exit(1); } } int main(int argc, char *argv[]) { STASIS_TEST_BEGIN_MAIN(); STASIS_TEST_FUNC *tests[] = { - test_get_wheel_file, + test_wheel_package, }; - // Create mock package directories, and files - mkdir("binpackage", 0755); - touch("binpackage/binpackage-1.2.3-cp311-cp311-linux_x86_64.whl"); - mkdir("anypackage", 0755); - touch("anypackage/anypackage-1.2.3-py2.py3-none-any.whl"); - mkdir("btpackage", 0755); - touch("btpackage/btpackage-1.2.3-mytag-py2.py3-none-any.whl"); + char ws[] = "workspace_XXXXXX"; + if (!mkdtemp(ws)) { + SYSERROR("mkdtemp failed: %s, %s", ws, strerror(errno)); + exit(1); + } + getcwd(cwd_start, sizeof(cwd_start) - 1); + mkdir(ws, 0755); + chdir(ws); + getcwd(cwd_workspace, sizeof(cwd_workspace) - 1); + + snprintf(conda_prefix, strlen(cwd_workspace) + strlen("conda") + 2, "%s/conda", cwd_workspace); + + const char *mockinidata = "[meta]\n" + "name = mock\n" + "version = 1.0.0\n" + "rc = 1\n" + "mission = generic\n" + "python = 3.11\n" + "[conda]\n" + "installer_name = Miniforge3\n" + "installer_version = 24.3.0-0\n" + "installer_platform = {{env:STASIS_CONDA_PLATFORM}}\n" + "installer_arch = {{env:STASIS_CONDA_ARCH}}\n" + "installer_baseurl = https://github.com/conda-forge/miniforge/releases/download/24.3.0-0\n"; + stasis_testing_write_ascii("mock.ini", mockinidata); + struct INIFILE *ini = ini_open("mock.ini"); + ctx._stasis_ini_fp.delivery = ini; + ctx._stasis_ini_fp.delivery_path = realpath("mock.ini", NULL); + + const char *sysconfdir = getenv("STASIS_SYSCONFDIR"); + globals.sysconfdir = strdup(sysconfdir ? sysconfdir : STASIS_SYSCONFDIR); + ctx.storage.root = strdup(cwd_workspace); + char *cfgfile = join((char *[]) {globals.sysconfdir, "stasis.ini", NULL}, "/"); + if (!cfgfile) { + SYSERROR("unable to create path to global config"); + exit(1); + } + + ctx._stasis_ini_fp.cfg = ini_open(cfgfile); + if (!ctx._stasis_ini_fp.cfg) { + SYSERROR("unable to open config file, %s", cfgfile); + exit(1); + } + ctx._stasis_ini_fp.cfg_path = realpath(cfgfile, NULL); + if (!ctx._stasis_ini_fp.cfg_path) { + SYSERROR("unable to determine absolute path of config, %s", cfgfile); + exit(1); + } + guard_free(cfgfile); + + setenv("LANG", "C", 1); + if (bootstrap_build_info(&ctx)) { + SYSERROR("bootstrap_build_info failed"); + exit(1); + } + if (delivery_init(&ctx, INI_READ_RENDER)) { + SYSERROR("delivery_init failed"); + exit(1); + } + + char *install_url = calloc(255, sizeof(install_url)); + delivery_get_conda_installer_url(&ctx, install_url, PATH_MAX); + delivery_get_conda_installer(&ctx, install_url); + delivery_install_conda(ctx.conda.installer_path, ctx.storage.conda_install_prefix); + guard_free(install_url); + + if (conda_activate(ctx.storage.conda_install_prefix, "base")) { + SYSERROR("conda_activate failed"); + exit(1); + } + if (conda_exec("install -y boa conda-build")) { + SYSERROR("conda_exec failed"); + exit(1); + } + if (conda_setup_headless()) { + SYSERROR("conda_setup_headless failed"); + exit(1); + } + if (conda_env_create("testpkg", ctx.meta.python, NULL)) { + SYSERROR("conda_env_create failed"); + exit(1); + } + if (conda_activate(ctx.storage.conda_install_prefix, "testpkg")) { + SYSERROR("conda_activate failed"); + exit(1); + } + + mock_python_package(); STASIS_TEST_RUN(tests); + + if (chdir(cwd_start) < 0) { + SYSERROR("chdir failed: %s, %s", cwd_start, strerror(errno)); + exit(1); + } + if (rmtree(cwd_workspace)) { + SYSERROR("rmtree failed: %s, %s", cwd_workspace, strerror(errno)); + } + delivery_free(&ctx); + globals_free(); + STASIS_TEST_END_MAIN(); + }
\ No newline at end of file diff --git a/tests/test_wheelinfo.c b/tests/test_wheelinfo.c new file mode 100644 index 0000000..1abbeac --- /dev/null +++ b/tests/test_wheelinfo.c @@ -0,0 +1,91 @@ +#include "testing.h" +#include "wheelinfo.h" + +void test_wheelinfo_get() { + struct testcase { + const char *filename; + struct WheelInfo expected; + }; + struct testcase tc[] = { + { + // Test for "build tags" + .filename = "btpackage-1.2.3-mytag-py2.py3-none-any.whl", + .expected = { + .file_name = "btpackage-1.2.3-mytag-py2.py3-none-any.whl", + .version = "1.2.3", + .distribution = "btpackage", + .build_tag = "mytag", + .platform_tag = "any", + .python_tag = "py2.py3", + .abi_tag = "none", + .path_name = ".", + } + }, + { + // Test for universal package format + .filename = "anypackage-1.2.3-py2.py3-none-any.whl", + .expected = { + .file_name = "anypackage-1.2.3-py2.py3-none-any.whl", + .version = "1.2.3", + .distribution = "anypackage", + .build_tag = NULL, + .platform_tag = "any", + .python_tag = "py2.py3", + .abi_tag = "none", + .path_name = ".", + } + }, + { + // Test for binary package format + .filename = "binpackage-1.2.3-cp311-cp311-linux_x86_64.whl", + .expected = { + .file_name = "binpackage-1.2.3-cp311-cp311-linux_x86_64.whl", + .version = "1.2.3", + .distribution = "binpackage", + .build_tag = NULL, + .platform_tag = "linux_x86_64", + .python_tag = "cp311", + .abi_tag = "cp311", + .path_name = ".", + } + }, + }; + + struct WheelInfo *doesnotexist = wheelinfo_get("doesnotexist", "doesnotexist-0.0.1-py2.py3-none-any.whl", (char *[]) {"not", NULL}, WHEEL_MATCH_ANY); + STASIS_ASSERT(doesnotexist == NULL, "returned non-NULL on error"); + + for (size_t i = 0; i < sizeof(tc) / sizeof(*tc); i++) { + struct testcase *test = &tc[i]; + struct WheelInfo *wheel = wheelinfo_get(".", test->expected.distribution, (char *[]) {(char *) test->expected.version, NULL}, WHEEL_MATCH_ANY); + STASIS_ASSERT(wheel != NULL, "result should not be NULL!"); + STASIS_ASSERT(wheel->file_name && strcmp(wheel->file_name, test->expected.file_name) == 0, "mismatched file name"); + STASIS_ASSERT(wheel->version && strcmp(wheel->version, test->expected.version) == 0, "mismatched version"); + STASIS_ASSERT(wheel->distribution && strcmp(wheel->distribution, test->expected.distribution) == 0, "mismatched distribution (package name)"); + STASIS_ASSERT(wheel->platform_tag && strcmp(wheel->platform_tag, test->expected.platform_tag) == 0, "mismatched platform tag ([platform]_[architecture])"); + STASIS_ASSERT(wheel->python_tag && strcmp(wheel->python_tag, test->expected.python_tag) == 0, "mismatched python tag (python version)"); + STASIS_ASSERT(wheel->abi_tag && strcmp(wheel->abi_tag, test->expected.abi_tag) == 0, "mismatched abi tag (python compatibility version)"); + if (wheel->build_tag) { + STASIS_ASSERT(strcmp(wheel->build_tag, test->expected.build_tag) == 0, + "mismatched build tag (optional arbitrary string)"); + } + wheelinfo_free(&wheel); + } +} + +int main(int argc, char *argv[]) { + STASIS_TEST_BEGIN_MAIN(); + STASIS_TEST_FUNC *tests[] = { + test_wheelinfo_get, + }; + + // Create mock package directories, and files + mkdir("binpackage", 0755); + touch("binpackage/binpackage-1.2.3-cp311-cp311-linux_x86_64.whl"); + mkdir("anypackage", 0755); + touch("anypackage/anypackage-1.2.3-py2.py3-none-any.whl"); + mkdir("btpackage", 0755); + touch("btpackage/btpackage-1.2.3-mytag-py2.py3-none-any.whl"); + + STASIS_TEST_RUN(tests); + STASIS_TEST_END_MAIN(); +}
\ No newline at end of file |
