Commit 7a704309 by Vicent Martí

Merge remote-tracking branch 'drizzd/diff-index-tests' into development

Conflicts:
	tests-clay/clay.h
	tests-clay/clay_main.c
parents 9191a6d2 0fb3fba1
/tests-clay/clay.h
/tests-clay/clay_main.c
/apidocs /apidocs
/trash-*.exe /trash-*.exe
/libgit2.pc /libgit2.pc
......
...@@ -49,6 +49,7 @@ OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON) ...@@ -49,6 +49,7 @@ OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON)
OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF) OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF)
OPTION (BUILD_TESTS "Build Tests" ON) OPTION (BUILD_TESTS "Build Tests" ON)
OPTION (BUILD_CLAY "Build Tests using the Clay suite" OFF) OPTION (BUILD_CLAY "Build Tests using the Clay suite" OFF)
OPTION (TAGS "Generate tags" OFF)
# Platform specific compilation flags # Platform specific compilation flags
IF (MSVC) IF (MSVC)
...@@ -91,7 +92,7 @@ FILE(GLOB SRC_H include/git2/*.h) ...@@ -91,7 +92,7 @@ FILE(GLOB SRC_H include/git2/*.h)
# On Windows use specific platform sources # On Windows use specific platform sources
IF (WIN32 AND NOT CYGWIN) 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) FILE(GLOB SRC src/*.c src/transports/*.c src/win32/*.c)
ELSE() ELSE()
FILE(GLOB SRC src/*.c src/transports/*.c src/unix/*.c) 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_ ...@@ -113,9 +114,9 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libgit2.pc.in ${CMAKE_CURRENT_BINARY_
# Install # Install
INSTALL(TARGETS git2 INSTALL(TARGETS git2
RUNTIME DESTINATION ${INSTALL_BIN} RUNTIME DESTINATION ${INSTALL_BIN}
LIBRARY DESTINATION ${INSTALL_LIB} LIBRARY DESTINATION ${INSTALL_LIB}
ARCHIVE DESTINATION ${INSTALL_LIB} ARCHIVE DESTINATION ${INSTALL_LIB}
) )
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${INSTALL_LIB}/pkgconfig ) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${INSTALL_LIB}/pkgconfig )
INSTALL(DIRECTORY include/git2 DESTINATION ${INSTALL_INC} ) INSTALL(DIRECTORY include/git2 DESTINATION ${INSTALL_INC} )
...@@ -126,7 +127,7 @@ IF (BUILD_TESTS) ...@@ -126,7 +127,7 @@ IF (BUILD_TESTS)
SET(TEST_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources" CACHE PATH "Path to test resources.") SET(TEST_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources" CACHE PATH "Path to test resources.")
ADD_DEFINITIONS(-DTEST_RESOURCES=\"${TEST_RESOURCES}\") ADD_DEFINITIONS(-DTEST_RESOURCES=\"${TEST_RESOURCES}\")
INCLUDE_DIRECTORIES(tests) INCLUDE_DIRECTORIES(tests)
FILE(GLOB SRC_TEST tests/t??-*.c) 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}) 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) ...@@ -142,13 +143,22 @@ IF (BUILD_TESTS)
ENDIF () ENDIF ()
IF (BUILD_CLAY) IF (BUILD_CLAY)
FIND_PACKAGE(PythonInterp REQUIRED)
SET(CLAY_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources/") 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}\") ADD_DEFINITIONS(-DCLAY_FIXTURE_PATH=\"${CLAY_FIXTURES}\")
INCLUDE_DIRECTORIES(tests-clay) INCLUDE_DIRECTORIES(${CLAY_PATH})
FILE(GLOB_RECURSE SRC_TEST tests-clay/*.c) 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}) TARGET_LINK_LIBRARIES(libgit2_clay ${CMAKE_THREAD_LIBS_INIT})
IF (WIN32) IF (WIN32)
TARGET_LINK_LIBRARIES(libgit2_clay ws2_32) TARGET_LINK_LIBRARIES(libgit2_clay ws2_32)
...@@ -159,3 +169,22 @@ IF (BUILD_CLAY) ...@@ -159,3 +169,22 @@ IF (BUILD_CLAY)
ENABLE_TESTING() ENABLE_TESTING()
ADD_TEST(libgit2_clay libgit2_clay) ADD_TEST(libgit2_clay libgit2_clay)
ENDIF () 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 ()
...@@ -301,6 +301,17 @@ GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_byindex(git_ ...@@ -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); 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 GIT_END_DECL
#endif #endif
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "common.h" #include "common.h"
#include "repository.h" #include "repository.h"
#include "index.h" #include "index.h"
#include "tree.h"
#include "tree-cache.h" #include "tree-cache.h"
#include "hash.h" #include "hash.h"
#include "git2/odb.h" #include "git2/odb.h"
...@@ -936,3 +937,44 @@ int git_index_entry_stage(const git_index_entry *entry) ...@@ -936,3 +937,44 @@ int git_index_entry_stage(const git_index_entry *entry)
{ {
return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT; 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);
}
...@@ -349,9 +349,6 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo) ...@@ -349,9 +349,6 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo)
{ {
assert(out && repo); assert(out && repo);
if (repo->is_bare)
return git__throw(GIT_EBAREINDEX, "Cannot open index in bare repository");
if (repo->_index == NULL) { if (repo->_index == NULL) {
int error; int error;
git_buf index_path = GIT_BUF_INIT; git_buf index_path = GIT_BUF_INIT;
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
#define MAX_FILEMODE 0777777 #define MAX_FILEMODE 0777777
#define MAX_FILEMODE_BYTES 6 #define MAX_FILEMODE_BYTES 6
#define ENTRY_IS_TREE(e) ((e)->attr & 040000)
static int valid_attributes(const int attributes) static int valid_attributes(const int attributes)
{ {
return attributes >= 0 && attributes <= MAX_FILEMODE; return attributes >= 0 && attributes <= MAX_FILEMODE;
...@@ -33,8 +31,8 @@ static int entry_sort_cmp(const void *a, const void *b) ...@@ -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); const git_tree_entry *entry_b = (const git_tree_entry *)(b);
return git_futils_cmp_path( return git_futils_cmp_path(
entry_a->filename, entry_a->filename_len, ENTRY_IS_TREE(entry_a), 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_b->filename, entry_b->filename_len, entry_is_tree(entry_b));
} }
...@@ -717,7 +715,7 @@ static int tree_walk_post( ...@@ -717,7 +715,7 @@ static int tree_walk_post(
if (callback(path->ptr, entry, payload) < 0) if (callback(path->ptr, entry, payload) < 0)
continue; continue;
if (ENTRY_IS_TREE(entry)) { if (entry_is_tree(entry)) {
git_tree *subtree; git_tree *subtree;
size_t path_len = path->size; size_t path_len = path->size;
...@@ -961,15 +959,22 @@ static int cmp_tentry_ientry(git_tree_entry *tentry, git_index_entry *ientry) ...@@ -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); 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)); memset(tentry, 0x0, sizeof(git_tree_entry));
tentry->attr = ientry->mode; 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); git_oid_cpy(&tentry->oid, &ientry->oid);
if (buf != NULL) { tentry->filename_len = strlen(tentry->filename);
tentry->filename = buf->ptr;
tentry->filename_len = buf->size;
}
} }
static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) 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) ...@@ -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; git_buf fn_buf = GIT_BUF_INIT;
int cmp, error = GIT_SUCCESS; int cmp, error = GIT_SUCCESS;
if (ENTRY_IS_TREE(tentry)) if (entry_is_tree(tentry))
return GIT_SUCCESS; return GIT_SUCCESS;
git_buf_puts(&fn_buf, root); git_buf_puts(&fn_buf, root);
...@@ -993,25 +998,24 @@ static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) ...@@ -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*/ /* Like with 'git diff-index', the index is the right side*/
cmp = strcmp(git_buf_cstr(&fn_buf), ientry->path); cmp = strcmp(git_buf_cstr(&fn_buf), ientry->path);
git_buf_free(&fn_buf);
if (cmp == 0) { if (cmp == 0) {
cbdata->i++; cbdata->i++;
if (!cmp_tentry_ientry(tentry, ientry)) if (!cmp_tentry_ientry(tentry, ientry))
goto exit; goto exit;
/* modification */ /* 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) if ((error = signal_modification(tentry, &fake_entry, cbdata->cb, cbdata->data)) < 0)
goto exit; goto exit;
} else if (cmp < 0) { } else if (cmp < 0) {
/* deletion */ /* deletion */
memcpy(&fake_entry, tentry, sizeof(git_tree_entry)); 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) if ((error = signal_deletion(tentry, cbdata->cb, cbdata->data)) < 0)
goto exit; goto exit;
} else { } else {
/* addition */ /* addition */
cbdata->i++; 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) if ((error = signal_addition(&fake_entry, cbdata->cb, cbdata->data)) < 0)
goto exit; goto exit;
/* /*
...@@ -1024,7 +1028,6 @@ static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) ...@@ -1024,7 +1028,6 @@ static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data)
} }
exit: exit:
git_buf_free(&fn_buf);
return error; return error;
} }
......
...@@ -31,6 +31,11 @@ struct git_treebuilder { ...@@ -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); void git_tree__free(git_tree *tree);
int git_tree__parse(git_tree *tree, git_odb_object *obj); int git_tree__parse(git_tree *tree, git_odb_object *obj);
......
...@@ -9,13 +9,9 @@ https://github.com/tanoku/clay ...@@ -9,13 +9,9 @@ https://github.com/tanoku/clay
* Write your modules and tests. Use good, meaningful names. * Write your modules and tests. Use good, meaningful names.
* Mix the tests:
./clay -vtap .
* Make sure you actually build the tests by setting: * Make sure you actually build the tests by setting:
BUILD_CLAY=ON cmake -DBUILD_CLAY=ON build/
* Test: * Test:
......
#ifndef __CLAY_TEST_H__
#define __CLAY_TEST_H__
#include <stdlib.h>
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
#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 "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);
}
#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");
}
#include "clay_libgit2.h" #include "clay_libgit2.h"
#include "testlib.h"
#include "posix.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) void test_index_rename__single_file(void)
{ {
git_repository *repo; git_repository *repo;
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
#include "tree.h" #include "tree.h"
#include "repository.h" #include "repository.h"
static unsigned int expect_idx;
static git_repository *repo; static git_repository *repo;
static git_index *theindex;
static git_tree *atree, *btree; static git_tree *atree, *btree;
static git_oid aoid, boid; static git_oid aoid, boid;
...@@ -27,9 +27,18 @@ static int diff_cb(const git_tree_diff_data *diff, void *data) ...@@ -27,9 +27,18 @@ static int diff_cb(const git_tree_diff_data *diff, void *data)
return GIT_SUCCESS; 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) void test_object_tree_diff__initialize(void)
{ {
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); 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) void test_object_tree_diff__cleanup(void)
...@@ -58,7 +67,7 @@ void test_object_tree_diff__addition(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(&atree, repo, &aoid));
cl_must_pass(git_tree_lookup(&btree, repo, &boid)); 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) void test_object_tree_diff__deletion(void)
...@@ -79,7 +88,7 @@ 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(&atree, repo, &aoid));
cl_must_pass(git_tree_lookup(&btree, repo, &boid)); 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) void test_object_tree_diff__modification(void)
...@@ -101,13 +110,20 @@ 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(&atree, repo, &aoid));
cl_must_pass(git_tree_lookup(&btree, repo, &boid)); 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) static int diff_more_cb(const git_tree_diff_data *diff, void *data)
{ {
git_tree_diff_data *expect = (git_tree_diff_data *) data; struct diff_more_data *more_data = data;
diff_cmp(diff, &expect[expect_idx++]); 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; return GIT_SUCCESS;
} }
...@@ -116,9 +132,10 @@ void test_object_tree_diff__more(void) ...@@ -116,9 +132,10 @@ void test_object_tree_diff__more(void)
{ {
char *astr = "814889a078c031f61ed08ab5fa863aea9314344d"; char *astr = "814889a078c031f61ed08ab5fa863aea9314344d";
char *bstr = "75057dd4114e74cca1d750d0aee1647c903cb60a"; 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 */ /* M README */
expect[0].old_attr = 0100644; expect[0].old_attr = 0100644;
expect[0].new_attr = 0100644; expect[0].new_attr = 0100644;
...@@ -146,5 +163,5 @@ void test_object_tree_diff__more(void) ...@@ -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(&atree, repo, &aoid));
cl_must_pass(git_tree_lookup(&btree, repo, &boid)); 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);
} }
#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));
}
#ifndef INCLUDE_testlib_h__
#define INCLUDE_testlib_h__
void file_create(const char *filename, const char *content);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment