]> git.proxmox.com Git - libgit2.git/blob - tests/fetchhead/nonetwork.c
aadcc788027495dd5ef88795220467a5ac670465
[libgit2.git] / tests / fetchhead / nonetwork.c
1 #include "clar_libgit2.h"
2
3 #include "futils.h"
4 #include "fetchhead.h"
5
6 #include "fetchhead_data.h"
7
8 #define DO_LOCAL_TEST 0
9
10 static git_repository *g_repo;
11
12 void test_fetchhead_nonetwork__initialize(void)
13 {
14 g_repo = NULL;
15 }
16
17 static void cleanup_repository(void *path)
18 {
19 if (g_repo) {
20 git_repository_free(g_repo);
21 g_repo = NULL;
22 }
23
24 cl_fixture_cleanup((const char *)path);
25 }
26
27 static void populate_fetchhead(git_vector *out, git_repository *repo)
28 {
29 git_fetchhead_ref *fetchhead_ref;
30 git_oid oid;
31
32 cl_git_pass(git_oid_fromstr(&oid,
33 "49322bb17d3acc9146f98c97d078513228bbf3c0"));
34 cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 1,
35 "refs/heads/master",
36 "https://github.com/libgit2/TestGitRepository"));
37 cl_git_pass(git_vector_insert(out, fetchhead_ref));
38
39 cl_git_pass(git_oid_fromstr(&oid,
40 "0966a434eb1a025db6b71485ab63a3bfbea520b6"));
41 cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0,
42 "refs/heads/first-merge",
43 "https://github.com/libgit2/TestGitRepository"));
44 cl_git_pass(git_vector_insert(out, fetchhead_ref));
45
46 cl_git_pass(git_oid_fromstr(&oid,
47 "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1"));
48 cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0,
49 "refs/heads/no-parent",
50 "https://github.com/libgit2/TestGitRepository"));
51 cl_git_pass(git_vector_insert(out, fetchhead_ref));
52
53 cl_git_pass(git_oid_fromstr(&oid,
54 "d96c4e80345534eccee5ac7b07fc7603b56124cb"));
55 cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0,
56 "refs/tags/annotated_tag",
57 "https://github.com/libgit2/TestGitRepository"));
58 cl_git_pass(git_vector_insert(out, fetchhead_ref));
59
60 cl_git_pass(git_oid_fromstr(&oid,
61 "55a1a760df4b86a02094a904dfa511deb5655905"));
62 cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0,
63 "refs/tags/blob",
64 "https://github.com/libgit2/TestGitRepository"));
65 cl_git_pass(git_vector_insert(out, fetchhead_ref));
66
67 cl_git_pass(git_oid_fromstr(&oid,
68 "8f50ba15d49353813cc6e20298002c0d17b0a9ee"));
69 cl_git_pass(git_fetchhead_ref_create(&fetchhead_ref, &oid, 0,
70 "refs/tags/commit_tree",
71 "https://github.com/libgit2/TestGitRepository"));
72 cl_git_pass(git_vector_insert(out, fetchhead_ref));
73
74 cl_git_pass(git_fetchhead_write(repo, out));
75 }
76
77 void test_fetchhead_nonetwork__write(void)
78 {
79 git_vector fetchhead_vector = GIT_VECTOR_INIT;
80 git_fetchhead_ref *fetchhead_ref;
81 git_str fetchhead_buf = GIT_STR_INIT;
82 int equals = 0;
83 size_t i;
84
85 cl_git_pass(git_vector_init(&fetchhead_vector, 6, NULL));
86
87 cl_set_cleanup(&cleanup_repository, "./test1");
88 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
89
90 populate_fetchhead(&fetchhead_vector, g_repo);
91
92 cl_git_pass(git_futils_readbuffer(&fetchhead_buf,
93 "./test1/.git/FETCH_HEAD"));
94
95 equals = (strcmp(fetchhead_buf.ptr, FETCH_HEAD_WILDCARD_DATA_LOCAL) == 0);
96
97 git_str_dispose(&fetchhead_buf);
98
99 git_vector_foreach(&fetchhead_vector, i, fetchhead_ref) {
100 git_fetchhead_ref_free(fetchhead_ref);
101 }
102
103 git_vector_free(&fetchhead_vector);
104
105 cl_assert(equals);
106 }
107
108 typedef struct {
109 git_vector *fetchhead_vector;
110 size_t idx;
111 } fetchhead_ref_cb_data;
112
113 static int fetchhead_ref_cb(const char *name, const char *url,
114 const git_oid *oid, unsigned int is_merge, void *payload)
115 {
116 fetchhead_ref_cb_data *cb_data = payload;
117 git_fetchhead_ref *expected;
118
119 cl_assert(payload);
120
121 expected = git_vector_get(cb_data->fetchhead_vector, cb_data->idx);
122
123 cl_assert_equal_oid(&expected->oid, oid);
124 cl_assert(expected->is_merge == is_merge);
125
126 if (expected->ref_name)
127 cl_assert_equal_s(expected->ref_name, name);
128 else
129 cl_assert(name == NULL);
130
131 if (expected->remote_url)
132 cl_assert_equal_s(expected->remote_url, url);
133 else
134 cl_assert(url == NULL);
135
136 cb_data->idx++;
137
138 return 0;
139 }
140
141 void test_fetchhead_nonetwork__read(void)
142 {
143 git_vector fetchhead_vector = GIT_VECTOR_INIT;
144 git_fetchhead_ref *fetchhead_ref;
145 fetchhead_ref_cb_data cb_data;
146 size_t i;
147
148 memset(&cb_data, 0x0, sizeof(fetchhead_ref_cb_data));
149
150 cl_set_cleanup(&cleanup_repository, "./test1");
151 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
152
153 populate_fetchhead(&fetchhead_vector, g_repo);
154
155 cb_data.fetchhead_vector = &fetchhead_vector;
156
157 cl_git_pass(git_repository_fetchhead_foreach(g_repo, fetchhead_ref_cb, &cb_data));
158
159 git_vector_foreach(&fetchhead_vector, i, fetchhead_ref) {
160 git_fetchhead_ref_free(fetchhead_ref);
161 }
162
163 git_vector_free(&fetchhead_vector);
164 }
165
166 static int read_old_style_cb(const char *name, const char *url,
167 const git_oid *oid, unsigned int is_merge, void *payload)
168 {
169 git_oid expected;
170
171 GIT_UNUSED(payload);
172
173 git_oid_fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0");
174
175 cl_assert(name == NULL);
176 cl_assert(url == NULL);
177 cl_assert_equal_oid(&expected, oid);
178 cl_assert(is_merge == 1);
179
180 return 0;
181 }
182
183 void test_fetchhead_nonetwork__read_old_style(void)
184 {
185 cl_set_cleanup(&cleanup_repository, "./test1");
186 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
187
188 cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\n");
189
190 cl_git_pass(git_repository_fetchhead_foreach(g_repo, read_old_style_cb, NULL));
191 }
192
193 static int read_type_missing(const char *ref_name, const char *remote_url,
194 const git_oid *oid, unsigned int is_merge, void *payload)
195 {
196 git_oid expected;
197
198 GIT_UNUSED(payload);
199
200 git_oid_fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0");
201
202 cl_assert_equal_s("name", ref_name);
203 cl_assert_equal_s("remote_url", remote_url);
204 cl_assert_equal_oid(&expected, oid);
205 cl_assert(is_merge == 0);
206
207 return 0;
208 }
209
210 void test_fetchhead_nonetwork__type_missing(void)
211 {
212 cl_set_cleanup(&cleanup_repository, "./test1");
213 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
214
215 cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\t'name' of remote_url\n");
216
217 cl_git_pass(git_repository_fetchhead_foreach(g_repo, read_type_missing, NULL));
218 }
219
220 static int read_name_missing(const char *ref_name, const char *remote_url,
221 const git_oid *oid, unsigned int is_merge, void *payload)
222 {
223 git_oid expected;
224
225 GIT_UNUSED(payload);
226
227 git_oid_fromstr(&expected, "49322bb17d3acc9146f98c97d078513228bbf3c0");
228
229 cl_assert(ref_name == NULL);
230 cl_assert_equal_s("remote_url", remote_url);
231 cl_assert_equal_oid(&expected, oid);
232 cl_assert(is_merge == 0);
233
234 return 0;
235 }
236
237 void test_fetchhead_nonetwork__name_missing(void)
238 {
239 cl_set_cleanup(&cleanup_repository, "./test1");
240 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
241
242 cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\tremote_url\n");
243
244 cl_git_pass(git_repository_fetchhead_foreach(g_repo, read_name_missing, NULL));
245 }
246
247 static int read_noop(const char *ref_name, const char *remote_url,
248 const git_oid *oid, unsigned int is_merge, void *payload)
249 {
250 GIT_UNUSED(ref_name);
251 GIT_UNUSED(remote_url);
252 GIT_UNUSED(oid);
253 GIT_UNUSED(is_merge);
254 GIT_UNUSED(payload);
255
256 return 0;
257 }
258
259 void test_fetchhead_nonetwork__nonexistent(void)
260 {
261 int error;
262
263 cl_set_cleanup(&cleanup_repository, "./test1");
264 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
265
266 cl_git_fail((error = git_repository_fetchhead_foreach(g_repo, read_noop, NULL)));
267 cl_assert(error == GIT_ENOTFOUND);
268 }
269
270 void test_fetchhead_nonetwork__invalid_unterminated_last_line(void)
271 {
272 cl_set_cleanup(&cleanup_repository, "./test1");
273 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
274
275 cl_git_rewritefile("./test1/.git/FETCH_HEAD", "unterminated");
276 cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL));
277 }
278
279 void test_fetchhead_nonetwork__invalid_oid(void)
280 {
281 cl_set_cleanup(&cleanup_repository, "./test1");
282 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
283
284 cl_git_rewritefile("./test1/.git/FETCH_HEAD", "shortoid\n");
285 cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL));
286 }
287
288 void test_fetchhead_nonetwork__invalid_for_merge(void)
289 {
290 cl_set_cleanup(&cleanup_repository, "./test1");
291 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
292
293 cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tinvalid-merge\t\n");
294 cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL));
295
296 cl_assert(git__prefixcmp(git_error_last()->message, "invalid for-merge") == 0);
297 }
298
299 void test_fetchhead_nonetwork__invalid_description(void)
300 {
301 cl_set_cleanup(&cleanup_repository, "./test1");
302 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
303
304 cl_git_rewritefile("./test1/.git/FETCH_HEAD", "49322bb17d3acc9146f98c97d078513228bbf3c0\tnot-for-merge\n");
305 cl_git_fail(git_repository_fetchhead_foreach(g_repo, read_noop, NULL));
306
307 cl_assert(git__prefixcmp(git_error_last()->message, "invalid description") == 0);
308 }
309
310 static int assert_master_for_merge(const char *ref, const char *url, const git_oid *id, unsigned int is_merge, void *data)
311 {
312 GIT_UNUSED(url);
313 GIT_UNUSED(id);
314 GIT_UNUSED(data);
315
316 if (!strcmp("refs/heads/master", ref) && !is_merge)
317 return -1;
318
319 return 0;
320 }
321
322 static int assert_none_for_merge(const char *ref, const char *url, const git_oid *id, unsigned int is_merge, void *data)
323 {
324 GIT_UNUSED(ref);
325 GIT_UNUSED(url);
326 GIT_UNUSED(id);
327 GIT_UNUSED(data);
328
329 return is_merge ? -1 : 0;
330 }
331
332 void test_fetchhead_nonetwork__unborn_with_upstream(void)
333 {
334 git_repository *repo;
335 git_remote *remote;
336
337 /* Create an empty repo to clone from */
338 cl_set_cleanup(&cleanup_repository, "./test1");
339 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
340 cl_set_cleanup(&cleanup_repository, "./repowithunborn");
341 cl_git_pass(git_clone(&repo, "./test1", "./repowithunborn", NULL));
342
343 /* Simulate someone pushing to it by changing to one that has stuff */
344 cl_git_pass(git_remote_set_url(repo, "origin", cl_fixture("testrepo.git")));
345 cl_git_pass(git_remote_lookup(&remote, repo, "origin"));
346
347 cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL));
348 git_remote_free(remote);
349
350 cl_git_pass(git_repository_fetchhead_foreach(repo, assert_master_for_merge, NULL));
351
352 git_repository_free(repo);
353 cl_fixture_cleanup("./repowithunborn");
354 }
355
356 void test_fetchhead_nonetwork__fetch_into_repo_with_symrefs(void)
357 {
358 git_repository *repo;
359 git_remote *remote;
360 git_reference *symref;
361
362 repo = cl_git_sandbox_init("empty_standard_repo");
363
364 /*
365 * Testing for a specific constellation where the repository has at
366 * least one symbolic reference in its refdb.
367 */
368 cl_git_pass(git_reference_symbolic_create(&symref, repo, "refs/heads/symref", "refs/heads/master", 0, NULL));
369
370 cl_git_pass(git_remote_set_url(repo, "origin", cl_fixture("testrepo.git")));
371 cl_git_pass(git_remote_lookup(&remote, repo, "origin"));
372 cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL));
373
374 git_remote_free(remote);
375 git_reference_free(symref);
376 cl_git_sandbox_cleanup();
377 }
378
379 void test_fetchhead_nonetwork__fetch_into_repo_with_invalid_head(void)
380 {
381 git_remote *remote;
382 char *strings[] = { "refs/heads/*:refs/remotes/origin/*" };
383 git_strarray refspecs = { strings, 1 };
384
385 cl_set_cleanup(&cleanup_repository, "./test1");
386 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
387
388 /* HEAD pointing to nonexistent branch */
389 cl_git_rewritefile("./test1/.git/HEAD", "ref: refs/heads/\n");
390
391 cl_git_pass(git_remote_create_anonymous(&remote, g_repo, cl_fixture("testrepo.git")));
392 cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, NULL));
393 cl_git_pass(git_repository_fetchhead_foreach(g_repo, assert_none_for_merge, NULL));
394
395 git_remote_free(remote);
396 }
397
398 void test_fetchhead_nonetwork__quote_in_branch_name(void)
399 {
400 cl_set_cleanup(&cleanup_repository, "./test1");
401 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
402
403 cl_git_rewritefile("./test1/.git/FETCH_HEAD", FETCH_HEAD_QUOTE_DATA);
404 cl_git_pass(git_repository_fetchhead_foreach(g_repo, read_noop, NULL));
405 }
406
407 static bool found_master;
408 static bool found_haacked;
409 static bool find_master_haacked_called;
410
411 static int find_master_haacked(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
412 {
413 GIT_UNUSED(remote_url);
414 GIT_UNUSED(oid);
415 GIT_UNUSED(payload);
416
417 find_master_haacked_called = true;
418
419 if (!strcmp("refs/heads/master", ref_name)) {
420 cl_assert(is_merge);
421 found_master = true;
422 }
423 if (!strcmp("refs/heads/haacked", ref_name)) {
424 cl_assert(is_merge);
425 found_haacked = true;
426 }
427
428 return 0;
429 }
430
431 void test_fetchhead_nonetwork__create_when_refpecs_given(void)
432 {
433 git_remote *remote;
434 git_str path = GIT_STR_INIT;
435 char *refspec1 = "refs/heads/master";
436 char *refspec2 = "refs/heads/haacked";
437 char *refspecs[] = { refspec1, refspec2 };
438 git_strarray specs = {
439 refspecs,
440 2,
441 };
442
443 cl_set_cleanup(&cleanup_repository, "./test1");
444 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
445
446 cl_git_pass(git_str_joinpath(&path, git_repository_path(g_repo), "FETCH_HEAD"));
447 cl_git_pass(git_remote_create(&remote, g_repo, "origin", cl_fixture("testrepo.git")));
448
449 cl_assert(!git_fs_path_exists(path.ptr));
450 cl_git_pass(git_remote_fetch(remote, &specs, NULL, NULL));
451 cl_assert(git_fs_path_exists(path.ptr));
452
453 cl_git_pass(git_repository_fetchhead_foreach(g_repo, find_master_haacked, NULL));
454 cl_assert(find_master_haacked_called);
455 cl_assert(found_master);
456 cl_assert(found_haacked);
457
458 git_remote_free(remote);
459 git_str_dispose(&path);
460 }
461
462 static bool count_refs_called;
463 struct prefix_count {
464 const char *prefix;
465 int count;
466 int expected;
467 };
468
469 static int count_refs(const char *ref_name, const char *remote_url, const git_oid *oid, unsigned int is_merge, void *payload)
470 {
471 int i;
472 struct prefix_count *prefix_counts = (struct prefix_count *) payload;
473
474 GIT_UNUSED(remote_url);
475 GIT_UNUSED(oid);
476 GIT_UNUSED(is_merge);
477
478 count_refs_called = true;
479
480 for (i = 0; prefix_counts[i].prefix; i++) {
481 if (!git__prefixcmp(ref_name, prefix_counts[i].prefix))
482 prefix_counts[i].count++;
483 }
484
485 return 0;
486 }
487
488 void test_fetchhead_nonetwork__create_with_multiple_refspecs(void)
489 {
490 git_remote *remote;
491 git_str path = GIT_STR_INIT;
492
493 cl_set_cleanup(&cleanup_repository, "./test1");
494 cl_git_pass(git_repository_init(&g_repo, "./test1", 0));
495
496 cl_git_pass(git_remote_create(&remote, g_repo, "origin", cl_fixture("testrepo.git")));
497 git_remote_free(remote);
498 cl_git_pass(git_remote_add_fetch(g_repo, "origin", "+refs/notes/*:refs/origin/notes/*"));
499 /* Pick up the new refspec */
500 cl_git_pass(git_remote_lookup(&remote, g_repo, "origin"));
501
502 cl_git_pass(git_str_joinpath(&path, git_repository_path(g_repo), "FETCH_HEAD"));
503 cl_assert(!git_fs_path_exists(path.ptr));
504 cl_git_pass(git_remote_fetch(remote, NULL, NULL, NULL));
505 cl_assert(git_fs_path_exists(path.ptr));
506
507 {
508 int i;
509 struct prefix_count prefix_counts[] = {
510 {"refs/notes/", 0, 1},
511 {"refs/heads/", 0, 13},
512 {"refs/tags/", 0, 7},
513 {NULL, 0, 0},
514 };
515
516 cl_git_pass(git_repository_fetchhead_foreach(g_repo, count_refs, &prefix_counts));
517 cl_assert(count_refs_called);
518 for (i = 0; prefix_counts[i].prefix; i++)
519 cl_assert_equal_i(prefix_counts[i].expected, prefix_counts[i].count);
520 }
521
522 git_remote_free(remote);
523 git_str_dispose(&path);
524 }
525
526 void test_fetchhead_nonetwork__credentials_are_stripped(void)
527 {
528 git_fetchhead_ref *ref;
529 git_oid oid;
530
531 cl_git_pass(git_oid_fromstr(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0"));
532 cl_git_pass(git_fetchhead_ref_create(&ref, &oid, 0,
533 "refs/tags/commit_tree", "http://foo:bar@github.com/libgit2/TestGitRepository"));
534 cl_assert_equal_s(ref->remote_url, "http://github.com/libgit2/TestGitRepository");
535 git_fetchhead_ref_free(ref);
536
537 cl_git_pass(git_oid_fromstr(&oid, "49322bb17d3acc9146f98c97d078513228bbf3c0"));
538 cl_git_pass(git_fetchhead_ref_create(&ref, &oid, 0,
539 "refs/tags/commit_tree", "https://foo:bar@github.com/libgit2/TestGitRepository"));
540 cl_assert_equal_s(ref->remote_url, "https://github.com/libgit2/TestGitRepository");
541 git_fetchhead_ref_free(ref);
542 }