diff --git a/.gitignore b/.gitignore index 6594f1478..49d63e4b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/tests-clay/clay.h +/tests-clay/clay_main.c /apidocs /trash-*.exe /libgit2.pc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5505a96ca..764519350 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON) OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF) OPTION (BUILD_TESTS "Build Tests" ON) OPTION (BUILD_CLAY "Build Tests using the Clay suite" OFF) +OPTION (TAGS "Generate tags" OFF) # Platform specific compilation flags IF (MSVC) @@ -91,7 +92,7 @@ FILE(GLOB SRC_H include/git2/*.h) # On Windows use specific platform sources IF (WIN32 AND NOT CYGWIN) - ADD_DEFINITIONS(-DWIN32 -D_DEBUG) + ADD_DEFINITIONS(-DWIN32 -D_DEBUG) FILE(GLOB SRC src/*.c src/transports/*.c src/win32/*.c) ELSE() FILE(GLOB SRC src/*.c src/transports/*.c src/unix/*.c) @@ -113,9 +114,9 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libgit2.pc.in ${CMAKE_CURRENT_BINARY_ # Install INSTALL(TARGETS git2 - RUNTIME DESTINATION ${INSTALL_BIN} - LIBRARY DESTINATION ${INSTALL_LIB} - ARCHIVE DESTINATION ${INSTALL_LIB} + RUNTIME DESTINATION ${INSTALL_BIN} + LIBRARY DESTINATION ${INSTALL_LIB} + ARCHIVE DESTINATION ${INSTALL_LIB} ) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${INSTALL_LIB}/pkgconfig ) INSTALL(DIRECTORY include/git2 DESTINATION ${INSTALL_INC} ) @@ -126,7 +127,7 @@ IF (BUILD_TESTS) SET(TEST_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources" CACHE PATH "Path to test resources.") ADD_DEFINITIONS(-DTEST_RESOURCES=\"${TEST_RESOURCES}\") - INCLUDE_DIRECTORIES(tests) + INCLUDE_DIRECTORIES(tests) FILE(GLOB SRC_TEST tests/t??-*.c) ADD_EXECUTABLE(libgit2_test tests/test_main.c tests/test_lib.c tests/test_helpers.c ${SRC} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP}) @@ -142,13 +143,22 @@ IF (BUILD_TESTS) ENDIF () IF (BUILD_CLAY) + FIND_PACKAGE(PythonInterp REQUIRED) + SET(CLAY_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources/") + SET(CLAY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests-clay") ADD_DEFINITIONS(-DCLAY_FIXTURE_PATH=\"${CLAY_FIXTURES}\") - INCLUDE_DIRECTORIES(tests-clay) - FILE(GLOB_RECURSE SRC_TEST tests-clay/*.c) + INCLUDE_DIRECTORIES(${CLAY_PATH}) + FILE(GLOB_RECURSE SRC_TEST ${CLAY_PATH}/*/*.c ${CLAY_PATH}/clay_helpers.c ${CLAY_PATH}/testlib.c) - ADD_EXECUTABLE(libgit2_clay ${SRC} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP}) + ADD_CUSTOM_COMMAND( + OUTPUT ${CLAY_PATH}/clay_main.c ${CLAY_PATH}/clay.h + COMMAND ${PYTHON_EXECUTABLE} clay -vtap . + DEPENDS ${CLAY_PATH}/clay ${SRC_TEST} + WORKING_DIRECTORY ${CLAY_PATH} + ) + ADD_EXECUTABLE(libgit2_clay ${SRC} ${CLAY_PATH}/clay_main.c ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP}) TARGET_LINK_LIBRARIES(libgit2_clay ${CMAKE_THREAD_LIBS_INIT}) IF (WIN32) TARGET_LINK_LIBRARIES(libgit2_clay ws2_32) @@ -159,3 +169,22 @@ IF (BUILD_CLAY) ENABLE_TESTING() ADD_TEST(libgit2_clay libgit2_clay) ENDIF () + +IF (TAGS) + FIND_PROGRAM(CTAGS ctags) + IF (NOT CTAGS) + message(FATAL_ERROR "Could not find ctags command") + ENDIF () + + FILE(GLOB_RECURSE SRC_ALL *.[ch]) + + ADD_CUSTOM_COMMAND( + OUTPUT tags + COMMAND ${CTAGS} -a ${SRC_ALL} + DEPENDS ${SRC_ALL} + ) + ADD_CUSTOM_TARGET( + do_tags ALL + DEPENDS tags + ) +ENDIF () diff --git a/include/git2/index.h b/include/git2/index.h index 5e9c34d4b..627d6c4fd 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -301,6 +301,17 @@ GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_byindex(git_ */ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry); +/** + * Read a tree into the index file + * + * The current index contents will be replaced by the specified tree. + * + * @param index an existing index object + * @param tree tree to read + * @return GIT_SUCCESS or an error code + */ +GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree); + /** @} */ GIT_END_DECL #endif diff --git a/src/index.c b/src/index.c index 43e8efa57..9f9a08f0d 100644 --- a/src/index.c +++ b/src/index.c @@ -10,6 +10,7 @@ #include "common.h" #include "repository.h" #include "index.h" +#include "tree.h" #include "tree-cache.h" #include "hash.h" #include "git2/odb.h" @@ -936,3 +937,44 @@ int git_index_entry_stage(const git_index_entry *entry) { return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT; } + +static int read_tree_cb(const char *root, git_tree_entry *tentry, void *data) +{ + int ret = GIT_SUCCESS; + git_index *index = data; + git_index_entry *entry = NULL; + git_buf path = GIT_BUF_INIT; + + if (entry_is_tree(tentry)) + goto exit; + + ret = git_buf_joinpath(&path, root, tentry->filename); + if (ret < GIT_SUCCESS) + goto exit; + + entry = git__calloc(1, sizeof(git_index_entry)); + if (!entry) { + ret = GIT_ENOMEM; + goto exit; + } + + entry->mode = tentry->attr; + entry->oid = tentry->oid; + entry->path = git_buf_detach(&path); + + ret = index_insert(index, entry, 0); + +exit: + git_buf_free(&path); + + if (ret < GIT_SUCCESS) + index_entry_free(entry); + return ret; +} + +int git_index_read_tree(git_index *index, git_tree *tree) +{ + git_index_clear(index); + + return git_tree_walk(tree, read_tree_cb, GIT_TREEWALK_POST, index); +} diff --git a/src/repository.c b/src/repository.c index a94ecce55..a408599f7 100644 --- a/src/repository.c +++ b/src/repository.c @@ -349,9 +349,6 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) { assert(out && repo); - if (repo->is_bare) - return git__throw(GIT_EBAREINDEX, "Cannot open index in bare repository"); - if (repo->_index == NULL) { int error; git_buf index_path = GIT_BUF_INIT; diff --git a/src/tree.c b/src/tree.c index b698a8a24..8bc17d975 100644 --- a/src/tree.c +++ b/src/tree.c @@ -15,8 +15,6 @@ #define MAX_FILEMODE 0777777 #define MAX_FILEMODE_BYTES 6 -#define ENTRY_IS_TREE(e) ((e)->attr & 040000) - static int valid_attributes(const int attributes) { return attributes >= 0 && attributes <= MAX_FILEMODE; @@ -33,8 +31,8 @@ static int entry_sort_cmp(const void *a, const void *b) const git_tree_entry *entry_b = (const git_tree_entry *)(b); return git_futils_cmp_path( - entry_a->filename, entry_a->filename_len, ENTRY_IS_TREE(entry_a), - entry_b->filename, entry_b->filename_len, ENTRY_IS_TREE(entry_b)); + entry_a->filename, entry_a->filename_len, entry_is_tree(entry_a), + entry_b->filename, entry_b->filename_len, entry_is_tree(entry_b)); } @@ -717,7 +715,7 @@ static int tree_walk_post( if (callback(path->ptr, entry, payload) < 0) continue; - if (ENTRY_IS_TREE(entry)) { + if (entry_is_tree(entry)) { git_tree *subtree; size_t path_len = path->size; @@ -961,15 +959,22 @@ static int cmp_tentry_ientry(git_tree_entry *tentry, git_index_entry *ientry) return git_oid_cmp(&tentry->oid, &ientry->oid); } -static void make_tentry(git_tree_entry *tentry, git_index_entry *ientry, git_buf *buf) +static void make_tentry(git_tree_entry *tentry, git_index_entry *ientry) { + char *last_slash; + memset(tentry, 0x0, sizeof(git_tree_entry)); tentry->attr = ientry->mode; + + last_slash = strrchr(ientry->path, '/'); + if (last_slash) + last_slash++; + else + last_slash = ientry->path; + tentry->filename = last_slash; + git_oid_cpy(&tentry->oid, &ientry->oid); - if (buf != NULL) { - tentry->filename = buf->ptr; - tentry->filename_len = buf->size; - } + tentry->filename_len = strlen(tentry->filename); } static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) @@ -980,7 +985,7 @@ static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) git_buf fn_buf = GIT_BUF_INIT; int cmp, error = GIT_SUCCESS; - if (ENTRY_IS_TREE(tentry)) + if (entry_is_tree(tentry)) return GIT_SUCCESS; git_buf_puts(&fn_buf, root); @@ -993,25 +998,24 @@ static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) /* Like with 'git diff-index', the index is the right side*/ cmp = strcmp(git_buf_cstr(&fn_buf), ientry->path); + git_buf_free(&fn_buf); if (cmp == 0) { cbdata->i++; if (!cmp_tentry_ientry(tentry, ientry)) goto exit; /* modification */ - make_tentry(&fake_entry, ientry, &fn_buf); + make_tentry(&fake_entry, ientry); if ((error = signal_modification(tentry, &fake_entry, cbdata->cb, cbdata->data)) < 0) goto exit; } else if (cmp < 0) { /* deletion */ memcpy(&fake_entry, tentry, sizeof(git_tree_entry)); - fake_entry.filename = fn_buf.ptr; - fake_entry.filename_len = fn_buf.size; if ((error = signal_deletion(tentry, cbdata->cb, cbdata->data)) < 0) goto exit; } else { /* addition */ cbdata->i++; - make_tentry(&fake_entry, ientry, &fn_buf); + make_tentry(&fake_entry, ientry); if ((error = signal_addition(&fake_entry, cbdata->cb, cbdata->data)) < 0) goto exit; /* @@ -1024,7 +1028,6 @@ static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) } exit: - git_buf_free(&fn_buf); return error; } diff --git a/src/tree.h b/src/tree.h index 4f8c07f08..6b2a7d36d 100644 --- a/src/tree.h +++ b/src/tree.h @@ -31,6 +31,11 @@ struct git_treebuilder { }; +GIT_INLINE(unsigned int) entry_is_tree(const struct git_tree_entry *e) +{ + return e->attr & 040000; +} + void git_tree__free(git_tree *tree); int git_tree__parse(git_tree *tree, git_odb_object *obj); diff --git a/tests-clay/README.md b/tests-clay/README.md index 6b5a659f8..f7720610a 100644 --- a/tests-clay/README.md +++ b/tests-clay/README.md @@ -9,13 +9,9 @@ https://github.com/tanoku/clay * Write your modules and tests. Use good, meaningful names. -* Mix the tests: - - ./clay -vtap . - * Make sure you actually build the tests by setting: - BUILD_CLAY=ON + cmake -DBUILD_CLAY=ON build/ * Test: diff --git a/tests-clay/clay.h b/tests-clay/clay.h deleted file mode 100644 index 98c306215..000000000 --- a/tests-clay/clay.h +++ /dev/null @@ -1,234 +0,0 @@ -#ifndef __CLAY_TEST_H__ -#define __CLAY_TEST_H__ - -#include - -void clay__assert( - int condition, - const char *file, - int line, - const char *error, - const char *description, - int should_abort); - -void cl_set_cleanup(void (*cleanup)(void *), void *opaque); -void cl_fs_cleanup(void); - -#ifdef CLAY_FIXTURE_PATH -const char *cl_fixture(const char *fixture_name); -void cl_fixture_sandbox(const char *fixture_name); -void cl_fixture_cleanup(const char *fixture_name); -#endif - -/** - * Assertion macros with explicit error message - */ -#define cl_must_pass_(expr, desc) clay__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 1) -#define cl_must_fail_(expr, desc) clay__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 1) -#define cl_assert_(expr, desc) clay__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 1) - -/** - * Check macros with explicit error message - */ -#define cl_check_pass_(expr, desc) clay__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 0) -#define cl_check_fail_(expr, desc) clay__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 0) -#define cl_check_(expr, desc) clay__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 0) - -/** - * Assertion macros with no error message - */ -#define cl_must_pass(expr) cl_must_pass_(expr, NULL) -#define cl_must_fail(expr) cl_must_fail_(expr, NULL) -#define cl_assert(expr) cl_assert_(expr, NULL) - -/** - * Check macros with no error message - */ -#define cl_check_pass(expr) cl_check_pass_(expr, NULL) -#define cl_check_fail(expr) cl_check_fail_(expr, NULL) -#define cl_check(expr) cl_check_(expr, NULL) - -/** - * Forced failure/warning - */ -#define cl_fail(desc) clay__assert(0, __FILE__, __LINE__, "Test failed.", desc, 1) -#define cl_warning(desc) clay__assert(0, __FILE__, __LINE__, "Warning during test execution:", desc, 0) - -/** - * Test method declarations - */ -extern void clay_on_init(void); -extern void clay_on_shutdown(void); -extern void test_attr_file__assign_variants(void); -extern void test_attr_file__check_attr_examples(void); -extern void test_attr_file__match_variants(void); -extern void test_attr_file__simple_read(void); -extern void test_attr_lookup__assign_variants(void); -extern void test_attr_lookup__check_attr_examples(void); -extern void test_attr_lookup__from_buffer(void); -extern void test_attr_lookup__match_variants(void); -extern void test_attr_lookup__simple(void); -extern void test_attr_repo__bad_macros(void); -extern void test_attr_repo__cleanup(void); -extern void test_attr_repo__foreach(void); -extern void test_attr_repo__get_many(void); -extern void test_attr_repo__get_one(void); -extern void test_attr_repo__initialize(void); -extern void test_attr_repo__macros(void); -extern void test_attr_repo__manpage_example(void); -extern void test_buf_basic__printf(void); -extern void test_buf_basic__resize(void); -extern void test_config_add__cleanup(void); -extern void test_config_add__initialize(void); -extern void test_config_add__to_existing_section(void); -extern void test_config_add__to_new_section(void); -extern void test_config_new__write_new_config(void); -extern void test_config_read__blank_lines(void); -extern void test_config_read__case_sensitive(void); -extern void test_config_read__empty_files(void); -extern void test_config_read__header_in_last_line(void); -extern void test_config_read__invalid_ext_headers(void); -extern void test_config_read__lone_variable(void); -extern void test_config_read__multiline_value(void); -extern void test_config_read__number_suffixes(void); -extern void test_config_read__prefixes(void); -extern void test_config_read__simple_read(void); -extern void test_config_read__subsection_header(void); -extern void test_config_stress__cleanup(void); -extern void test_config_stress__dont_break_on_invalid_input(void); -extern void test_config_stress__initialize(void); -extern void test_config_write__cleanup(void); -extern void test_config_write__delete_inexistent(void); -extern void test_config_write__delete_value(void); -extern void test_config_write__initialize(void); -extern void test_config_write__replace_value(void); -extern void test_core_buffer__0(void); -extern void test_core_buffer__1(void); -extern void test_core_buffer__2(void); -extern void test_core_buffer__3(void); -extern void test_core_buffer__4(void); -extern void test_core_buffer__5(void); -extern void test_core_buffer__6(void); -extern void test_core_buffer__7(void); -extern void test_core_buffer__8(void); -extern void test_core_buffer__9(void); -extern void test_core_dirent__dont_traverse_dot(void); -extern void test_core_dirent__dont_traverse_empty_folders(void); -extern void test_core_dirent__traverse_slash_terminated_folder(void); -extern void test_core_dirent__traverse_subfolder(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_filebuf__3(void); -extern void test_core_filebuf__4(void); -extern void test_core_filebuf__5(void); -extern void test_core_oid__initialize(void); -extern void test_core_oid__streq(void); -extern void test_core_path__0_dirname(void); -extern void test_core_path__1_basename(void); -extern void test_core_path__2_topdir(void); -extern void test_core_path__5_joins(void); -extern void test_core_path__6_long_joins(void); -extern void test_core_path__7_path_to_dir(void); -extern void test_core_path__8_self_join(void); -extern void test_core_rmdir__delete_recursive(void); -extern void test_core_rmdir__fail_to_delete_non_empty_dir(void); -extern void test_core_rmdir__initialize(void); -extern void test_core_string__0(void); -extern void test_core_string__1(void); -extern void test_core_strtol__int32(void); -extern void test_core_strtol__int64(void); -extern void test_core_vector__0(void); -extern void test_core_vector__1(void); -extern void test_core_vector__2(void); -extern void test_core_vector__3(void); -extern void test_core_vector__4(void); -extern void test_core_vector__5(void); -extern void test_index_rename__single_file(void); -extern void test_network_remotelocal__cleanup(void); -extern void test_network_remotelocal__initialize(void); -extern void test_network_remotelocal__retrieve_advertised_references(void); -extern void test_network_remotes__cleanup(void); -extern void test_network_remotes__fnmatch(void); -extern void test_network_remotes__initialize(void); -extern void test_network_remotes__parsing(void); -extern void test_network_remotes__refspec_parsing(void); -extern void test_network_remotes__transform(void); -extern void test_object_commit_commitstagedfile__cleanup(void); -extern void test_object_commit_commitstagedfile__generate_predictable_object_ids(void); -extern void test_object_commit_commitstagedfile__initialize(void); -extern void test_object_raw_chars__build_valid_oid_from_raw_bytes(void); -extern void test_object_raw_chars__find_invalid_chars_in_oid(void); -extern void test_object_raw_compare__compare_allocfmt_oids(void); -extern void test_object_raw_compare__compare_fmt_oids(void); -extern void test_object_raw_compare__compare_pathfmt_oids(void); -extern void test_object_raw_compare__succeed_on_copy_oid(void); -extern void test_object_raw_compare__succeed_on_oid_comparison_equal(void); -extern void test_object_raw_compare__succeed_on_oid_comparison_greater(void); -extern void test_object_raw_compare__succeed_on_oid_comparison_lesser(void); -extern void test_object_raw_convert__succeed_on_oid_to_string_conversion(void); -extern void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void); -extern void test_object_raw_fromstr__fail_on_invalid_oid_string(void); -extern void test_object_raw_fromstr__succeed_on_valid_oid_string(void); -extern void test_object_raw_hash__hash_buffer_in_single_call(void); -extern void test_object_raw_hash__hash_by_blocks(void); -extern void test_object_raw_hash__hash_commit_object(void); -extern void test_object_raw_hash__hash_junk_data(void); -extern void test_object_raw_hash__hash_multi_byte_object(void); -extern void test_object_raw_hash__hash_one_byte_object(void); -extern void test_object_raw_hash__hash_tag_object(void); -extern void test_object_raw_hash__hash_tree_object(void); -extern void test_object_raw_hash__hash_two_byte_object(void); -extern void test_object_raw_hash__hash_vector(void); -extern void test_object_raw_hash__hash_zero_length_object(void); -extern void test_object_raw_short__oid_shortener_no_duplicates(void); -extern void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void); -extern void test_object_raw_size__validate_oid_size(void); -extern void test_object_raw_type2string__check_type_is_loose(void); -extern void test_object_raw_type2string__convert_string_to_type(void); -extern void test_object_raw_type2string__convert_type_to_string(void); -extern void test_object_tree_diff__addition(void); -extern void test_object_tree_diff__cleanup(void); -extern void test_object_tree_diff__deletion(void); -extern void test_object_tree_diff__initialize(void); -extern void test_object_tree_diff__modification(void); -extern void test_object_tree_diff__more(void); -extern void test_object_tree_frompath__cleanup(void); -extern void test_object_tree_frompath__fail_when_processing_an_invalid_path(void); -extern void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void); -extern void test_object_tree_frompath__initialize(void); -extern void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void); -extern void test_odb_loose__cleanup(void); -extern void test_odb_loose__exists(void); -extern void test_odb_loose__initialize(void); -extern void test_odb_loose__simple_reads(void); -extern void test_odb_packed__cleanup(void); -extern void test_odb_packed__initialize(void); -extern void test_odb_packed__mass_read(void); -extern void test_odb_packed__read_header_0(void); -extern void test_odb_packed__read_header_1(void); -extern void test_odb_sorting__alternate_backends_sorting(void); -extern void test_odb_sorting__basic_backends_sorting(void); -extern void test_odb_sorting__cleanup(void); -extern void test_odb_sorting__initialize(void); -extern void test_refs_crashes__double_free(void); -extern void test_repo_getters__cleanup(void); -extern void test_repo_getters__empty(void); -extern void test_repo_getters__head_detached(void); -extern void test_repo_getters__head_orphan(void); -extern void test_repo_getters__initialize(void); -extern void test_repo_init__bare_repo(void); -extern void test_repo_init__bare_repo_noslash(void); -extern void test_repo_init__initialize(void); -extern void test_repo_init__standard_repo(void); -extern void test_repo_init__standard_repo_noslash(void); -extern void test_repo_open__bare_empty_repo(void); -extern void test_repo_open__standard_empty_repo(void); -extern void test_status_single__hash_single_file(void); -extern void test_status_worktree__cleanup(void); -extern void test_status_worktree__empty_repository(void); -extern void test_status_worktree__initialize(void); -extern void test_status_worktree__whole_repository(void); - -#endif diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c deleted file mode 100644 index d9ef970c5..000000000 --- a/tests-clay/clay_main.c +++ /dev/null @@ -1,1188 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -/* required for sandboxing */ -#include -#include - -#ifdef _WIN32 -# include -# include -# include -# include - -# 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 /* waitpid(2) */ -# include -# define _MAIN_CC - typedef struct stat STAT_T; -#endif - -#include "clay.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 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); -}; - -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_print_*.c */ -static void clay_print_init(int test_count, int suite_count, const char *suite_names); -static void clay_print_shutdown(int test_count, int suite_count, int error_count); -static void clay_print_error(int num, const struct clay_error *error); -static void clay_print_ontest(const char *test_name, int test_number, int failed); -static void clay_print_onsuite(const char *suite_name); -static void clay_print_onabort(const char *msg, ...); - -/* From clay_sandbox.c */ -static void clay_unsandbox(void); -static int clay_sandbox(void); - -/* Event callback overrides */ -#define clay_on_test() /* nop */ -#define clay_on_suite() /* nop */ - -/* Autogenerated test data by clay */ -static const struct clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_cb_buf_basic[] = { - {"printf", &test_buf_basic__printf}, - {"resize", &test_buf_basic__resize} -}; -static const struct clay_func _clay_cb_config_add[] = { - {"to_existing_section", &test_config_add__to_existing_section}, - {"to_new_section", &test_config_add__to_new_section} -}; -static const struct clay_func _clay_cb_config_new[] = { - {"write_new_config", &test_config_new__write_new_config} -}; -static const struct clay_func _clay_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 clay_func _clay_cb_config_stress[] = { - {"dont_break_on_invalid_input", &test_config_stress__dont_break_on_invalid_input} -}; -static const struct clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_cb_core_oid[] = { - {"streq", &test_core_oid__streq} -}; -static const struct clay_func _clay_cb_core_path[] = { - {"0_dirname", &test_core_path__0_dirname}, - {"1_basename", &test_core_path__1_basename}, - {"2_topdir", &test_core_path__2_topdir}, - {"5_joins", &test_core_path__5_joins}, - {"6_long_joins", &test_core_path__6_long_joins}, - {"7_path_to_dir", &test_core_path__7_path_to_dir}, - {"8_self_join", &test_core_path__8_self_join} -}; -static const struct clay_func _clay_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 clay_func _clay_cb_core_string[] = { - {"0", &test_core_string__0}, - {"1", &test_core_string__1} -}; -static const struct clay_func _clay_cb_core_strtol[] = { - {"int32", &test_core_strtol__int32}, - {"int64", &test_core_strtol__int64} -}; -static const struct clay_func _clay_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 clay_func _clay_cb_index_rename[] = { - {"single_file", &test_index_rename__single_file} -}; -static const struct clay_func _clay_cb_network_remotelocal[] = { - {"retrieve_advertised_references", &test_network_remotelocal__retrieve_advertised_references} -}; -static const struct clay_func _clay_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 clay_func _clay_cb_object_commit_commitstagedfile[] = { - {"generate_predictable_object_ids", &test_object_commit_commitstagedfile__generate_predictable_object_ids} -}; -static const struct clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_cb_object_raw_size[] = { - {"validate_oid_size", &test_object_raw_size__validate_oid_size} -}; -static const struct clay_func _clay_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 clay_func _clay_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 clay_func _clay_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 clay_func _clay_cb_odb_loose[] = { - {"exists", &test_odb_loose__exists}, - {"simple_reads", &test_odb_loose__simple_reads} -}; -static const struct clay_func _clay_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 clay_func _clay_cb_odb_sorting[] = { - {"alternate_backends_sorting", &test_odb_sorting__alternate_backends_sorting}, - {"basic_backends_sorting", &test_odb_sorting__basic_backends_sorting} -}; -static const struct clay_func _clay_cb_refs_crashes[] = { - {"double_free", &test_refs_crashes__double_free} -}; -static const struct clay_func _clay_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 clay_func _clay_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 clay_func _clay_cb_repo_open[] = { - {"bare_empty_repo", &test_repo_open__bare_empty_repo}, - {"standard_empty_repo", &test_repo_open__standard_empty_repo} -}; -static const struct clay_func _clay_cb_status_single[] = { - {"hash_single_file", &test_status_single__hash_single_file} -}; -static const struct clay_func _clay_cb_status_worktree[] = { - {"empty_repository", &test_status_worktree__empty_repository}, - {"whole_repository", &test_status_worktree__whole_repository} -}; - -static const struct clay_suite _clay_suites[] = { - { - "attr::file", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_attr_file, 4 - }, - { - "attr::lookup", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_attr_lookup, 5 - }, - { - "attr::repo", - {"initialize", &test_attr_repo__initialize}, - {"cleanup", &test_attr_repo__cleanup}, - _clay_cb_attr_repo, 6 - }, - { - "buf::basic", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_buf_basic, 2 - }, - { - "config::add", - {"initialize", &test_config_add__initialize}, - {"cleanup", &test_config_add__cleanup}, - _clay_cb_config_add, 2 - }, - { - "config::new", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_config_new, 1 - }, - { - "config::read", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_config_read, 11 - }, - { - "config::stress", - {"initialize", &test_config_stress__initialize}, - {"cleanup", &test_config_stress__cleanup}, - _clay_cb_config_stress, 1 - }, - { - "config::write", - {"initialize", &test_config_write__initialize}, - {"cleanup", &test_config_write__cleanup}, - _clay_cb_config_write, 3 - }, - { - "core::buffer", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_core_buffer, 10 - }, - { - "core::dirent", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_core_dirent, 5 - }, - { - "core::filebuf", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_core_filebuf, 6 - }, - { - "core::oid", - {"initialize", &test_core_oid__initialize}, - {NULL, NULL}, - _clay_cb_core_oid, 1 - }, - { - "core::path", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_core_path, 7 - }, - { - "core::rmdir", - {"initialize", &test_core_rmdir__initialize}, - {NULL, NULL}, - _clay_cb_core_rmdir, 2 - }, - { - "core::string", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_core_string, 2 - }, - { - "core::strtol", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_core_strtol, 2 - }, - { - "core::vector", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_core_vector, 6 - }, - { - "index::rename", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_index_rename, 1 - }, - { - "network::remotelocal", - {"initialize", &test_network_remotelocal__initialize}, - {"cleanup", &test_network_remotelocal__cleanup}, - _clay_cb_network_remotelocal, 1 - }, - { - "network::remotes", - {"initialize", &test_network_remotes__initialize}, - {"cleanup", &test_network_remotes__cleanup}, - _clay_cb_network_remotes, 4 - }, - { - "object::commit::commitstagedfile", - {"initialize", &test_object_commit_commitstagedfile__initialize}, - {"cleanup", &test_object_commit_commitstagedfile__cleanup}, - _clay_cb_object_commit_commitstagedfile, 1 - }, - { - "object::raw::chars", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_chars, 2 - }, - { - "object::raw::compare", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_compare, 7 - }, - { - "object::raw::convert", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_convert, 2 - }, - { - "object::raw::fromstr", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_fromstr, 2 - }, - { - "object::raw::hash", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_hash, 11 - }, - { - "object::raw::short", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_short, 2 - }, - { - "object::raw::size", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_size, 1 - }, - { - "object::raw::type2string", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_object_raw_type2string, 3 - }, - { - "object::tree::diff", - {"initialize", &test_object_tree_diff__initialize}, - {"cleanup", &test_object_tree_diff__cleanup}, - _clay_cb_object_tree_diff, 4 - }, - { - "object::tree::frompath", - {"initialize", &test_object_tree_frompath__initialize}, - {"cleanup", &test_object_tree_frompath__cleanup}, - _clay_cb_object_tree_frompath, 3 - }, - { - "odb::loose", - {"initialize", &test_odb_loose__initialize}, - {"cleanup", &test_odb_loose__cleanup}, - _clay_cb_odb_loose, 2 - }, - { - "odb::packed", - {"initialize", &test_odb_packed__initialize}, - {"cleanup", &test_odb_packed__cleanup}, - _clay_cb_odb_packed, 3 - }, - { - "odb::sorting", - {"initialize", &test_odb_sorting__initialize}, - {"cleanup", &test_odb_sorting__cleanup}, - _clay_cb_odb_sorting, 2 - }, - { - "refs::crashes", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_refs_crashes, 1 - }, - { - "repo::getters", - {"initialize", &test_repo_getters__initialize}, - {"cleanup", &test_repo_getters__cleanup}, - _clay_cb_repo_getters, 3 - }, - { - "repo::init", - {"initialize", &test_repo_init__initialize}, - {NULL, NULL}, - _clay_cb_repo_init, 4 - }, - { - "repo::open", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_repo_open, 2 - }, - { - "status::single", - {NULL, NULL}, - {NULL, NULL}, - _clay_cb_status_single, 1 - }, - { - "status::worktree", - {"initialize", &test_status_worktree__initialize}, - {"cleanup", &test_status_worktree__cleanup}, - _clay_cb_status_worktree, 2 - } -}; - -static size_t _clay_suite_count = 41; -static size_t _clay_callback_count = 140; - -/* Core test functions */ -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_on_test(); - _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_ontest( - test->name, - _clay.test_count, - (_clay.suite_errors > error_st) - ); -} - -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; - } - - _clay.errors = _clay.last_error = NULL; -} - -static void -clay_run_suite(const struct clay_suite *suite) -{ - const struct clay_func *test = suite->tests; - size_t i; - - clay_print_onsuite(suite->name); - clay_on_suite(); - - _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); - } -} - -#if 0 /* temporarily disabled */ -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); -} -#endif - -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) -{ - 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 's': - if ((size_t)num >= _clay_suite_count) { - clay_print_onabort("Suite number %d does not exist.\n", num); - exit(-1); - } - - clay_run_suite(&_clay_suites[num]); - break; - - default: - clay_usage(argv[0]); - } - } -} - -static int -clay_test(int argc, char **argv) -{ - clay_print_init( - (int)_clay_callback_count, - (int)_clay_suite_count, - "" - ); - - if (clay_sandbox() < 0) { - clay_print_onabort("Failed to sandbox the test runner.\n"); - exit(-1); - } - - clay_on_init(); - - if (argc > 1) { - clay_parse_args(argc, argv); - } else { - size_t i; - for (i = 0; i < _clay_suite_count; ++i) - clay_run_suite(&_clay_suites[i]); - } - - clay_print_shutdown( - _clay.test_count, - (int)_clay_suite_count, - _clay.total_errors - ); - - clay_on_shutdown(); - - 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) { - clay_print_onabort( - "Fatal error: 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; -} - -static char _clay_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 clay_unsandbox(void) -{ - if (_clay_path[0] == '\0') - return; - -#ifdef _WIN32 - chdir(".."); -#endif - - fs_rm(_clay_path); -} - -static int build_sandbox_path(void) -{ - const char path_tail[] = "clay_tmp_XXXXXX"; - size_t len; - - if (find_tmp_path(_clay_path, sizeof(_clay_path)) < 0) - return -1; - - len = strlen(_clay_path); - -#ifdef _WIN32 - { /* normalize path to POSIX forward slashes */ - size_t i; - for (i = 0; i < len; ++i) { - if (_clay_path[i] == '\\') - _clay_path[i] = '/'; - } - } -#endif - - if (_clay_path[len - 1] != '/') { - _clay_path[len++] = '/'; - } - - strncpy(_clay_path + len, path_tail, sizeof(_clay_path) - len); - -#ifdef _WIN32 - if (mktemp_s(_clay_path, sizeof(_clay_path)) != 0) - return -1; - - if (mkdir(_clay_path, 0700) != 0) - return -1; -#else - if (mkdtemp(_clay_path) == NULL) - return -1; -#endif - - return 0; -} - -static int clay_sandbox(void) -{ - if (_clay_path[0] == '\0' && build_sandbox_path() < 0) - return -1; - - if (chdir(_clay_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 CLAY_FIXTURE_PATH -const char *cl_fixture(const char *fixture_name) -{ - return fixture_path(CLAY_FIXTURE_PATH, fixture_name); -} - -void cl_fixture_sandbox(const char *fixture_name) -{ - fs_copy(cl_fixture(fixture_name), _clay_path); -} - -void cl_fixture_cleanup(const char *fixture_name) -{ - fs_rm(fixture_path(_clay_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(_clay_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) -{ - clay_unsandbox(); - clay_sandbox(); -} -#endif - - -static void clay_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 clay_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 clay_print_error(int num, const struct clay_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 clay_print_ontest(const char *test_name, int test_number, int failed) -{ - printf("%s %d - %s\n", - failed ? "not ok" : "ok", - test_number, - test_name - ); - - clay_report_errors(); -} - -static void clay_print_onsuite(const char *suite_name) -{ - printf("# *** %s ***\n", suite_name); -} - -static void clay_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 clay_test(argc, argv); -} diff --git a/tests-clay/index/read_tree.c b/tests-clay/index/read_tree.c new file mode 100644 index 000000000..d884c8d51 --- /dev/null +++ b/tests-clay/index/read_tree.c @@ -0,0 +1,46 @@ +#include "clay_libgit2.h" +#include "testlib.h" +#include "posix.h" + +/* Test that reading and writing a tree is a no-op */ +void test_index_read_tree__read_write_involution(void) +{ + git_repository *repo; + git_index *index; + git_oid tree_oid; + git_tree *tree; + git_oid expected; + + p_mkdir("read_tree", 0700); + + cl_git_pass(git_repository_init(&repo, "./read_tree", 0)); + cl_git_pass(git_repository_index(&index, repo)); + + cl_assert(git_index_entrycount(index) == 0); + + p_mkdir("./read_tree/abc", 0700); + + /* Sort order: '-' < '/' < '_' */ + file_create("./read_tree/abc-d", NULL); + file_create("./read_tree/abc/d", NULL); + file_create("./read_tree/abc_d", NULL); + + cl_git_pass(git_index_add(index, "abc-d", 0)); + cl_git_pass(git_index_add(index, "abc_d", 0)); + cl_git_pass(git_index_add(index, "abc/d", 0)); + + /* write-tree */ + cl_git_pass(git_tree_create_fromindex(&expected, index)); + + /* read-tree */ + git_tree_lookup(&tree, repo, &expected); + cl_git_pass(git_index_read_tree(index, tree)); + + cl_git_pass(git_tree_create_fromindex(&tree_oid, index)); + cl_assert(git_oid_cmp(&expected, &tree_oid) == 0); + + git_index_free(index); + git_repository_free(repo); + + cl_fixture_cleanup("read_tree"); +} diff --git a/tests-clay/index/rename.c b/tests-clay/index/rename.c index f81125434..c949fa7f2 100644 --- a/tests-clay/index/rename.c +++ b/tests-clay/index/rename.c @@ -1,16 +1,7 @@ #include "clay_libgit2.h" +#include "testlib.h" #include "posix.h" -static void file_create(const char *filename, const char *content) -{ - int fd; - - fd = p_creat(filename, 0666); - cl_assert(fd != 0); - cl_git_pass(p_write(fd, content, strlen(content))); - cl_git_pass(p_close(fd)); -} - void test_index_rename__single_file(void) { git_repository *repo; diff --git a/tests-clay/object/tree/diff.c b/tests-clay/object/tree/diff.c index 471e46544..b2c7f6913 100644 --- a/tests-clay/object/tree/diff.c +++ b/tests-clay/object/tree/diff.c @@ -2,8 +2,8 @@ #include "tree.h" #include "repository.h" -static unsigned int expect_idx; static git_repository *repo; +static git_index *theindex; static git_tree *atree, *btree; static git_oid aoid, boid; @@ -27,9 +27,18 @@ static int diff_cb(const git_tree_diff_data *diff, void *data) return GIT_SUCCESS; } +static void test_diff(git_tree *a, git_tree *b, git_tree_diff_cb cb, void *data) +{ + cl_must_pass(git_tree_diff(a, b, cb, data)); + + cl_git_pass(git_index_read_tree(theindex, b)); + cl_git_pass(git_tree_diff_index_recursive(a, theindex, cb, data)); +} + void test_object_tree_diff__initialize(void) { cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_index(&theindex, repo)); } void test_object_tree_diff__cleanup(void) @@ -58,7 +67,7 @@ void test_object_tree_diff__addition(void) cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - cl_must_pass(git_tree_diff(atree, btree, diff_cb, &expect)); + test_diff(atree, btree, diff_cb, &expect); } void test_object_tree_diff__deletion(void) @@ -79,7 +88,7 @@ void test_object_tree_diff__deletion(void) cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - cl_must_pass(git_tree_diff(atree, btree, diff_cb, &expect)); + test_diff(atree, btree, diff_cb, &expect); } void test_object_tree_diff__modification(void) @@ -101,13 +110,20 @@ void test_object_tree_diff__modification(void) cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - cl_must_pass(git_tree_diff(atree, btree, diff_cb, &expect)); + test_diff(atree, btree, diff_cb, &expect); } +struct diff_more_data { + git_tree_diff_data expect[3]; + int expect_idx; +}; + static int diff_more_cb(const git_tree_diff_data *diff, void *data) { - git_tree_diff_data *expect = (git_tree_diff_data *) data; - diff_cmp(diff, &expect[expect_idx++]); + struct diff_more_data *more_data = data; + diff_cmp(diff, &more_data->expect[more_data->expect_idx]); + + more_data->expect_idx = (more_data->expect_idx + 1) % ARRAY_SIZE(more_data->expect); return GIT_SUCCESS; } @@ -116,9 +132,10 @@ void test_object_tree_diff__more(void) { char *astr = "814889a078c031f61ed08ab5fa863aea9314344d"; char *bstr = "75057dd4114e74cca1d750d0aee1647c903cb60a"; - git_tree_diff_data expect[3]; + struct diff_more_data more_data; + git_tree_diff_data *expect = more_data.expect; - memset(expect, 0x0, 3 * sizeof(git_tree_diff_data)); + memset(&more_data, 0x0, sizeof(struct diff_more_data)); /* M README */ expect[0].old_attr = 0100644; expect[0].new_attr = 0100644; @@ -146,5 +163,5 @@ void test_object_tree_diff__more(void) cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - cl_must_pass(git_tree_diff(atree, btree, diff_more_cb, expect)); + test_diff(atree, btree, diff_more_cb, &more_data); } diff --git a/tests-clay/testlib.c b/tests-clay/testlib.c new file mode 100644 index 000000000..d45fc2c26 --- /dev/null +++ b/tests-clay/testlib.c @@ -0,0 +1,20 @@ +#include "clay.h" +#include "testlib.h" +#include "posix.h" + +void file_create(const char *filename, const char *content) +{ + int fd; + + fd = p_creat(filename, 0666); + cl_assert(fd != 0); + + if (content) { + cl_must_pass(p_write(fd, content, strlen(content))); + } else { + cl_must_pass(p_write(fd, filename, strlen(filename))); + cl_must_pass(p_write(fd, "\n", 1)); + } + + cl_must_pass(p_close(fd)); +} diff --git a/tests-clay/testlib.h b/tests-clay/testlib.h new file mode 100644 index 000000000..2e8867c12 --- /dev/null +++ b/tests-clay/testlib.h @@ -0,0 +1,6 @@ +#ifndef INCLUDE_testlib_h__ +#define INCLUDE_testlib_h__ + +void file_create(const char *filename, const char *content); + +#endif