summaryrefslogtreecommitdiff
path: root/tests-clar/clar_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests-clar/clar_main.c')
-rw-r--r--tests-clar/clar_main.c1230
1 files changed, 1230 insertions, 0 deletions
diff --git a/tests-clar/clar_main.c b/tests-clar/clar_main.c
new file mode 100644
index 000000000..16e627041
--- /dev/null
+++ b/tests-clar/clar_main.c
@@ -0,0 +1,1230 @@
+#include <assert.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdarg.h>
+
+/* required for sandboxing */
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+# include <windows.h>
+# include <io.h>
+# include <shellapi.h>
+# include <direct.h>
+
+# define _MAIN_CC __cdecl
+
+# define stat(path, st) _stat(path, st)
+# define mkdir(path, mode) _mkdir(path)
+# define chdir(path) _chdir(path)
+# define access(path, mode) _access(path, mode)
+# define strdup(str) _strdup(str)
+
+# ifndef __MINGW32__
+# pragma comment(lib, "shell32")
+# define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE)
+# define W_OK 02
+# define S_ISDIR(x) ((x & _S_IFDIR) != 0)
+# define mktemp_s(path, len) _mktemp_s(path, len)
+# endif
+ typedef struct _stat STAT_T;
+#else
+# include <sys/wait.h> /* waitpid(2) */
+# include <unistd.h>
+# define _MAIN_CC
+ typedef struct stat STAT_T;
+#endif
+
+#include "clar.h"
+
+static void fs_rm(const char *_source);
+static void fs_copy(const char *_source, const char *dest);
+
+static const char *
+fixture_path(const char *base, const char *fixture_name);
+
+struct clar_error {
+ const char *test;
+ int test_number;
+ const char *suite;
+ const char *file;
+ int line_number;
+ const char *error_msg;
+ char *description;
+
+ struct clar_error *next;
+};
+
+static struct {
+ const char *active_test;
+ const char *active_suite;
+
+ int suite_errors;
+ int total_errors;
+
+ int test_count;
+
+ struct clar_error *errors;
+ struct clar_error *last_error;
+
+ void (*local_cleanup)(void *);
+ void *local_cleanup_payload;
+
+ jmp_buf trampoline;
+ int trampoline_enabled;
+} _clar;
+
+struct clar_func {
+ const char *name;
+ void (*ptr)(void);
+};
+
+struct clar_suite {
+ const char *name;
+ struct clar_func initialize;
+ struct clar_func cleanup;
+ const struct clar_func *tests;
+ size_t test_count;
+};
+
+/* From clar_print_*.c */
+static void clar_print_init(int test_count, int suite_count, const char *suite_names);
+static void clar_print_shutdown(int test_count, int suite_count, int error_count);
+static void clar_print_error(int num, const struct clar_error *error);
+static void clar_print_ontest(const char *test_name, int test_number, int failed);
+static void clar_print_onsuite(const char *suite_name);
+static void clar_print_onabort(const char *msg, ...);
+
+/* From clar_sandbox.c */
+static void clar_unsandbox(void);
+static int clar_sandbox(void);
+
+/* Event callback overrides */
+#define clar_on_test() /* nop */
+#define clar_on_suite() /* nop */
+
+/* Autogenerated test data by clar */
+static const struct clar_func _clar_cb_attr_file[] = {
+ {"assign_variants", &test_attr_file__assign_variants},
+ {"check_attr_examples", &test_attr_file__check_attr_examples},
+ {"match_variants", &test_attr_file__match_variants},
+ {"simple_read", &test_attr_file__simple_read}
+};
+static const struct clar_func _clar_cb_attr_lookup[] = {
+ {"assign_variants", &test_attr_lookup__assign_variants},
+ {"check_attr_examples", &test_attr_lookup__check_attr_examples},
+ {"from_buffer", &test_attr_lookup__from_buffer},
+ {"match_variants", &test_attr_lookup__match_variants},
+ {"simple", &test_attr_lookup__simple}
+};
+static const struct clar_func _clar_cb_attr_repo[] = {
+ {"bad_macros", &test_attr_repo__bad_macros},
+ {"foreach", &test_attr_repo__foreach},
+ {"get_many", &test_attr_repo__get_many},
+ {"get_one", &test_attr_repo__get_one},
+ {"macros", &test_attr_repo__macros},
+ {"manpage_example", &test_attr_repo__manpage_example}
+};
+static const struct clar_func _clar_cb_buf_basic[] = {
+ {"printf", &test_buf_basic__printf},
+ {"resize", &test_buf_basic__resize}
+};
+static const struct clar_func _clar_cb_config_add[] = {
+ {"to_existing_section", &test_config_add__to_existing_section},
+ {"to_new_section", &test_config_add__to_new_section}
+};
+static const struct clar_func _clar_cb_config_new[] = {
+ {"write_new_config", &test_config_new__write_new_config}
+};
+static const struct clar_func _clar_cb_config_read[] = {
+ {"blank_lines", &test_config_read__blank_lines},
+ {"case_sensitive", &test_config_read__case_sensitive},
+ {"empty_files", &test_config_read__empty_files},
+ {"header_in_last_line", &test_config_read__header_in_last_line},
+ {"invalid_ext_headers", &test_config_read__invalid_ext_headers},
+ {"lone_variable", &test_config_read__lone_variable},
+ {"multiline_value", &test_config_read__multiline_value},
+ {"number_suffixes", &test_config_read__number_suffixes},
+ {"prefixes", &test_config_read__prefixes},
+ {"simple_read", &test_config_read__simple_read},
+ {"subsection_header", &test_config_read__subsection_header}
+};
+static const struct clar_func _clar_cb_config_stress[] = {
+ {"dont_break_on_invalid_input", &test_config_stress__dont_break_on_invalid_input}
+};
+static const struct clar_func _clar_cb_config_write[] = {
+ {"delete_inexistent", &test_config_write__delete_inexistent},
+ {"delete_value", &test_config_write__delete_value},
+ {"replace_value", &test_config_write__replace_value}
+};
+static const struct clar_func _clar_cb_core_buffer[] = {
+ {"0", &test_core_buffer__0},
+ {"1", &test_core_buffer__1},
+ {"2", &test_core_buffer__2},
+ {"3", &test_core_buffer__3},
+ {"4", &test_core_buffer__4},
+ {"5", &test_core_buffer__5},
+ {"6", &test_core_buffer__6},
+ {"7", &test_core_buffer__7},
+ {"8", &test_core_buffer__8},
+ {"9", &test_core_buffer__9}
+};
+static const struct clar_func _clar_cb_core_dirent[] = {
+ {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot},
+ {"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders},
+ {"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder},
+ {"traverse_subfolder", &test_core_dirent__traverse_subfolder},
+ {"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames}
+};
+static const struct clar_func _clar_cb_core_filebuf[] = {
+ {"0", &test_core_filebuf__0},
+ {"1", &test_core_filebuf__1},
+ {"2", &test_core_filebuf__2},
+ {"3", &test_core_filebuf__3},
+ {"4", &test_core_filebuf__4},
+ {"5", &test_core_filebuf__5}
+};
+static const struct clar_func _clar_cb_core_hex[] = {
+ {"fromhex", &test_core_hex__fromhex}
+};
+static const struct clar_func _clar_cb_core_oid[] = {
+ {"streq", &test_core_oid__streq}
+};
+static const struct clar_func _clar_cb_core_path[] = {
+ {"00_dirname", &test_core_path__00_dirname},
+ {"01_basename", &test_core_path__01_basename},
+ {"02_topdir", &test_core_path__02_topdir},
+ {"05_joins", &test_core_path__05_joins},
+ {"06_long_joins", &test_core_path__06_long_joins},
+ {"07_path_to_dir", &test_core_path__07_path_to_dir},
+ {"08_self_join", &test_core_path__08_self_join},
+ {"09_percent_decode", &test_core_path__09_percent_decode},
+ {"10_fromurl", &test_core_path__10_fromurl},
+ {"11_walkup", &test_core_path__11_walkup}
+};
+static const struct clar_func _clar_cb_core_rmdir[] = {
+ {"delete_recursive", &test_core_rmdir__delete_recursive},
+ {"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir}
+};
+static const struct clar_func _clar_cb_core_string[] = {
+ {"0", &test_core_string__0},
+ {"1", &test_core_string__1}
+};
+static const struct clar_func _clar_cb_core_strtol[] = {
+ {"int32", &test_core_strtol__int32},
+ {"int64", &test_core_strtol__int64}
+};
+static const struct clar_func _clar_cb_core_vector[] = {
+ {"0", &test_core_vector__0},
+ {"1", &test_core_vector__1},
+ {"2", &test_core_vector__2},
+ {"3", &test_core_vector__3},
+ {"4", &test_core_vector__4},
+ {"5", &test_core_vector__5}
+};
+static const struct clar_func _clar_cb_index_read_tree[] = {
+ {"read_write_involution", &test_index_read_tree__read_write_involution}
+};
+static const struct clar_func _clar_cb_index_rename[] = {
+ {"single_file", &test_index_rename__single_file}
+};
+static const struct clar_func _clar_cb_network_createremotethenload[] = {
+ {"parsing", &test_network_createremotethenload__parsing}
+};
+static const struct clar_func _clar_cb_network_remotelocal[] = {
+ {"retrieve_advertised_references", &test_network_remotelocal__retrieve_advertised_references},
+ {"retrieve_advertised_references_from_spaced_repository", &test_network_remotelocal__retrieve_advertised_references_from_spaced_repository}
+};
+static const struct clar_func _clar_cb_network_remotes[] = {
+ {"fnmatch", &test_network_remotes__fnmatch},
+ {"parsing", &test_network_remotes__parsing},
+ {"refspec_parsing", &test_network_remotes__refspec_parsing},
+ {"transform", &test_network_remotes__transform}
+};
+static const struct clar_func _clar_cb_object_commit_commitstagedfile[] = {
+ {"generate_predictable_object_ids", &test_object_commit_commitstagedfile__generate_predictable_object_ids}
+};
+static const struct clar_func _clar_cb_object_raw_chars[] = {
+ {"build_valid_oid_from_raw_bytes", &test_object_raw_chars__build_valid_oid_from_raw_bytes},
+ {"find_invalid_chars_in_oid", &test_object_raw_chars__find_invalid_chars_in_oid}
+};
+static const struct clar_func _clar_cb_object_raw_compare[] = {
+ {"compare_allocfmt_oids", &test_object_raw_compare__compare_allocfmt_oids},
+ {"compare_fmt_oids", &test_object_raw_compare__compare_fmt_oids},
+ {"compare_pathfmt_oids", &test_object_raw_compare__compare_pathfmt_oids},
+ {"succeed_on_copy_oid", &test_object_raw_compare__succeed_on_copy_oid},
+ {"succeed_on_oid_comparison_equal", &test_object_raw_compare__succeed_on_oid_comparison_equal},
+ {"succeed_on_oid_comparison_greater", &test_object_raw_compare__succeed_on_oid_comparison_greater},
+ {"succeed_on_oid_comparison_lesser", &test_object_raw_compare__succeed_on_oid_comparison_lesser}
+};
+static const struct clar_func _clar_cb_object_raw_convert[] = {
+ {"succeed_on_oid_to_string_conversion", &test_object_raw_convert__succeed_on_oid_to_string_conversion},
+ {"succeed_on_oid_to_string_conversion_big", &test_object_raw_convert__succeed_on_oid_to_string_conversion_big}
+};
+static const struct clar_func _clar_cb_object_raw_fromstr[] = {
+ {"fail_on_invalid_oid_string", &test_object_raw_fromstr__fail_on_invalid_oid_string},
+ {"succeed_on_valid_oid_string", &test_object_raw_fromstr__succeed_on_valid_oid_string}
+};
+static const struct clar_func _clar_cb_object_raw_hash[] = {
+ {"hash_buffer_in_single_call", &test_object_raw_hash__hash_buffer_in_single_call},
+ {"hash_by_blocks", &test_object_raw_hash__hash_by_blocks},
+ {"hash_commit_object", &test_object_raw_hash__hash_commit_object},
+ {"hash_junk_data", &test_object_raw_hash__hash_junk_data},
+ {"hash_multi_byte_object", &test_object_raw_hash__hash_multi_byte_object},
+ {"hash_one_byte_object", &test_object_raw_hash__hash_one_byte_object},
+ {"hash_tag_object", &test_object_raw_hash__hash_tag_object},
+ {"hash_tree_object", &test_object_raw_hash__hash_tree_object},
+ {"hash_two_byte_object", &test_object_raw_hash__hash_two_byte_object},
+ {"hash_vector", &test_object_raw_hash__hash_vector},
+ {"hash_zero_length_object", &test_object_raw_hash__hash_zero_length_object}
+};
+static const struct clar_func _clar_cb_object_raw_short[] = {
+ {"oid_shortener_no_duplicates", &test_object_raw_short__oid_shortener_no_duplicates},
+ {"oid_shortener_stresstest_git_oid_shorten", &test_object_raw_short__oid_shortener_stresstest_git_oid_shorten}
+};
+static const struct clar_func _clar_cb_object_raw_size[] = {
+ {"validate_oid_size", &test_object_raw_size__validate_oid_size}
+};
+static const struct clar_func _clar_cb_object_raw_type2string[] = {
+ {"check_type_is_loose", &test_object_raw_type2string__check_type_is_loose},
+ {"convert_string_to_type", &test_object_raw_type2string__convert_string_to_type},
+ {"convert_type_to_string", &test_object_raw_type2string__convert_type_to_string}
+};
+static const struct clar_func _clar_cb_object_tree_diff[] = {
+ {"addition", &test_object_tree_diff__addition},
+ {"deletion", &test_object_tree_diff__deletion},
+ {"modification", &test_object_tree_diff__modification},
+ {"more", &test_object_tree_diff__more}
+};
+static const struct clar_func _clar_cb_object_tree_frompath[] = {
+ {"fail_when_processing_an_invalid_path", &test_object_tree_frompath__fail_when_processing_an_invalid_path},
+ {"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment},
+ {"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry}
+};
+static const struct clar_func _clar_cb_odb_loose[] = {
+ {"exists", &test_odb_loose__exists},
+ {"simple_reads", &test_odb_loose__simple_reads}
+};
+static const struct clar_func _clar_cb_odb_packed[] = {
+ {"mass_read", &test_odb_packed__mass_read},
+ {"read_header_0", &test_odb_packed__read_header_0},
+ {"read_header_1", &test_odb_packed__read_header_1}
+};
+static const struct clar_func _clar_cb_odb_sorting[] = {
+ {"alternate_backends_sorting", &test_odb_sorting__alternate_backends_sorting},
+ {"basic_backends_sorting", &test_odb_sorting__basic_backends_sorting}
+};
+static const struct clar_func _clar_cb_refs_crashes[] = {
+ {"double_free", &test_refs_crashes__double_free}
+};
+static const struct clar_func _clar_cb_repo_getters[] = {
+ {"empty", &test_repo_getters__empty},
+ {"head_detached", &test_repo_getters__head_detached},
+ {"head_orphan", &test_repo_getters__head_orphan}
+};
+static const struct clar_func _clar_cb_repo_init[] = {
+ {"bare_repo", &test_repo_init__bare_repo},
+ {"bare_repo_noslash", &test_repo_init__bare_repo_noslash},
+ {"standard_repo", &test_repo_init__standard_repo},
+ {"standard_repo_noslash", &test_repo_init__standard_repo_noslash}
+};
+static const struct clar_func _clar_cb_repo_open[] = {
+ {"bare_empty_repo", &test_repo_open__bare_empty_repo},
+ {"standard_empty_repo", &test_repo_open__standard_empty_repo}
+};
+static const struct clar_func _clar_cb_status_ignore[] = {
+ {"0", &test_status_ignore__0}
+};
+static const struct clar_func _clar_cb_status_single[] = {
+ {"hash_single_file", &test_status_single__hash_single_file}
+};
+static const struct clar_func _clar_cb_status_worktree[] = {
+ {"empty_repository", &test_status_worktree__empty_repository},
+ {"ignores", &test_status_worktree__ignores},
+ {"single_file", &test_status_worktree__single_file},
+ {"whole_repository", &test_status_worktree__whole_repository}
+};
+
+static const struct clar_suite _clar_suites[] = {
+ {
+ "attr::file",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_attr_file, 4
+ },
+ {
+ "attr::lookup",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_attr_lookup, 5
+ },
+ {
+ "attr::repo",
+ {"initialize", &test_attr_repo__initialize},
+ {"cleanup", &test_attr_repo__cleanup},
+ _clar_cb_attr_repo, 6
+ },
+ {
+ "buf::basic",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_buf_basic, 2
+ },
+ {
+ "config::add",
+ {"initialize", &test_config_add__initialize},
+ {"cleanup", &test_config_add__cleanup},
+ _clar_cb_config_add, 2
+ },
+ {
+ "config::new",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_config_new, 1
+ },
+ {
+ "config::read",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_config_read, 11
+ },
+ {
+ "config::stress",
+ {"initialize", &test_config_stress__initialize},
+ {"cleanup", &test_config_stress__cleanup},
+ _clar_cb_config_stress, 1
+ },
+ {
+ "config::write",
+ {"initialize", &test_config_write__initialize},
+ {"cleanup", &test_config_write__cleanup},
+ _clar_cb_config_write, 3
+ },
+ {
+ "core::buffer",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_buffer, 10
+ },
+ {
+ "core::dirent",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_dirent, 5
+ },
+ {
+ "core::filebuf",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_filebuf, 6
+ },
+ {
+ "core::hex",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_hex, 1
+ },
+ {
+ "core::oid",
+ {"initialize", &test_core_oid__initialize},
+ {NULL, NULL},
+ _clar_cb_core_oid, 1
+ },
+ {
+ "core::path",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_path, 10
+ },
+ {
+ "core::rmdir",
+ {"initialize", &test_core_rmdir__initialize},
+ {NULL, NULL},
+ _clar_cb_core_rmdir, 2
+ },
+ {
+ "core::string",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_string, 2
+ },
+ {
+ "core::strtol",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_strtol, 2
+ },
+ {
+ "core::vector",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_core_vector, 6
+ },
+ {
+ "index::read::tree",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_index_read_tree, 1
+ },
+ {
+ "index::rename",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_index_rename, 1
+ },
+ {
+ "network::createremotethenload",
+ {"initialize", &test_network_createremotethenload__initialize},
+ {"cleanup", &test_network_createremotethenload__cleanup},
+ _clar_cb_network_createremotethenload, 1
+ },
+ {
+ "network::remotelocal",
+ {"initialize", &test_network_remotelocal__initialize},
+ {"cleanup", &test_network_remotelocal__cleanup},
+ _clar_cb_network_remotelocal, 2
+ },
+ {
+ "network::remotes",
+ {"initialize", &test_network_remotes__initialize},
+ {"cleanup", &test_network_remotes__cleanup},
+ _clar_cb_network_remotes, 4
+ },
+ {
+ "object::commit::commitstagedfile",
+ {"initialize", &test_object_commit_commitstagedfile__initialize},
+ {"cleanup", &test_object_commit_commitstagedfile__cleanup},
+ _clar_cb_object_commit_commitstagedfile, 1
+ },
+ {
+ "object::raw::chars",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_chars, 2
+ },
+ {
+ "object::raw::compare",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_compare, 7
+ },
+ {
+ "object::raw::convert",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_convert, 2
+ },
+ {
+ "object::raw::fromstr",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_fromstr, 2
+ },
+ {
+ "object::raw::hash",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_hash, 11
+ },
+ {
+ "object::raw::short",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_short, 2
+ },
+ {
+ "object::raw::size",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_size, 1
+ },
+ {
+ "object::raw::type2string",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_object_raw_type2string, 3
+ },
+ {
+ "object::tree::diff",
+ {"initialize", &test_object_tree_diff__initialize},
+ {"cleanup", &test_object_tree_diff__cleanup},
+ _clar_cb_object_tree_diff, 4
+ },
+ {
+ "object::tree::frompath",
+ {"initialize", &test_object_tree_frompath__initialize},
+ {"cleanup", &test_object_tree_frompath__cleanup},
+ _clar_cb_object_tree_frompath, 3
+ },
+ {
+ "odb::loose",
+ {"initialize", &test_odb_loose__initialize},
+ {"cleanup", &test_odb_loose__cleanup},
+ _clar_cb_odb_loose, 2
+ },
+ {
+ "odb::packed",
+ {"initialize", &test_odb_packed__initialize},
+ {"cleanup", &test_odb_packed__cleanup},
+ _clar_cb_odb_packed, 3
+ },
+ {
+ "odb::sorting",
+ {"initialize", &test_odb_sorting__initialize},
+ {"cleanup", &test_odb_sorting__cleanup},
+ _clar_cb_odb_sorting, 2
+ },
+ {
+ "refs::crashes",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_refs_crashes, 1
+ },
+ {
+ "repo::getters",
+ {"initialize", &test_repo_getters__initialize},
+ {"cleanup", &test_repo_getters__cleanup},
+ _clar_cb_repo_getters, 3
+ },
+ {
+ "repo::init",
+ {"initialize", &test_repo_init__initialize},
+ {NULL, NULL},
+ _clar_cb_repo_init, 4
+ },
+ {
+ "repo::open",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_repo_open, 2
+ },
+ {
+ "status::ignore",
+ {"initialize", &test_status_ignore__initialize},
+ {"cleanup", &test_status_ignore__cleanup},
+ _clar_cb_status_ignore, 1
+ },
+ {
+ "status::single",
+ {NULL, NULL},
+ {NULL, NULL},
+ _clar_cb_status_single, 1
+ },
+ {
+ "status::worktree",
+ {"initialize", &test_status_worktree__initialize},
+ {"cleanup", &test_status_worktree__cleanup},
+ _clar_cb_status_worktree, 4
+ }
+};
+
+static size_t _clar_suite_count = 45;
+static size_t _clar_callback_count = 150;
+
+/* Core test functions */
+static void
+clar_run_test(
+ const struct clar_func *test,
+ const struct clar_func *initialize,
+ const struct clar_func *cleanup)
+{
+ int error_st = _clar.suite_errors;
+
+ clar_on_test();
+ _clar.trampoline_enabled = 1;
+
+ if (setjmp(_clar.trampoline) == 0) {
+ if (initialize->ptr != NULL)
+ initialize->ptr();
+
+ test->ptr();
+ }
+
+ _clar.trampoline_enabled = 0;
+
+ if (_clar.local_cleanup != NULL)
+ _clar.local_cleanup(_clar.local_cleanup_payload);
+
+ if (cleanup->ptr != NULL)
+ cleanup->ptr();
+
+ _clar.test_count++;
+
+ /* remove any local-set cleanup methods */
+ _clar.local_cleanup = NULL;
+ _clar.local_cleanup_payload = NULL;
+
+ clar_print_ontest(
+ test->name,
+ _clar.test_count,
+ (_clar.suite_errors > error_st)
+ );
+}
+
+static void
+clar_report_errors(void)
+{
+ int i = 1;
+ struct clar_error *error, *next;
+
+ error = _clar.errors;
+ while (error != NULL) {
+ next = error->next;
+ clar_print_error(i++, error);
+ free(error->description);
+ free(error);
+ error = next;
+ }
+
+ _clar.errors = _clar.last_error = NULL;
+}
+
+static void
+clar_run_suite(const struct clar_suite *suite)
+{
+ const struct clar_func *test = suite->tests;
+ size_t i;
+
+ clar_print_onsuite(suite->name);
+ clar_on_suite();
+
+ _clar.active_suite = suite->name;
+ _clar.suite_errors = 0;
+
+ for (i = 0; i < suite->test_count; ++i) {
+ _clar.active_test = test[i].name;
+ clar_run_test(&test[i], &suite->initialize, &suite->cleanup);
+ }
+}
+
+#if 0 /* temporarily disabled */
+static void
+clar_run_single(const struct clar_func *test,
+ const struct clar_suite *suite)
+{
+ _clar.suite_errors = 0;
+ _clar.active_suite = suite->name;
+ _clar.active_test = test->name;
+
+ clar_run_test(test, &suite->initialize, &suite->cleanup);
+}
+#endif
+
+static void
+clar_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
+clar_parse_args(int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; ++i) {
+ char *argument = argv[i];
+ char action;
+ int num;
+
+ if (argument[0] != '-')
+ clar_usage(argv[0]);
+
+ action = argument[1];
+ num = strtol(argument + 2, &argument, 10);
+
+ if (*argument != '\0' || num < 0)
+ clar_usage(argv[0]);
+
+ switch (action) {
+ case 's':
+ if ((size_t)num >= _clar_suite_count) {
+ clar_print_onabort("Suite number %d does not exist.\n", num);
+ exit(-1);
+ }
+
+ clar_run_suite(&_clar_suites[num]);
+ break;
+
+ default:
+ clar_usage(argv[0]);
+ }
+ }
+}
+
+static int
+clar_test(int argc, char **argv)
+{
+ clar_print_init(
+ (int)_clar_callback_count,
+ (int)_clar_suite_count,
+ ""
+ );
+
+ if (clar_sandbox() < 0) {
+ clar_print_onabort("Failed to sandbox the test runner.\n");
+ exit(-1);
+ }
+
+ clar_on_init();
+
+ if (argc > 1) {
+ clar_parse_args(argc, argv);
+ } else {
+ size_t i;
+ for (i = 0; i < _clar_suite_count; ++i)
+ clar_run_suite(&_clar_suites[i]);
+ }
+
+ clar_print_shutdown(
+ _clar.test_count,
+ (int)_clar_suite_count,
+ _clar.total_errors
+ );
+
+ clar_on_shutdown();
+
+ clar_unsandbox();
+ return _clar.total_errors;
+}
+
+void
+clar__assert(
+ int condition,
+ const char *file,
+ int line,
+ const char *error_msg,
+ const char *description,
+ int should_abort)
+{
+ struct clar_error *error;
+
+ if (condition)
+ return;
+
+ error = calloc(1, sizeof(struct clar_error));
+
+ if (_clar.errors == NULL)
+ _clar.errors = error;
+
+ if (_clar.last_error != NULL)
+ _clar.last_error->next = error;
+
+ _clar.last_error = error;
+
+ error->test = _clar.active_test;
+ error->test_number = _clar.test_count;
+ error->suite = _clar.active_suite;
+ error->file = file;
+ error->line_number = line;
+ error->error_msg = error_msg;
+
+ if (description != NULL)
+ error->description = strdup(description);
+
+ _clar.suite_errors++;
+ _clar.total_errors++;
+
+ if (should_abort) {
+ if (!_clar.trampoline_enabled) {
+ clar_print_onabort(
+ "Fatal error: a cleanup method raised an exception.");
+ exit(-1);
+ }
+
+ longjmp(_clar.trampoline, -1);
+ }
+}
+
+void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
+{
+ _clar.local_cleanup = cleanup;
+ _clar.local_cleanup_payload = opaque;
+}
+
+static char _clar_path[4096];
+
+static int
+is_valid_tmp_path(const char *path)
+{
+ STAT_T st;
+
+ if (stat(path, &st) != 0)
+ return 0;
+
+ if (!S_ISDIR(st.st_mode))
+ return 0;
+
+ return (access(path, W_OK) == 0);
+}
+
+static int
+find_tmp_path(char *buffer, size_t length)
+{
+#ifndef _WIN32
+ static const size_t var_count = 4;
+ static const char *env_vars[] = {
+ "TMPDIR", "TMP", "TEMP", "USERPROFILE"
+ };
+
+ size_t i;
+
+ 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 0;
+ }
+ }
+
+ /* If the environment doesn't say anything, try to use /tmp */
+ if (is_valid_tmp_path("/tmp")) {
+ strncpy(buffer, "/tmp", length);
+ return 0;
+ }
+
+#else
+ if (GetTempPath((DWORD)length, buffer))
+ return 0;
+#endif
+
+ /* This system doesn't like us, try to use the current directory */
+ if (is_valid_tmp_path(".")) {
+ strncpy(buffer, ".", length);
+ return 0;
+ }
+
+ return -1;
+}
+
+static void clar_unsandbox(void)
+{
+ if (_clar_path[0] == '\0')
+ return;
+
+#ifdef _WIN32
+ chdir("..");
+#endif
+
+ fs_rm(_clar_path);
+}
+
+static int build_sandbox_path(void)
+{
+ const char path_tail[] = "clar_tmp_XXXXXX";
+ size_t len;
+
+ if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0)
+ return -1;
+
+ len = strlen(_clar_path);
+
+#ifdef _WIN32
+ { /* normalize path to POSIX forward slashes */
+ size_t i;
+ for (i = 0; i < len; ++i) {
+ if (_clar_path[i] == '\\')
+ _clar_path[i] = '/';
+ }
+ }
+#endif
+
+ if (_clar_path[len - 1] != '/') {
+ _clar_path[len++] = '/';
+ }
+
+ strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len);
+
+#ifdef _WIN32
+ if (mktemp_s(_clar_path, sizeof(_clar_path)) != 0)
+ return -1;
+
+ if (mkdir(_clar_path, 0700) != 0)
+ return -1;
+#else
+ if (mkdtemp(_clar_path) == NULL)
+ return -1;
+#endif
+
+ return 0;
+}
+
+static int clar_sandbox(void)
+{
+ if (_clar_path[0] == '\0' && build_sandbox_path() < 0)
+ return -1;
+
+ if (chdir(_clar_path) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+static const char *
+fixture_path(const char *base, const char *fixture_name)
+{
+ static char _path[4096];
+ size_t root_len;
+
+ root_len = strlen(base);
+ strncpy(_path, base, sizeof(_path));
+
+ if (_path[root_len - 1] != '/')
+ _path[root_len++] = '/';
+
+ if (fixture_name[0] == '/')
+ fixture_name++;
+
+ strncpy(_path + root_len,
+ fixture_name,
+ sizeof(_path) - root_len);
+
+ return _path;
+}
+
+#ifdef CLAR_FIXTURE_PATH
+const char *cl_fixture(const char *fixture_name)
+{
+ return fixture_path(CLAR_FIXTURE_PATH, fixture_name);
+}
+
+void cl_fixture_sandbox(const char *fixture_name)
+{
+ fs_copy(cl_fixture(fixture_name), _clar_path);
+}
+
+void cl_fixture_cleanup(const char *fixture_name)
+{
+ fs_rm(fixture_path(_clar_path, fixture_name));
+}
+#endif
+
+#ifdef _WIN32
+
+#define FOF_FLAGS (FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR)
+
+static char *
+fileops_path(const char *_path)
+{
+ char *path = NULL;
+ size_t length, i;
+
+ if (_path == NULL)
+ return NULL;
+
+ length = strlen(_path);
+ path = malloc(length + 2);
+
+ if (path == NULL)
+ return NULL;
+
+ memcpy(path, _path, length);
+ path[length] = 0;
+ path[length + 1] = 0;
+
+ for (i = 0; i < length; ++i) {
+ if (path[i] == '/')
+ path[i] = '\\';
+ }
+
+ return path;
+}
+
+static void
+fileops(int mode, const char *_source, const char *_dest)
+{
+ SHFILEOPSTRUCT fops;
+
+ char *source = fileops_path(_source);
+ char *dest = fileops_path(_dest);
+
+ ZeroMemory(&fops, sizeof(SHFILEOPSTRUCT));
+
+ fops.wFunc = mode;
+ fops.pFrom = source;
+ fops.pTo = dest;
+ fops.fFlags = FOF_FLAGS;
+
+ cl_assert_(
+ SHFileOperation(&fops) == 0,
+ "Windows SHFileOperation failed"
+ );
+
+ free(source);
+ free(dest);
+}
+
+static void
+fs_rm(const char *_source)
+{
+ fileops(FO_DELETE, _source, NULL);
+}
+
+static void
+fs_copy(const char *_source, const char *_dest)
+{
+ fileops(FO_COPY, _source, _dest);
+}
+
+void
+cl_fs_cleanup(void)
+{
+ fs_rm(fixture_path(_clar_path, "*"));
+}
+
+#else
+static int
+shell_out(char * const argv[])
+{
+ int status;
+ pid_t pid;
+
+ pid = fork();
+
+ if (pid < 0) {
+ fprintf(stderr,
+ "System error: `fork()` call failed.\n");
+ exit(-1);
+ }
+
+ if (pid == 0) {
+ execv(argv[0], argv);
+ }
+
+ waitpid(pid, &status, 0);
+ return WEXITSTATUS(status);
+}
+
+static void
+fs_copy(const char *_source, const char *dest)
+{
+ char *argv[5];
+ char *source;
+ size_t source_len;
+
+ source = strdup(_source);
+ source_len = strlen(source);
+
+ if (source[source_len - 1] == '/')
+ source[source_len - 1] = 0;
+
+ argv[0] = "/bin/cp";
+ argv[1] = "-R";
+ argv[2] = source;
+ argv[3] = (char *)dest;
+ argv[4] = NULL;
+
+ cl_must_pass_(
+ shell_out(argv),
+ "Failed to copy test fixtures to sandbox"
+ );
+
+ free(source);
+}
+
+static void
+fs_rm(const char *source)
+{
+ char *argv[4];
+
+ argv[0] = "/bin/rm";
+ argv[1] = "-Rf";
+ argv[2] = (char *)source;
+ argv[3] = NULL;
+
+ cl_must_pass_(
+ shell_out(argv),
+ "Failed to cleanup the sandbox"
+ );
+}
+
+void
+cl_fs_cleanup(void)
+{
+ clar_unsandbox();
+ clar_sandbox();
+}
+#endif
+
+
+static void clar_print_init(int test_count, int suite_count, const char *suite_names)
+{
+ (void)test_count;
+ (void)suite_names;
+ (void)suite_count;
+ printf("TAP version 13\n");
+}
+
+static void clar_print_shutdown(int test_count, int suite_count, int error_count)
+{
+ (void)test_count;
+ (void)suite_count;
+ (void)error_count;
+
+ if (!error_count)
+ printf("# passed all %d test(s)\n", test_count);
+ else
+ printf("# failed %d among %d test(s)\n", error_count,
+ test_count);
+ printf("1..%d\n", test_count);
+}
+
+static void clar_print_error(int num, const struct clar_error *error)
+{
+ (void)num;
+
+ printf(" ---\n");
+ printf(" message : %s\n", error->error_msg);
+ printf(" severity: fail\n");
+ printf(" suite : %s\n", error->suite);
+ printf(" test : %s\n", error->test);
+ printf(" file : %s\n", error->file);
+ printf(" line : %d\n", error->line_number);
+
+ if (error->description != NULL)
+ printf(" description: %s\n", error->description);
+
+ printf(" ...\n");
+}
+
+static void clar_print_ontest(const char *test_name, int test_number, int failed)
+{
+ printf("%s %d - %s\n",
+ failed ? "not ok" : "ok",
+ test_number,
+ test_name
+ );
+
+ clar_report_errors();
+}
+
+static void clar_print_onsuite(const char *suite_name)
+{
+ printf("# *** %s ***\n", suite_name);
+}
+
+static void clar_print_onabort(const char *msg, ...)
+{
+ va_list argp;
+ va_start(argp, msg);
+ fprintf(stdout, "Bail out! ");
+ vfprintf(stdout, msg, argp);
+ va_end(argp);
+}
+
+
+int _MAIN_CC main(int argc, char *argv[])
+{
+ return clar_test(argc, argv);
+}