Commit 11bd7a034ba9046a7ba601c446e937377d507065

Russell Belfer 2013-12-12T11:14:51

More tests of canceling from callbacks This covers diff print, push, and ref foreach. This also has a fix for a small memory leak in the push tests.

diff --git a/tests/diff/patch.c b/tests/diff/patch.c
index bd1598b..0cef3bd 100644
--- a/tests/diff/patch.c
+++ b/tests/diff/patch.c
@@ -30,8 +30,6 @@ static int check_removal_cb(
 	const git_diff_line *line,
 	void *payload)
 {
-	GIT_UNUSED(payload);
-
 	switch (line->origin) {
 	case GIT_DIFF_LINE_FILE_HDR:
 		cl_assert_equal_s(EXPECTED_HEADER, line->content);
@@ -40,10 +38,12 @@ static int check_removal_cb(
 
 	case GIT_DIFF_LINE_HUNK_HDR:
 		cl_assert_equal_s(EXPECTED_HUNK, line->content);
-		/* Fall through */
+		goto check_hunk;
 
 	case GIT_DIFF_LINE_CONTEXT:
 	case GIT_DIFF_LINE_DELETION:
+		if (payload != NULL)
+			return *(int *)payload;
 		goto check_hunk;
 
 	default:
@@ -101,6 +101,39 @@ void test_diff_patch__can_properly_display_the_removal_of_a_file(void)
 	git_tree_free(one);
 }
 
+void test_diff_patch__can_cancel_diff_print(void)
+{
+	const char *one_sha = "26a125e";
+	const char *another_sha = "735b6a2";
+	git_tree *one, *another;
+	git_diff *diff;
+	int fail_with;
+
+	g_repo = cl_git_sandbox_init("status");
+
+	one = resolve_commit_oid_to_tree(g_repo, one_sha);
+	another = resolve_commit_oid_to_tree(g_repo, another_sha);
+
+	cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL));
+
+	fail_with = -2323;
+
+	cl_git_fail_with(git_diff_print(
+		diff, GIT_DIFF_FORMAT_PATCH, check_removal_cb, &fail_with),
+		fail_with);
+
+	fail_with = 45;
+
+	cl_git_fail_with(git_diff_print(
+		diff, GIT_DIFF_FORMAT_PATCH, check_removal_cb, &fail_with),
+		fail_with);
+
+	git_diff_free(diff);
+
+	git_tree_free(another);
+	git_tree_free(one);
+}
+
 void test_diff_patch__to_string(void)
 {
 	const char *one_sha = "26a125e";
diff --git a/tests/online/push.c b/tests/online/push.c
index be505c3..33f1746 100644
--- a/tests/online/push.c
+++ b/tests/online/push.c
@@ -207,6 +207,7 @@ static void verify_tracking_branches(git_remote *remote, expected_ref expected_r
 	}
 
 	cl_assert_equal_i(error, GIT_ITEROVER);
+	git_branch_iterator_free(iter);
 
 	/* Loop through expected refs, make sure they exist */
 	for (i = 0; i < expected_refs_len; i++) {
@@ -371,19 +372,25 @@ void test_online_push__cleanup(void)
 	cl_git_sandbox_cleanup();
 }
 
-static int push_pack_progress_cb(int stage, unsigned int current, unsigned int total, void* payload)
+static int push_pack_progress_cb(
+	int stage, unsigned int current, unsigned int total, void* payload)
 {
-	int *was_called = (int *) payload;
+	int *calls = (int *)payload;
 	GIT_UNUSED(stage); GIT_UNUSED(current); GIT_UNUSED(total);
-	*was_called = 1;
+	if (*calls < 0)
+		return *calls;
+	(*calls)++;
 	return 0;
 }
 
-static int push_transfer_progress_cb(unsigned int current, unsigned int total, size_t bytes, void* payload)
+static int push_transfer_progress_cb(
+	unsigned int current, unsigned int total, size_t bytes, void* payload)
 {
-	int *was_called = (int *) payload;
+	int *calls = (int *)payload;
 	GIT_UNUSED(current); GIT_UNUSED(total); GIT_UNUSED(bytes);
-	*was_called = 1;
+	if (*calls < 0)
+		return *calls;
+	(*calls)++;
 	return 0;
 }
 
@@ -397,15 +404,16 @@ static int push_transfer_progress_cb(unsigned int current, unsigned int total, s
  * @param expected_ret expected return value from git_push_finish()
  * @param check_progress_cb Check that the push progress callbacks are called
  */
-static void do_push(const char *refspecs[], size_t refspecs_len,
+static void do_push(
+	const char *refspecs[], size_t refspecs_len,
 	push_status expected_statuses[], size_t expected_statuses_len,
-	expected_ref expected_refs[], size_t expected_refs_len, int expected_ret, int check_progress_cb)
+	expected_ref expected_refs[], size_t expected_refs_len,
+	int expected_ret, int check_progress_cb)
 {
 	git_push *push;
 	git_push_options opts = GIT_PUSH_OPTIONS_INIT;
 	size_t i;
-	int ret;
-	int pack_progress_called = 0, transfer_progress_called = 0;
+	int pack_progress_calls = 0, transfer_progress_calls = 0;
 
 	if (_remote) {
 		/* Auto-detect the number of threads to use */
@@ -416,30 +424,35 @@ static void do_push(const char *refspecs[], size_t refspecs_len,
 		cl_git_pass(git_push_new(&push, _remote));
 		cl_git_pass(git_push_set_options(push, &opts));
 
-		if (check_progress_cb)
-			cl_git_pass(git_push_set_callbacks(push, push_pack_progress_cb, &pack_progress_called, push_transfer_progress_cb, &transfer_progress_called));
+		if (check_progress_cb) {
+			/* if EUSER, then abort in transfer */
+			if (expected_ret == GIT_EUSER)
+				transfer_progress_calls = GIT_EUSER;
+
+			cl_git_pass(
+				git_push_set_callbacks(
+					push, push_pack_progress_cb, &pack_progress_calls,
+					push_transfer_progress_cb, &transfer_progress_calls));
+		}
 
 		for (i = 0; i < refspecs_len; i++)
 			cl_git_pass(git_push_add_refspec(push, refspecs[i]));
 
 		if (expected_ret < 0) {
-			cl_git_fail(ret = git_push_finish(push));
+			cl_git_fail_with(git_push_finish(push), expected_ret);
 			cl_assert_equal_i(0, git_push_unpack_ok(push));
-		}
-		else {
-			cl_git_pass(ret = git_push_finish(push));
+		} else {
+			cl_git_pass(git_push_finish(push));
 			cl_assert_equal_i(1, git_push_unpack_ok(push));
 		}
 
-		if (check_progress_cb) {
-			cl_assert_equal_i(1, pack_progress_called);
-			cl_assert_equal_i(1, transfer_progress_called);
+		if (check_progress_cb && !expected_ret) {
+			cl_assert(pack_progress_calls > 0);
+			cl_assert(transfer_progress_calls > 0);
 		}
 
 		do_verify_push_status(push, expected_statuses, expected_statuses_len);
 
-		cl_assert_equal_i(expected_ret, ret);
-
 		verify_refs(_remote, expected_refs, expected_refs_len);
 
 		cl_git_pass(git_push_update_tips(push));
@@ -507,6 +520,12 @@ void test_online_push__b5(void)
 		exp_refs, ARRAY_SIZE(exp_refs), 0, 1);
 }
 
+void test_online_push__b5_cancel(void)
+{
+	const char *specs[] = { "refs/heads/b5:refs/heads/b5" };
+	do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1);
+}
+
 void test_online_push__multi(void)
 {
 	const char *specs[] = {
@@ -731,7 +750,7 @@ void test_online_push__bad_refspecs(void)
 	git_push *push;
 
 	if (_remote) {
-//		cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH));
+/*		cl_git_pass(git_remote_connect(_remote, GIT_DIRECTION_PUSH)); */
 		cl_git_pass(git_push_new(&push, _remote));
 
 		/* Unexpanded branch names not supported */
diff --git a/tests/refs/iterator.c b/tests/refs/iterator.c
index 266410f..a29b0cf 100644
--- a/tests/refs/iterator.c
+++ b/tests/refs/iterator.c
@@ -46,36 +46,43 @@ static int refcmp_cb(const void *a, const void *b)
 	return strcmp(refa->name, refb->name);
 }
 
+static void assert_all_refnames_match(git_vector *output)
+{
+	size_t i;
+	git_reference *ref;
+
+	cl_assert_equal_sz(output->length, ARRAY_SIZE(refnames));
+
+	git_vector_sort(output);
+
+	git_vector_foreach(output, i, ref) {
+		cl_assert_equal_s(ref->name, refnames[i]);
+		git_reference_free(ref);
+	}
+
+	git_vector_free(output);
+}
+
 void test_refs_iterator__list(void)
 {
 	git_reference_iterator *iter;
 	git_vector output;
 	git_reference *ref;
-	int error;
-	size_t i;
 
 	cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
 	cl_git_pass(git_reference_iterator_new(&iter, repo));
 
-	do {
-		error = git_reference_next(&ref, iter);
-		cl_assert(error == 0 || error == GIT_ITEROVER);
-		if (error != GIT_ITEROVER) {
-			cl_git_pass(git_vector_insert(&output, ref));
-		}
-	} while (!error);
+	while (1) {
+		int error = git_reference_next(&ref, iter);
+		if (error == GIT_ITEROVER)
+			break;
+		cl_git_pass(error);
+		cl_git_pass(git_vector_insert(&output, ref));
+	}
 
 	git_reference_iterator_free(iter);
-	cl_assert_equal_sz(output.length, ARRAY_SIZE(refnames));
 
-	git_vector_sort(&output);
-
-	git_vector_foreach(&output, i, ref) {
-		cl_assert_equal_s(ref->name, refnames[i]);
-		git_reference_free(ref);
-	}
-
-	git_vector_free(&output);
+	assert_all_refnames_match(&output);
 }
 
 void test_refs_iterator__empty(void)
@@ -95,3 +102,87 @@ void test_refs_iterator__empty(void)
 	git_odb_free(odb);
 	git_repository_free(empty);
 }
+
+static int refs_foreach_cb(git_reference *reference, void *payload)
+{
+	git_vector *output = payload;
+	cl_git_pass(git_vector_insert(output, reference));
+	return 0;
+}
+
+void test_refs_iterator__foreach(void)
+{
+	git_vector output;
+	cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
+	cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
+	assert_all_refnames_match(&output);
+}
+
+static int refs_foreach_cancel_cb(git_reference *reference, void *payload)
+{
+	int *cancel_after = payload;
+
+	git_reference_free(reference);
+
+	if (!*cancel_after)
+		return -333;
+	(*cancel_after)--;
+	return 0;
+}
+
+void test_refs_iterator__foreach_can_cancel(void)
+{
+	int cancel_after = 3;
+	cl_git_fail_with(
+		git_reference_foreach(repo, refs_foreach_cancel_cb, &cancel_after),
+		-333);
+	cl_assert_equal_i(0, cancel_after);
+}
+
+static int refs_foreach_name_cb(const char *name, void *payload)
+{
+	git_vector *output = payload;
+	cl_git_pass(git_vector_insert(output, git__strdup(name)));
+	return 0;
+}
+
+void test_refs_iterator__foreach_name(void)
+{
+	git_vector output;
+	size_t i;
+	char *name;
+
+	cl_git_pass(git_vector_init(&output, 32, &git__strcmp_cb));
+	cl_git_pass(
+		git_reference_foreach_name(repo, refs_foreach_name_cb, &output));
+
+	cl_assert_equal_sz(output.length, ARRAY_SIZE(refnames));
+	git_vector_sort(&output);
+
+	git_vector_foreach(&output, i, name) {
+		cl_assert_equal_s(name, refnames[i]);
+		git__free(name);
+	}
+
+	git_vector_free(&output);
+}
+
+static int refs_foreach_name_cancel_cb(const char *name, void *payload)
+{
+	int *cancel_after = payload;
+	if (!*cancel_after)
+		return -333;
+	GIT_UNUSED(name);
+	(*cancel_after)--;
+	return 0;
+}
+
+void test_refs_iterator__foreach_name_can_cancel(void)
+{
+	int cancel_after = 5;
+	cl_git_fail_with(
+		git_reference_foreach_name(
+			repo, refs_foreach_name_cancel_cb, &cancel_after),
+		-333);
+	cl_assert_equal_i(0, cancel_after);
+}