1 #include "clar_libgit2.h"
2 #include "refs.h"
3 #include "vector.h"
4 
5 static git_repository *repo;
6 
test_refs_iterator__initialize(void)7 void test_refs_iterator__initialize(void)
8 {
9 	repo = cl_git_sandbox_init("testrepo.git");
10 }
11 
test_refs_iterator__cleanup(void)12 void test_refs_iterator__cleanup(void)
13 {
14 	cl_git_sandbox_cleanup();
15 }
16 
17 static const char *refnames[] = {
18 	"refs/blobs/annotated_tag_to_blob",
19 	"refs/heads/br2",
20 	"refs/heads/cannot-fetch",
21 	"refs/heads/chomped",
22 	"refs/heads/haacked",
23 	"refs/heads/master",
24 	"refs/heads/not-good",
25 	"refs/heads/packed",
26 	"refs/heads/packed-test",
27 	"refs/heads/subtrees",
28 	"refs/heads/test",
29 	"refs/heads/track-local",
30 	"refs/heads/trailing",
31 	"refs/notes/fanout",
32 	"refs/remotes/test/master",
33 	"refs/tags/annotated_tag_to_blob",
34 	"refs/tags/e90810b",
35 	"refs/tags/hard_tag",
36 	"refs/tags/point_to_blob",
37 	"refs/tags/taggerless",
38 	"refs/tags/test",
39 	"refs/tags/wrapped_tag",
40 	NULL
41 };
42 
43 static const char *refnames_with_symlink[] = {
44 	"refs/blobs/annotated_tag_to_blob",
45 	"refs/heads/br2",
46 	"refs/heads/cannot-fetch",
47 	"refs/heads/chomped",
48 	"refs/heads/haacked",
49 	"refs/heads/link/a",
50 	"refs/heads/link/b",
51 	"refs/heads/link/c",
52 	"refs/heads/link/d",
53 	"refs/heads/master",
54 	"refs/heads/not-good",
55 	"refs/heads/packed",
56 	"refs/heads/packed-test",
57 	"refs/heads/subtrees",
58 	"refs/heads/test",
59 	"refs/heads/track-local",
60 	"refs/heads/trailing",
61 	"refs/notes/fanout",
62 	"refs/remotes/test/master",
63 	"refs/tags/annotated_tag_to_blob",
64 	"refs/tags/e90810b",
65 	"refs/tags/hard_tag",
66 	"refs/tags/point_to_blob",
67 	"refs/tags/taggerless",
68 	"refs/tags/test",
69 	"refs/tags/wrapped_tag",
70 	NULL
71 };
72 
refcmp_cb(const void * a,const void * b)73 static int refcmp_cb(const void *a, const void *b)
74 {
75 	const git_reference *refa = (const git_reference *)a;
76 	const git_reference *refb = (const git_reference *)b;
77 
78 	return strcmp(refa->name, refb->name);
79 }
80 
assert_all_refnames_match(const char ** expected,git_vector * names)81 static void assert_all_refnames_match(const char **expected, git_vector *names)
82 {
83 	size_t i;
84 	git_reference *ref;
85 
86 	git_vector_sort(names);
87 
88 	git_vector_foreach(names, i, ref) {
89 		cl_assert(expected[i] != NULL);
90 		cl_assert_equal_s(expected[i], ref->name);
91 		git_reference_free(ref);
92 	}
93 	cl_assert(expected[i] == NULL);
94 
95 	git_vector_free(names);
96 }
97 
test_refs_iterator__list(void)98 void test_refs_iterator__list(void)
99 {
100 	git_reference_iterator *iter;
101 	git_vector output;
102 	git_reference *ref;
103 
104 	cl_git_pass(git_vector_init(&output, 33, &refcmp_cb));
105 	cl_git_pass(git_reference_iterator_new(&iter, repo));
106 
107 	while (1) {
108 		int error = git_reference_next(&ref, iter);
109 		if (error == GIT_ITEROVER)
110 			break;
111 		cl_git_pass(error);
112 		cl_git_pass(git_vector_insert(&output, ref));
113 	}
114 
115 	git_reference_iterator_free(iter);
116 
117 	assert_all_refnames_match(refnames, &output);
118 }
119 
test_refs_iterator__empty(void)120 void test_refs_iterator__empty(void)
121 {
122 	git_reference_iterator *iter;
123 	git_odb *odb;
124 	git_reference *ref;
125 	git_repository *empty;
126 
127 	cl_git_pass(git_odb_new(&odb));
128 	cl_git_pass(git_repository_wrap_odb(&empty, odb));
129 
130 	cl_git_pass(git_reference_iterator_new(&iter, empty));
131 	cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&ref, iter));
132 
133 	git_reference_iterator_free(iter);
134 	git_odb_free(odb);
135 	git_repository_free(empty);
136 }
137 
refs_foreach_cb(git_reference * reference,void * payload)138 static int refs_foreach_cb(git_reference *reference, void *payload)
139 {
140 	git_vector *output = payload;
141 	cl_git_pass(git_vector_insert(output, reference));
142 	return 0;
143 }
144 
test_refs_iterator__foreach(void)145 void test_refs_iterator__foreach(void)
146 {
147 	git_vector output;
148 	cl_git_pass(git_vector_init(&output, 33, &refcmp_cb));
149 	cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
150 	assert_all_refnames_match(refnames, &output);
151 }
152 
test_refs_iterator__foreach_through_symlink(void)153 void test_refs_iterator__foreach_through_symlink(void)
154 {
155 	git_vector output;
156 
157 #ifdef GIT_WIN32
158 	cl_skip();
159 #endif
160 
161 	cl_git_pass(git_vector_init(&output, 32, &refcmp_cb));
162 
163 	cl_git_pass(p_mkdir("refs", 0777));
164 	cl_git_mkfile("refs/a", "1234567890123456789012345678901234567890");
165 	cl_git_mkfile("refs/b", "1234567890123456789012345678901234567890");
166 	cl_git_mkfile("refs/c", "1234567890123456789012345678901234567890");
167 	cl_git_mkfile("refs/d", "1234567890123456789012345678901234567890");
168 
169 	cl_git_pass(p_symlink("../../../refs", "testrepo.git/refs/heads/link"));
170 
171 	cl_git_pass(git_reference_foreach(repo, refs_foreach_cb, &output));
172 	assert_all_refnames_match(refnames_with_symlink, &output);
173 }
174 
refs_foreach_cancel_cb(git_reference * reference,void * payload)175 static int refs_foreach_cancel_cb(git_reference *reference, void *payload)
176 {
177 	int *cancel_after = payload;
178 
179 	git_reference_free(reference);
180 
181 	if (!*cancel_after)
182 		return -333;
183 	(*cancel_after)--;
184 	return 0;
185 }
186 
test_refs_iterator__foreach_can_cancel(void)187 void test_refs_iterator__foreach_can_cancel(void)
188 {
189 	int cancel_after = 3;
190 	cl_git_fail_with(
191 		git_reference_foreach(repo, refs_foreach_cancel_cb, &cancel_after),
192 		-333);
193 	cl_assert_equal_i(0, cancel_after);
194 }
195 
refs_foreach_name_cb(const char * name,void * payload)196 static int refs_foreach_name_cb(const char *name, void *payload)
197 {
198 	git_vector *output = payload;
199 	cl_git_pass(git_vector_insert(output, git__strdup(name)));
200 	return 0;
201 }
202 
test_refs_iterator__foreach_name(void)203 void test_refs_iterator__foreach_name(void)
204 {
205 	git_vector output;
206 	size_t i;
207 	char *name;
208 
209 	cl_git_pass(git_vector_init(&output, 32, &git__strcmp_cb));
210 	cl_git_pass(
211 		git_reference_foreach_name(repo, refs_foreach_name_cb, &output));
212 
213 	git_vector_sort(&output);
214 
215 	git_vector_foreach(&output, i, name) {
216 		cl_assert(refnames[i] != NULL);
217 		cl_assert_equal_s(refnames[i], name);
218 		git__free(name);
219 	}
220 
221 	git_vector_free(&output);
222 }
223 
refs_foreach_name_cancel_cb(const char * name,void * payload)224 static int refs_foreach_name_cancel_cb(const char *name, void *payload)
225 {
226 	int *cancel_after = payload;
227 	if (!*cancel_after)
228 		return -333;
229 	GIT_UNUSED(name);
230 	(*cancel_after)--;
231 	return 0;
232 }
233 
test_refs_iterator__foreach_name_can_cancel(void)234 void test_refs_iterator__foreach_name_can_cancel(void)
235 {
236 	int cancel_after = 5;
237 	cl_git_fail_with(
238 		git_reference_foreach_name(
239 			repo, refs_foreach_name_cancel_cb, &cancel_after),
240 		-333);
241 	cl_assert_equal_i(0, cancel_after);
242 }
243 
test_refs_iterator__concurrent_delete(void)244 void test_refs_iterator__concurrent_delete(void)
245 {
246 	git_reference_iterator *iter;
247 	size_t full_count = 0, concurrent_count = 0;
248 	const char *name;
249 	int error;
250 
251 	cl_git_sandbox_cleanup();
252 	repo = cl_git_sandbox_init("testrepo");
253 
254 	cl_git_pass(git_reference_iterator_new(&iter, repo));
255 	while ((error = git_reference_next_name(&name, iter)) == 0) {
256 		full_count++;
257 	}
258 
259 	git_reference_iterator_free(iter);
260 	cl_assert_equal_i(GIT_ITEROVER, error);
261 
262 	cl_git_pass(git_reference_iterator_new(&iter, repo));
263 	while ((error = git_reference_next_name(&name, iter)) == 0) {
264 		cl_git_pass(git_reference_remove(repo, name));
265 		concurrent_count++;
266 	}
267 
268 	git_reference_iterator_free(iter);
269 	cl_assert_equal_i(GIT_ITEROVER, error);
270 
271 	cl_assert_equal_i(full_count, concurrent_count);
272 }
273