summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/attr/file.c16
-rw-r--r--tests/attr/lookup.c16
-rw-r--r--tests/attr/repo.c9
-rw-r--r--tests/clar_libgit2.h2
-rw-r--r--tests/core/strmap.c72
-rw-r--r--tests/core/vector.c15
-rw-r--r--tests/diff/diff_helpers.c29
-rw-r--r--tests/diff/iterator.c59
-rw-r--r--tests/index/tests.c20
-rw-r--r--tests/status/ignore.c6
-rw-r--r--tests/threads/diff.c182
-rw-r--r--tests/threads/iterator.c49
-rw-r--r--tests/threads/refdb.c3
-rw-r--r--tests/threads/thread_helpers.c44
-rw-r--r--tests/threads/thread_helpers.h8
15 files changed, 417 insertions, 113 deletions
diff --git a/tests/attr/file.c b/tests/attr/file.c
index 4eb1d22fe..1f4108c3c 100644
--- a/tests/attr/file.c
+++ b/tests/attr/file.c
@@ -11,9 +11,9 @@ void test_attr_file__simple_read(void)
git_attr_assignment *assign;
git_attr_rule *rule;
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0")));
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr0")));
- cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2);
+ cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1);
rule = get_rule(0);
@@ -37,9 +37,9 @@ void test_attr_file__match_variants(void)
git_attr_rule *rule;
git_attr_assignment *assign;
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1")));
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr1")));
- cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2);
+ cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10);
/* let's do a thorough check of this rule, then just verify
@@ -121,9 +121,9 @@ void test_attr_file__assign_variants(void)
git_attr_rule *rule;
git_attr_assignment *assign;
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2")));
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr2")));
- cl_assert_equal_s(cl_fixture("attr/attr2"), file->key + 2);
+ cl_assert_equal_s(cl_fixture("attr/attr2"), file->entry->path);
cl_assert(file->rules.length == 11);
check_one_assign(file, 0, 0, "pat0", "simple", EXPECT_TRUE, NULL);
@@ -187,8 +187,8 @@ void test_attr_file__check_attr_examples(void)
git_attr_rule *rule;
git_attr_assignment *assign;
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3")));
- cl_assert_equal_s(cl_fixture("attr/attr3"), file->key + 2);
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr3")));
+ cl_assert_equal_s(cl_fixture("attr/attr3"), file->entry->path);
cl_assert(file->rules.length == 3);
rule = get_rule(0);
diff --git a/tests/attr/lookup.c b/tests/attr/lookup.c
index 200bdd2c7..030ea075d 100644
--- a/tests/attr/lookup.c
+++ b/tests/attr/lookup.c
@@ -9,8 +9,8 @@ void test_attr_lookup__simple(void)
git_attr_path path;
const char *value = NULL;
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr0")));
- cl_assert_equal_s(cl_fixture("attr/attr0"), file->key + 2);
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr0")));
+ cl_assert_equal_s(cl_fixture("attr/attr0"), file->entry->path);
cl_assert(file->rules.length == 1);
cl_git_pass(git_attr_path__init(&path, "test", NULL));
@@ -129,8 +129,8 @@ void test_attr_lookup__match_variants(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr1")));
- cl_assert_equal_s(cl_fixture("attr/attr1"), file->key + 2);
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr1")));
+ cl_assert_equal_s(cl_fixture("attr/attr1"), file->entry->path);
cl_assert(file->rules.length == 10);
cl_git_pass(git_attr_path__init(&path, "/testing/for/pat0", NULL));
@@ -190,7 +190,7 @@ void test_attr_lookup__assign_variants(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr2")));
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr2")));
cl_assert(file->rules.length == 11);
run_test_cases(file, cases, 0);
@@ -225,7 +225,7 @@ void test_attr_lookup__check_attr_examples(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new_and_load(&file, cl_fixture("attr/attr3")));
+ cl_git_pass(git_attr_file__load_standalone(&file, cl_fixture("attr/attr3")));
cl_assert(file->rules.length == 3);
run_test_cases(file, cases, 0);
@@ -250,9 +250,9 @@ void test_attr_lookup__from_buffer(void)
{ NULL, NULL, 0, NULL }
};
- cl_git_pass(git_attr_file__new(&file, 0, NULL, NULL));
+ cl_git_pass(git_attr_file__new(&file, NULL, 0));
- cl_git_pass(git_attr_file__parse_buffer(NULL, NULL, "a* foo\nabc bar\n* baz", file));
+ cl_git_pass(git_attr_file__parse_buffer(NULL, file, "a* foo\nabc bar\n* baz"));
cl_assert(file->rules.length == 3);
diff --git a/tests/attr/repo.c b/tests/attr/repo.c
index 49cccdc5a..71dc7a5b5 100644
--- a/tests/attr/repo.c
+++ b/tests/attr/repo.c
@@ -68,9 +68,12 @@ void test_attr_repo__get_one(void)
attr_check_expected(scan->expected, scan->expected_str, scan->attr, value);
}
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes"));
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitattributes"));
- cl_assert(git_attr_cache__is_cached(g_repo, 0, "sub/.gitattributes"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/attributes"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitattributes"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, "sub/.gitattributes"));
}
void test_attr_repo__get_many(void)
diff --git a/tests/clar_libgit2.h b/tests/clar_libgit2.h
index c2489db38..d395bd66f 100644
--- a/tests/clar_libgit2.h
+++ b/tests/clar_libgit2.h
@@ -11,7 +11,7 @@
*
* Use this wrapper around all `git_` library calls that return error codes!
*/
-#define cl_git_pass(expr) cl_git_pass_(expr, __FILE__, __LINE__)
+#define cl_git_pass(expr) cl_git_pass_((expr), __FILE__, __LINE__)
#define cl_git_pass_(expr, file, line) do { \
int _lg2_error; \
diff --git a/tests/core/strmap.c b/tests/core/strmap.c
index f34a4f89f..a120f1feb 100644
--- a/tests/core/strmap.c
+++ b/tests/core/strmap.c
@@ -3,12 +3,22 @@
GIT__USE_STRMAP;
+git_strmap *g_table;
+
+void test_core_strmap__initialize(void)
+{
+ cl_git_pass(git_strmap_alloc(&g_table));
+ cl_assert(g_table != NULL);
+}
+
+void test_core_strmap__cleanup(void)
+{
+ git_strmap_free(g_table);
+}
+
void test_core_strmap__0(void)
{
- git_strmap *table = git_strmap_alloc();
- cl_assert(table != NULL);
- cl_assert(git_strmap_num_entries(table) == 0);
- git_strmap_free(table);
+ cl_assert(git_strmap_num_entries(g_table) == 0);
}
static void insert_strings(git_strmap *table, int count)
@@ -37,21 +47,17 @@ void test_core_strmap__1(void)
{
int i;
char *str;
- git_strmap *table = git_strmap_alloc();
- cl_assert(table != NULL);
- insert_strings(table, 20);
+ insert_strings(g_table, 20);
- cl_assert(git_strmap_exists(table, "aaaaaaaaa"));
- cl_assert(git_strmap_exists(table, "ggggggggg"));
- cl_assert(!git_strmap_exists(table, "aaaaaaaab"));
- cl_assert(!git_strmap_exists(table, "abcdefghi"));
+ cl_assert(git_strmap_exists(g_table, "aaaaaaaaa"));
+ cl_assert(git_strmap_exists(g_table, "ggggggggg"));
+ cl_assert(!git_strmap_exists(g_table, "aaaaaaaab"));
+ cl_assert(!git_strmap_exists(g_table, "abcdefghi"));
i = 0;
- git_strmap_foreach_value(table, str, { i++; free(str); });
+ git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 20);
-
- git_strmap_free(table);
}
void test_core_strmap__2(void)
@@ -59,44 +65,36 @@ void test_core_strmap__2(void)
khiter_t pos;
int i;
char *str;
- git_strmap *table = git_strmap_alloc();
- cl_assert(table != NULL);
- insert_strings(table, 20);
+ insert_strings(g_table, 20);
- cl_assert(git_strmap_exists(table, "aaaaaaaaa"));
- cl_assert(git_strmap_exists(table, "ggggggggg"));
- cl_assert(!git_strmap_exists(table, "aaaaaaaab"));
- cl_assert(!git_strmap_exists(table, "abcdefghi"));
+ cl_assert(git_strmap_exists(g_table, "aaaaaaaaa"));
+ cl_assert(git_strmap_exists(g_table, "ggggggggg"));
+ cl_assert(!git_strmap_exists(g_table, "aaaaaaaab"));
+ cl_assert(!git_strmap_exists(g_table, "abcdefghi"));
- cl_assert(git_strmap_exists(table, "bbbbbbbbb"));
- pos = git_strmap_lookup_index(table, "bbbbbbbbb");
- cl_assert(git_strmap_valid_index(table, pos));
- cl_assert_equal_s(git_strmap_value_at(table, pos), "bbbbbbbbb");
- free(git_strmap_value_at(table, pos));
- git_strmap_delete_at(table, pos);
+ cl_assert(git_strmap_exists(g_table, "bbbbbbbbb"));
+ pos = git_strmap_lookup_index(g_table, "bbbbbbbbb");
+ cl_assert(git_strmap_valid_index(g_table, pos));
+ cl_assert_equal_s(git_strmap_value_at(g_table, pos), "bbbbbbbbb");
+ free(git_strmap_value_at(g_table, pos));
+ git_strmap_delete_at(g_table, pos);
- cl_assert(!git_strmap_exists(table, "bbbbbbbbb"));
+ cl_assert(!git_strmap_exists(g_table, "bbbbbbbbb"));
i = 0;
- git_strmap_foreach_value(table, str, { i++; free(str); });
+ git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 19);
-
- git_strmap_free(table);
}
void test_core_strmap__3(void)
{
int i;
char *str;
- git_strmap *table = git_strmap_alloc();
- cl_assert(table != NULL);
- insert_strings(table, 10000);
+ insert_strings(g_table, 10000);
i = 0;
- git_strmap_foreach_value(table, str, { i++; free(str); });
+ git_strmap_foreach_value(g_table, str, { i++; free(str); });
cl_assert(i == 10000);
-
- git_strmap_free(table);
}
diff --git a/tests/core/vector.c b/tests/core/vector.c
index db52c004f..66f90b82b 100644
--- a/tests/core/vector.c
+++ b/tests/core/vector.c
@@ -190,8 +190,9 @@ void test_core_vector__5(void)
git_vector_free(&x);
}
-static int remove_ones(const git_vector *v, size_t idx)
+static int remove_ones(const git_vector *v, size_t idx, void *p)
{
+ GIT_UNUSED(p);
return (git_vector_get(v, idx) == (void *)0x001);
}
@@ -206,7 +207,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 1);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x001);
@@ -214,7 +215,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 3);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 0);
git_vector_insert(&x, (void*) 0x002);
@@ -223,7 +224,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
@@ -238,7 +239,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
@@ -253,7 +254,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x001);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 2);
git_vector_foreach(&x, i, compare) {
@@ -268,7 +269,7 @@ void test_core_vector__remove_matching(void)
git_vector_insert(&x, (void*) 0x003);
cl_assert(x.length == 4);
- git_vector_remove_matching(&x, remove_ones);
+ git_vector_remove_matching(&x, remove_ones, NULL);
cl_assert(x.length == 4);
git_vector_free(&x);
diff --git a/tests/diff/diff_helpers.c b/tests/diff/diff_helpers.c
index 33bb561f6..279cb20c5 100644
--- a/tests/diff/diff_helpers.c
+++ b/tests/diff/diff_helpers.c
@@ -1,5 +1,6 @@
#include "clar_libgit2.h"
#include "diff_helpers.h"
+#include "git2/sys/diff.h"
git_tree *resolve_commit_oid_to_tree(
git_repository *repo,
@@ -215,32 +216,16 @@ abort:
return GIT_EUSER;
}
-static int diff_print_cb(
- const git_diff_delta *delta,
- const git_diff_hunk *hunk,
- const git_diff_line *line,
- void *payload)
-{
- FILE *fp = payload;
-
- GIT_UNUSED(delta); GIT_UNUSED(hunk);
-
- if (line->origin == GIT_DIFF_LINE_CONTEXT ||
- line->origin == GIT_DIFF_LINE_ADDITION ||
- line->origin == GIT_DIFF_LINE_DELETION)
- fputc(line->origin, fp);
- fwrite(line->content, 1, line->content_len, fp);
- return 0;
-}
-
void diff_print(FILE *fp, git_diff *diff)
{
- cl_git_pass(git_diff_print(
- diff, GIT_DIFF_FORMAT_PATCH, diff_print_cb, fp ? fp : stderr));
+ cl_git_pass(
+ git_diff_print(diff, GIT_DIFF_FORMAT_PATCH,
+ git_diff_print_callback__to_file_handle, fp ? fp : stderr));
}
void diff_print_raw(FILE *fp, git_diff *diff)
{
- cl_git_pass(git_diff_print(
- diff, GIT_DIFF_FORMAT_RAW, diff_print_cb, fp ? fp : stderr));
+ cl_git_pass(
+ git_diff_print(diff, GIT_DIFF_FORMAT_RAW,
+ git_diff_print_callback__to_file_handle, fp ? fp : stderr));
}
diff --git a/tests/diff/iterator.c b/tests/diff/iterator.c
index 891d8a6e5..cdc64eb1d 100644
--- a/tests/diff/iterator.c
+++ b/tests/diff/iterator.c
@@ -355,6 +355,7 @@ static void index_iterator_test(
const char *sandbox,
const char *start,
const char *end,
+ git_iterator_flag_t flags,
int expected_count,
const char **expected_names,
const char **expected_oids)
@@ -362,11 +363,13 @@ static void index_iterator_test(
git_index *index;
git_iterator *i;
const git_index_entry *entry;
- int error, count = 0;
+ int error, count = 0, caps;
git_repository *repo = cl_git_sandbox_init(sandbox);
cl_git_pass(git_repository_index(&index, repo));
- cl_git_pass(git_iterator_for_index(&i, index, 0, start, end));
+ caps = git_index_caps(index);
+
+ cl_git_pass(git_iterator_for_index(&i, index, flags, start, end));
while (!(error = git_iterator_advance(&entry, i))) {
cl_assert(entry);
@@ -388,6 +391,8 @@ static void index_iterator_test(
cl_assert_equal_i(expected_count, count);
git_iterator_free(i);
+
+ cl_assert(caps == git_index_caps(index));
git_index_free(index);
}
@@ -446,7 +451,8 @@ static const char *expected_index_oids_0[] = {
void test_diff_iterator__index_0(void)
{
index_iterator_test(
- "attr", NULL, NULL, 23, expected_index_0, expected_index_oids_0);
+ "attr", NULL, NULL, 0, ARRAY_SIZE(expected_index_0),
+ expected_index_0, expected_index_oids_0);
}
static const char *expected_index_range[] = {
@@ -466,25 +472,26 @@ static const char *expected_index_oids_range[] = {
void test_diff_iterator__index_range(void)
{
index_iterator_test(
- "attr", "root", "root", 4, expected_index_range, expected_index_oids_range);
+ "attr", "root", "root", 0, ARRAY_SIZE(expected_index_range),
+ expected_index_range, expected_index_oids_range);
}
void test_diff_iterator__index_range_empty_0(void)
{
index_iterator_test(
- "attr", "empty", "empty", 0, NULL, NULL);
+ "attr", "empty", "empty", 0, 0, NULL, NULL);
}
void test_diff_iterator__index_range_empty_1(void)
{
index_iterator_test(
- "attr", "z_empty_after", NULL, 0, NULL, NULL);
+ "attr", "z_empty_after", NULL, 0, 0, NULL, NULL);
}
void test_diff_iterator__index_range_empty_2(void)
{
index_iterator_test(
- "attr", NULL, ".aaa_empty_before", 0, NULL, NULL);
+ "attr", NULL, ".aaa_empty_before", 0, 0, NULL, NULL);
}
static const char *expected_index_1[] = {
@@ -522,9 +529,45 @@ static const char* expected_index_oids_1[] = {
void test_diff_iterator__index_1(void)
{
index_iterator_test(
- "status", NULL, NULL, 13, expected_index_1, expected_index_oids_1);
+ "status", NULL, NULL, 0, ARRAY_SIZE(expected_index_1),
+ expected_index_1, expected_index_oids_1);
}
+static const char *expected_index_cs[] = {
+ "B", "D", "F", "H", "J", "L/1", "L/B", "L/D", "L/a", "L/c",
+ "a", "c", "e", "g", "i", "k/1", "k/B", "k/D", "k/a", "k/c",
+};
+
+static const char *expected_index_ci[] = {
+ "a", "B", "c", "D", "e", "F", "g", "H", "i", "J",
+ "k/1", "k/a", "k/B", "k/c", "k/D", "L/1", "L/a", "L/B", "L/c", "L/D",
+};
+
+void test_diff_iterator__index_case_folding(void)
+{
+ git_buf path = GIT_BUF_INIT;
+ int fs_is_ci = 0;
+
+ cl_git_pass(git_buf_joinpath(&path, cl_fixture("icase"), ".gitted/CoNfIg"));
+ fs_is_ci = git_path_exists(path.ptr);
+ git_buf_free(&path);
+
+ index_iterator_test(
+ "icase", NULL, NULL, 0, ARRAY_SIZE(expected_index_cs),
+ fs_is_ci ? expected_index_ci : expected_index_cs, NULL);
+
+ cl_git_sandbox_cleanup();
+
+ index_iterator_test(
+ "icase", NULL, NULL, GIT_ITERATOR_IGNORE_CASE,
+ ARRAY_SIZE(expected_index_ci), expected_index_ci, NULL);
+
+ cl_git_sandbox_cleanup();
+
+ index_iterator_test(
+ "icase", NULL, NULL, GIT_ITERATOR_DONT_IGNORE_CASE,
+ ARRAY_SIZE(expected_index_cs), expected_index_cs, NULL);
+}
/* -- WORKDIR ITERATOR TESTS -- */
diff --git a/tests/index/tests.c b/tests/index/tests.c
index 6e28af1f7..fa5c0bb1a 100644
--- a/tests/index/tests.c
+++ b/tests/index/tests.c
@@ -544,36 +544,22 @@ void test_index_tests__corrupted_extension(void)
cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR);
}
-static void assert_index_is_sorted(git_index *index)
-{
- git_vector *entries = &index->entries;
- size_t i;
-
- cl_assert(git_vector_is_sorted(entries));
-
- for (i = 1; i < git_vector_length(entries); ++i) {
- git_index_entry *prev = git_vector_get(entries, i - 1);
- git_index_entry *curr = git_vector_get(entries, i);
- cl_assert(index->entries._cmp(prev, curr) <= 0);
- }
-}
-
void test_index_tests__reload_while_ignoring_case(void)
{
git_index *index;
unsigned int caps;
cl_git_pass(git_index_open(&index, TEST_INDEX_PATH));
- assert_index_is_sorted(index);
+ cl_git_pass(git_vector_verify_sorted(&index->entries));
caps = git_index_caps(index);
cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEXCAP_IGNORE_CASE));
cl_git_pass(git_index_read(index, true));
- assert_index_is_sorted(index);
+ cl_git_pass(git_vector_verify_sorted(&index->entries));
cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE));
cl_git_pass(git_index_read(index, true));
- assert_index_is_sorted(index);
+ cl_git_pass(git_vector_verify_sorted(&index->entries));
git_index_free(index);
}
diff --git a/tests/status/ignore.c b/tests/status/ignore.c
index d6c26a847..052a8eae8 100644
--- a/tests/status/ignore.c
+++ b/tests/status/ignore.c
@@ -54,8 +54,10 @@ void test_status_ignore__0(void)
}
/* confirm that ignore files were cached */
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/exclude"));
- cl_assert(git_attr_cache__is_cached(g_repo, 0, ".gitignore"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".git/info/exclude"));
+ cl_assert(git_attr_cache__is_cached(
+ g_repo, GIT_ATTR_FILE__FROM_FILE, ".gitignore"));
}
diff --git a/tests/threads/diff.c b/tests/threads/diff.c
new file mode 100644
index 000000000..79b85800b
--- /dev/null
+++ b/tests/threads/diff.c
@@ -0,0 +1,182 @@
+#include "clar_libgit2.h"
+#include "thread_helpers.h"
+
+static git_repository *_repo;
+static git_tree *_a, *_b;
+static git_atomic _counts[4];
+static int _check_counts;
+
+#define THREADS 20
+
+void test_threads_diff__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+static void setup_trees(void)
+{
+ git_index *idx;
+
+ _repo = cl_git_sandbox_reopen(); /* reopen sandbox to flush caches */
+
+ /* avoid competing to load initial index */
+ cl_git_pass(git_repository_index(&idx, _repo));
+ git_index_free(idx);
+
+ cl_git_pass(git_revparse_single(
+ (git_object **)&_a, _repo, "0017bd4ab1^{tree}"));
+ cl_git_pass(git_revparse_single(
+ (git_object **)&_b, _repo, "26a125ee1b^{tree}"));
+
+ memset(_counts, 0, sizeof(_counts));
+}
+
+static void free_trees(void)
+{
+ git_tree_free(_a); _a = NULL;
+ git_tree_free(_b); _b = NULL;
+
+ if (_check_counts) {
+ cl_assert_equal_i(288, git_atomic_get(&_counts[0]));
+ cl_assert_equal_i(112, git_atomic_get(&_counts[1]));
+ cl_assert_equal_i( 80, git_atomic_get(&_counts[2]));
+ cl_assert_equal_i( 96, git_atomic_get(&_counts[3]));
+ }
+}
+
+static void *run_index_diffs(void *arg)
+{
+ int thread = *(int *)arg;
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_diff *diff = NULL;
+ size_t i;
+ int exp[4] = { 0, 0, 0, 0 };
+
+ switch (thread & 0x03) {
+ case 0: /* diff index to workdir */;
+ cl_git_pass(git_diff_index_to_workdir(&diff, _repo, NULL, &opts));
+ break;
+ case 1: /* diff tree 'a' to index */;
+ cl_git_pass(git_diff_tree_to_index(&diff, _repo, _a, NULL, &opts));
+ break;
+ case 2: /* diff tree 'b' to index */;
+ cl_git_pass(git_diff_tree_to_index(&diff, _repo, _b, NULL, &opts));
+ break;
+ case 3: /* diff index to workdir (explicit index) */;
+ {
+ git_index *idx;
+ cl_git_pass(git_repository_index(&idx, _repo));
+ cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
+ git_index_free(idx);
+ break;
+ }
+ }
+
+ /* keep some diff stats to make sure results are as expected */
+
+ i = git_diff_num_deltas(diff);
+ git_atomic_add(&_counts[0], (int32_t)i);
+ exp[0] = (int)i;
+
+ while (i > 0) {
+ switch (git_diff_get_delta(diff, --i)->status) {
+ case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&_counts[1]); break;
+ case GIT_DELTA_ADDED: exp[2]++; git_atomic_inc(&_counts[2]); break;
+ case GIT_DELTA_DELETED: exp[3]++; git_atomic_inc(&_counts[3]); break;
+ default: break;
+ }
+ }
+
+ switch (thread & 0x03) {
+ case 0: case 3:
+ cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(4, exp[1]);
+ cl_assert_equal_i(0, exp[2]); cl_assert_equal_i(4, exp[3]);
+ break;
+ case 1:
+ cl_assert_equal_i(12, exp[0]); cl_assert_equal_i(3, exp[1]);
+ cl_assert_equal_i(7, exp[2]); cl_assert_equal_i(2, exp[3]);
+ break;
+ case 2:
+ cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(3, exp[1]);
+ cl_assert_equal_i(3, exp[2]); cl_assert_equal_i(2, exp[3]);
+ break;
+ }
+
+ git_diff_free(diff);
+ giterr_clear();
+
+ return arg;
+}
+
+void test_threads_diff__concurrent_diffs(void)
+{
+ _repo = cl_git_sandbox_init("status");
+ _check_counts = 1;
+
+ run_in_parallel(
+ 5, 32, run_index_diffs, setup_trees, free_trees);
+}
+
+static void *run_index_diffs_with_modifier(void *arg)
+{
+ int thread = *(int *)arg;
+ git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+ git_diff *diff = NULL;
+ git_index *idx = NULL;
+
+ cl_git_pass(git_repository_index(&idx, _repo));
+
+ /* have first thread altering the index as we go */
+ if (thread == 0) {
+ int i;
+
+ for (i = 0; i < 300; ++i) {
+ switch (i & 0x03) {
+ case 0: (void)git_index_add_bypath(idx, "new_file"); break;
+ case 1: (void)git_index_remove_bypath(idx, "modified_file"); break;
+ case 2: (void)git_index_remove_bypath(idx, "new_file"); break;
+ case 3: (void)git_index_add_bypath(idx, "modified_file"); break;
+ }
+ git_thread_yield();
+ }
+
+ goto done;
+ }
+
+ /* only use explicit index in this test to prevent reloading */
+
+ switch (thread & 0x03) {
+ case 0: /* diff index to workdir */;
+ cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
+ break;
+ case 1: /* diff tree 'a' to index */;
+ cl_git_pass(git_diff_tree_to_index(&diff, _repo, _a, idx, &opts));
+ break;
+ case 2: /* diff tree 'b' to index */;
+ cl_git_pass(git_diff_tree_to_index(&diff, _repo, _b, idx, &opts));
+ break;
+ case 3: /* diff index to workdir reversed */;
+ opts.flags |= GIT_DIFF_REVERSE;
+ cl_git_pass(git_diff_index_to_workdir(&diff, _repo, idx, &opts));
+ break;
+ }
+
+ /* results will be unpredictable with index modifier thread running */
+
+ git_diff_free(diff);
+
+done:
+ git_index_free(idx);
+ giterr_clear();
+
+ return arg;
+}
+
+void test_threads_diff__with_concurrent_index_modified(void)
+{
+ _repo = cl_git_sandbox_init("status");
+ _check_counts = 0;
+
+ run_in_parallel(
+ 5, 16, run_index_diffs_with_modifier, setup_trees, free_trees);
+}
diff --git a/tests/threads/iterator.c b/tests/threads/iterator.c
new file mode 100644
index 000000000..8aeae1a6c
--- /dev/null
+++ b/tests/threads/iterator.c
@@ -0,0 +1,49 @@
+#include "clar_libgit2.h"
+#include "thread_helpers.h"
+#include "iterator.h"
+
+static git_repository *_repo;
+
+void test_threads_iterator__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+static void *run_workdir_iterator(void *arg)
+{
+ int error = 0;
+ git_iterator *iter;
+ const git_index_entry *entry = NULL;
+
+ cl_git_pass(git_iterator_for_workdir(
+ &iter, _repo, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
+
+ while (!error) {
+ if (entry && entry->mode == GIT_FILEMODE_TREE) {
+ error = git_iterator_advance_into(&entry, iter);
+
+ if (error == GIT_ENOTFOUND)
+ error = git_iterator_advance(&entry, iter);
+ } else {
+ error = git_iterator_advance(&entry, iter);
+ }
+
+ if (!error)
+ (void)git_iterator_current_is_ignored(iter);
+ }
+
+ cl_assert_equal_i(GIT_ITEROVER, error);
+
+ git_iterator_free(iter);
+ giterr_clear();
+ return arg;
+}
+
+
+void test_threads_iterator__workdir(void)
+{
+ _repo = cl_git_sandbox_init("status");
+
+ run_in_parallel(
+ 1, 20, run_workdir_iterator, NULL, NULL);
+}
diff --git a/tests/threads/refdb.c b/tests/threads/refdb.c
index fbf6ac09b..3b35b45e3 100644
--- a/tests/threads/refdb.c
+++ b/tests/threads/refdb.c
@@ -37,6 +37,7 @@ static void *iterate_refs(void *arg)
git_reference_iterator_free(i);
+ giterr_clear();
return arg;
}
@@ -115,6 +116,7 @@ static void *create_refs(void *arg)
for (i = 0; i < 10; ++i)
git_reference_free(ref[i]);
+ giterr_clear();
return arg;
}
@@ -141,6 +143,7 @@ static void *delete_refs(void *arg)
}
}
+ giterr_clear();
return arg;
}
diff --git a/tests/threads/thread_helpers.c b/tests/threads/thread_helpers.c
new file mode 100644
index 000000000..25370dddb
--- /dev/null
+++ b/tests/threads/thread_helpers.c
@@ -0,0 +1,44 @@
+#include "clar_libgit2.h"
+#include "thread_helpers.h"
+
+void run_in_parallel(
+ int repeats,
+ int threads,
+ void *(*func)(void *),
+ void (*before_test)(void),
+ void (*after_test)(void))
+{
+ int r, t, *id = git__calloc(threads, sizeof(int));
+#ifdef GIT_THREADS
+ git_thread *th = git__calloc(threads, sizeof(git_thread));
+ cl_assert(th != NULL);
+#else
+ void *th = NULL;
+#endif
+
+ cl_assert(id != NULL);
+
+ for (r = 0; r < repeats; ++r) {
+ if (before_test) before_test();
+
+ for (t = 0; t < threads; ++t) {
+ id[t] = t;
+#ifdef GIT_THREADS
+ cl_git_pass(git_thread_create(&th[t], NULL, func, &id[t]));
+#else
+ cl_assert(func(&id[t]) == &id[t]);
+#endif
+ }
+
+#ifdef GIT_THREADS
+ for (t = 0; t < threads; ++t)
+ cl_git_pass(git_thread_join(th[t], NULL));
+ memset(th, 0, threads * sizeof(git_thread));
+#endif
+
+ if (after_test) after_test();
+ }
+
+ git__free(id);
+ git__free(th);
+}
diff --git a/tests/threads/thread_helpers.h b/tests/threads/thread_helpers.h
new file mode 100644
index 000000000..3c13cfb6b
--- /dev/null
+++ b/tests/threads/thread_helpers.h
@@ -0,0 +1,8 @@
+#include "thread-utils.h"
+
+void run_in_parallel(
+ int repeats,
+ int threads,
+ void *(*func)(void *),
+ void (*before_test)(void),
+ void (*after_test)(void));