mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-05 07:26:40 +00:00
532 lines
11 KiB
C
532 lines
11 KiB
C
|
|
/*
|
|
* Clay v0.7.0
|
|
*
|
|
* This is an autogenerated file. Do not modify.
|
|
* To add new unit tests or suites, regenerate the whole
|
|
* file with `./clay`
|
|
*/
|
|
|
|
#define clay_print(...) printf(__VA_ARGS__)
|
|
|
|
#include <assert.h>
|
|
#include <setjmp.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
/* required for sandboxing */
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "clay.h"
|
|
|
|
struct clay_error {
|
|
const char *test;
|
|
int test_number;
|
|
const char *suite;
|
|
const char *file;
|
|
int line_number;
|
|
const char *error_msg;
|
|
char *description;
|
|
|
|
struct clay_error *next;
|
|
};
|
|
|
|
static struct {
|
|
const char *active_test;
|
|
const char *active_suite;
|
|
|
|
int suite_errors;
|
|
int total_errors;
|
|
|
|
int test_count;
|
|
|
|
struct clay_error *errors;
|
|
struct clay_error *last_error;
|
|
|
|
void (*local_cleanup)(void *);
|
|
void *local_cleanup_payload;
|
|
|
|
jmp_buf trampoline;
|
|
int trampoline_enabled;
|
|
} _clay;
|
|
|
|
struct clay_func {
|
|
const char *name;
|
|
void (*ptr)(void);
|
|
size_t suite_n;
|
|
};
|
|
|
|
struct clay_suite {
|
|
const char *name;
|
|
struct clay_func initialize;
|
|
struct clay_func cleanup;
|
|
const struct clay_func *tests;
|
|
size_t test_count;
|
|
};
|
|
|
|
/* From clay_sandbox.c */
|
|
static void clay_unsandbox(void);
|
|
static int clay_sandbox(void);
|
|
|
|
static void
|
|
clay_run_test(
|
|
const struct clay_func *test,
|
|
const struct clay_func *initialize,
|
|
const struct clay_func *cleanup)
|
|
{
|
|
int error_st = _clay.suite_errors;
|
|
|
|
_clay.trampoline_enabled = 1;
|
|
|
|
if (setjmp(_clay.trampoline) == 0) {
|
|
if (initialize->ptr != NULL)
|
|
initialize->ptr();
|
|
|
|
test->ptr();
|
|
}
|
|
|
|
_clay.trampoline_enabled = 0;
|
|
|
|
if (_clay.local_cleanup != NULL)
|
|
_clay.local_cleanup(_clay.local_cleanup_payload);
|
|
|
|
if (cleanup->ptr != NULL)
|
|
cleanup->ptr();
|
|
|
|
_clay.test_count++;
|
|
|
|
/* remove any local-set cleanup methods */
|
|
_clay.local_cleanup = NULL;
|
|
_clay.local_cleanup_payload = NULL;
|
|
|
|
clay_print("%c", (_clay.suite_errors > error_st) ? 'F' : '.');
|
|
}
|
|
|
|
static void
|
|
clay_print_error(int num, const struct clay_error *error)
|
|
{
|
|
clay_print(" %d) Failure:\n", num);
|
|
|
|
clay_print("%s::%s (%s) [%s:%d] [-t%d]\n",
|
|
error->suite,
|
|
error->test,
|
|
"no description",
|
|
error->file,
|
|
error->line_number,
|
|
error->test_number);
|
|
|
|
clay_print(" %s\n", error->error_msg);
|
|
|
|
if (error->description != NULL)
|
|
clay_print(" %s\n", error->description);
|
|
|
|
clay_print("\n");
|
|
}
|
|
|
|
static void
|
|
clay_report_errors(void)
|
|
{
|
|
int i = 1;
|
|
struct clay_error *error, *next;
|
|
|
|
error = _clay.errors;
|
|
while (error != NULL) {
|
|
next = error->next;
|
|
clay_print_error(i++, error);
|
|
free(error->description);
|
|
free(error);
|
|
error = next;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clay_run_suite(const struct clay_suite *suite)
|
|
{
|
|
const struct clay_func *test = suite->tests;
|
|
size_t i;
|
|
|
|
_clay.active_suite = suite->name;
|
|
_clay.suite_errors = 0;
|
|
|
|
for (i = 0; i < suite->test_count; ++i) {
|
|
_clay.active_test = test[i].name;
|
|
clay_run_test(&test[i], &suite->initialize, &suite->cleanup);
|
|
}
|
|
}
|
|
|
|
static void
|
|
clay_run_single(const struct clay_func *test,
|
|
const struct clay_suite *suite)
|
|
{
|
|
_clay.suite_errors = 0;
|
|
_clay.active_suite = suite->name;
|
|
_clay.active_test = test->name;
|
|
|
|
clay_run_test(test, &suite->initialize, &suite->cleanup);
|
|
}
|
|
|
|
static void
|
|
clay_usage(const char *arg)
|
|
{
|
|
printf("Usage: %s [options]\n\n", arg);
|
|
printf("Options:\n");
|
|
printf(" -tXX\t\tRun only the test number XX\n");
|
|
printf(" -sXX\t\tRun only the suite number XX\n");
|
|
exit(-1);
|
|
}
|
|
|
|
static void
|
|
clay_parse_args(
|
|
int argc, char **argv,
|
|
const struct clay_func *callbacks,
|
|
size_t cb_count,
|
|
const struct clay_suite *suites,
|
|
size_t suite_count)
|
|
{
|
|
int i;
|
|
|
|
for (i = 1; i < argc; ++i) {
|
|
char *argument = argv[i];
|
|
char action;
|
|
int num;
|
|
|
|
if (argument[0] != '-')
|
|
clay_usage(argv[0]);
|
|
|
|
action = argument[1];
|
|
num = strtol(argument + 2, &argument, 10);
|
|
|
|
if (*argument != '\0' || num < 0)
|
|
clay_usage(argv[0]);
|
|
|
|
switch (action) {
|
|
case 't':
|
|
if ((size_t)num >= cb_count) {
|
|
fprintf(stderr, "Test number %d does not exist.\n", num);
|
|
exit(-1);
|
|
}
|
|
|
|
clay_print("Started (%s::%s)\n",
|
|
suites[callbacks[num].suite_n].name,
|
|
callbacks[num].name);
|
|
|
|
clay_run_single(&callbacks[num], &suites[callbacks[num].suite_n]);
|
|
break;
|
|
|
|
case 's':
|
|
if ((size_t)num >= suite_count) {
|
|
fprintf(stderr, "Suite number %d does not exist.\n", num);
|
|
exit(-1);
|
|
}
|
|
|
|
clay_print("Started (%s::*)\n", suites[num].name);
|
|
clay_run_suite(&suites[num]);
|
|
break;
|
|
|
|
default:
|
|
clay_usage(argv[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
clay_test(
|
|
int argc, char **argv,
|
|
const char *suites_str,
|
|
const struct clay_func *callbacks,
|
|
size_t cb_count,
|
|
const struct clay_suite *suites,
|
|
size_t suite_count)
|
|
{
|
|
clay_print("Loaded %d suites: %s\n", (int)suite_count, suites_str);
|
|
|
|
if (!clay_sandbox()) {
|
|
fprintf(stderr,
|
|
"Failed to sandbox the test runner.\n"
|
|
"Testing will proceed without sandboxing.\n");
|
|
}
|
|
|
|
if (argc > 1) {
|
|
clay_parse_args(argc, argv,
|
|
callbacks, cb_count, suites, suite_count);
|
|
|
|
} else {
|
|
size_t i;
|
|
clay_print("Started\n");
|
|
|
|
for (i = 0; i < suite_count; ++i) {
|
|
const struct clay_suite *s = &suites[i];
|
|
clay_run_suite(s);
|
|
}
|
|
}
|
|
|
|
clay_print("\n\n");
|
|
clay_report_errors();
|
|
|
|
clay_unsandbox();
|
|
return _clay.total_errors;
|
|
}
|
|
|
|
void
|
|
clay__assert(
|
|
int condition,
|
|
const char *file,
|
|
int line,
|
|
const char *error_msg,
|
|
const char *description,
|
|
int should_abort)
|
|
{
|
|
struct clay_error *error;
|
|
|
|
if (condition)
|
|
return;
|
|
|
|
error = calloc(1, sizeof(struct clay_error));
|
|
|
|
if (_clay.errors == NULL)
|
|
_clay.errors = error;
|
|
|
|
if (_clay.last_error != NULL)
|
|
_clay.last_error->next = error;
|
|
|
|
_clay.last_error = error;
|
|
|
|
error->test = _clay.active_test;
|
|
error->test_number = _clay.test_count;
|
|
error->suite = _clay.active_suite;
|
|
error->file = file;
|
|
error->line_number = line;
|
|
error->error_msg = error_msg;
|
|
|
|
if (description != NULL)
|
|
error->description = strdup(description);
|
|
|
|
_clay.suite_errors++;
|
|
_clay.total_errors++;
|
|
|
|
if (should_abort) {
|
|
if (!_clay.trampoline_enabled) {
|
|
fprintf(stderr,
|
|
"Unhandled exception: a cleanup method raised an exception.");
|
|
exit(-1);
|
|
}
|
|
|
|
longjmp(_clay.trampoline, -1);
|
|
}
|
|
}
|
|
|
|
void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
|
|
{
|
|
_clay.local_cleanup = cleanup;
|
|
_clay.local_cleanup_payload = opaque;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
# define PLATFORM_SEP '\\'
|
|
#else
|
|
# define PLATFORM_SEP '/'
|
|
#endif
|
|
|
|
static char _clay_path[4096];
|
|
|
|
static int
|
|
is_valid_tmp_path(const char *path)
|
|
{
|
|
struct stat st;
|
|
return (lstat(path, &st) == 0 &&
|
|
(S_ISDIR(st.st_mode) ||
|
|
S_ISLNK(st.st_mode)) &&
|
|
access(path, W_OK) == 0);
|
|
}
|
|
|
|
static int
|
|
find_tmp_path(char *buffer, size_t length)
|
|
{
|
|
static const size_t var_count = 4;
|
|
static const char *env_vars[] = {
|
|
"TMPDIR", "TMP", "TEMP", "USERPROFILE"
|
|
};
|
|
|
|
size_t i;
|
|
|
|
#ifdef _WIN32
|
|
if (GetTempPath((DWORD)length, buffer))
|
|
return 1;
|
|
#endif
|
|
|
|
for (i = 0; i < var_count; ++i) {
|
|
const char *env = getenv(env_vars[i]);
|
|
if (!env)
|
|
continue;
|
|
|
|
if (is_valid_tmp_path(env)) {
|
|
strncpy(buffer, env, length);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* If the environment doesn't say anything, try to use /tmp */
|
|
if (is_valid_tmp_path("/tmp")) {
|
|
strncpy(buffer, "/tmp", length);
|
|
return 1;
|
|
}
|
|
|
|
/* This system doesn't like us, try to use the current directory */
|
|
if (is_valid_tmp_path(".")) {
|
|
strncpy(buffer, ".", length);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int clean_folder(const char *path)
|
|
{
|
|
const char os_cmd[] =
|
|
#ifdef _WIN32
|
|
"rd /s /q \"%s\"";
|
|
#else
|
|
"rm -rf \"%s\"";
|
|
#endif
|
|
|
|
char command[4096];
|
|
snprintf(command, sizeof(command), os_cmd, path);
|
|
return system(command);
|
|
}
|
|
|
|
static void clay_unsandbox(void)
|
|
{
|
|
if (_clay_path[0] == '\0')
|
|
return;
|
|
|
|
clean_folder(_clay_path);
|
|
}
|
|
|
|
static int clay_sandbox(void)
|
|
{
|
|
const char path_tail[] = "clay_tmp_XXXXXX";
|
|
size_t len;
|
|
|
|
if (!find_tmp_path(_clay_path, sizeof(_clay_path)))
|
|
return 0;
|
|
|
|
len = strlen(_clay_path);
|
|
|
|
if (_clay_path[len - 1] != PLATFORM_SEP) {
|
|
_clay_path[len++] = PLATFORM_SEP;
|
|
}
|
|
|
|
strcpy(_clay_path + len, path_tail);
|
|
|
|
if (mktemp(_clay_path) == NULL)
|
|
return 0;
|
|
|
|
if (mkdir(_clay_path, 0700) != 0)
|
|
return 0;
|
|
|
|
if (chdir(_clay_path) != 0)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
extern void test_core_dirent__dont_traverse_dot(void);
|
|
extern void test_core_dirent__traverse_subfolder(void);
|
|
extern void test_core_dirent__traverse_slash_terminated_folder(void);
|
|
extern void test_core_dirent__dont_traverse_empty_folders(void);
|
|
extern void test_core_dirent__traverse_weird_filenames(void);
|
|
extern void test_core_filebuf__0(void);
|
|
extern void test_core_filebuf__1(void);
|
|
extern void test_core_filebuf__2(void);
|
|
extern void test_core_path__0(void);
|
|
extern void test_core_path__1(void);
|
|
extern void test_core_path__2(void);
|
|
extern void test_core_path__5(void);
|
|
extern void test_core_path__6(void);
|
|
extern void test_core_rmdir__initialize();
|
|
extern void test_core_rmdir__delete_recursive(void);
|
|
extern void test_core_rmdir__fail_to_delete_non_empty_dir(void);
|
|
extern void test_core_string__0(void);
|
|
extern void test_core_string__1(void);
|
|
extern void test_core_vector__0(void);
|
|
extern void test_core_vector__1(void);
|
|
extern void test_core_vector__2(void);
|
|
|
|
static const struct clay_func _all_callbacks[] = {
|
|
{"dont_traverse_dot", &test_core_dirent__dont_traverse_dot, 0},
|
|
{"traverse_subfolder", &test_core_dirent__traverse_subfolder, 0},
|
|
{"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder, 0},
|
|
{"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders, 0},
|
|
{"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames, 0},
|
|
{"0", &test_core_filebuf__0, 1},
|
|
{"1", &test_core_filebuf__1, 1},
|
|
{"2", &test_core_filebuf__2, 1},
|
|
{"0", &test_core_path__0, 2},
|
|
{"1", &test_core_path__1, 2},
|
|
{"2", &test_core_path__2, 2},
|
|
{"5", &test_core_path__5, 2},
|
|
{"6", &test_core_path__6, 2},
|
|
{"delete_recursive", &test_core_rmdir__delete_recursive, 3},
|
|
{"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir, 3},
|
|
{"0", &test_core_string__0, 4},
|
|
{"1", &test_core_string__1, 4},
|
|
{"0", &test_core_vector__0, 5},
|
|
{"1", &test_core_vector__1, 5},
|
|
{"2", &test_core_vector__2, 5}
|
|
};
|
|
|
|
static const struct clay_suite _all_suites[] = {
|
|
{
|
|
"core::dirent",
|
|
{NULL, NULL, 0},
|
|
{NULL, NULL, 0},
|
|
&_all_callbacks[0], 5
|
|
},
|
|
{
|
|
"core::filebuf",
|
|
{NULL, NULL, 0},
|
|
{NULL, NULL, 0},
|
|
&_all_callbacks[5], 3
|
|
},
|
|
{
|
|
"core::path",
|
|
{NULL, NULL, 0},
|
|
{NULL, NULL, 0},
|
|
&_all_callbacks[8], 5
|
|
},
|
|
{
|
|
"core::rmdir",
|
|
{"initialize", &test_core_rmdir__initialize, 3},
|
|
{NULL, NULL, 0},
|
|
&_all_callbacks[13], 2
|
|
},
|
|
{
|
|
"core::string",
|
|
{NULL, NULL, 0},
|
|
{NULL, NULL, 0},
|
|
&_all_callbacks[15], 2
|
|
},
|
|
{
|
|
"core::vector",
|
|
{NULL, NULL, 0},
|
|
{NULL, NULL, 0},
|
|
&_all_callbacks[17], 3
|
|
}
|
|
};
|
|
|
|
static const char _suites_str[] = "core::dirent, core::filebuf, core::path, core::rmdir, core::string, core::vector";
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
return clay_test(
|
|
argc, argv, _suites_str,
|
|
_all_callbacks, 20,
|
|
_all_suites, 6
|
|
);
|
|
}
|