aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt14
-rw-r--r--tests/include/testing.h46
-rw-r--r--tests/setup.sh4
-rw-r--r--tests/test_artifactory.c15
-rw-r--r--tests/test_conda.c30
-rw-r--r--tests/test_docker.c2
-rw-r--r--tests/test_download.c3
-rw-r--r--tests/test_environment.c4
-rw-r--r--tests/test_ini.c18
-rw-r--r--tests/test_junitxml.c4
-rw-r--r--tests/test_multiprocessing.c48
-rw-r--r--tests/test_recipe.c2
-rw-r--r--tests/test_relocation.c13
-rw-r--r--tests/test_str.c22
-rw-r--r--tests/test_strlist.c20
-rw-r--r--tests/test_system.c4
-rw-r--r--tests/test_template.c51
-rw-r--r--tests/test_tests.c52
-rw-r--r--tests/test_utils.c44
-rw-r--r--tests/test_version_compare.c172
-rw-r--r--tests/test_wheel.c276
-rw-r--r--tests/test_wheelinfo.c91
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