]> git.proxmox.com Git - libgit2.git/blob - tests/repo/iterator.c
Merge pull request #2763 from libgit2/cmn/local-proto-progress
[libgit2.git] / tests / repo / iterator.c
1 #include "clar_libgit2.h"
2 #include "iterator.h"
3 #include "repository.h"
4 #include "fileops.h"
5 #include <stdarg.h>
6
7 static git_repository *g_repo;
8
9 void test_repo_iterator__initialize(void)
10 {
11 }
12
13 void test_repo_iterator__cleanup(void)
14 {
15 cl_git_sandbox_cleanup();
16 g_repo = NULL;
17 }
18
19 static void expect_iterator_items(
20 git_iterator *i,
21 int expected_flat,
22 const char **expected_flat_paths,
23 int expected_total,
24 const char **expected_total_paths)
25 {
26 const git_index_entry *entry;
27 int count, error;
28 int no_trees = !(git_iterator_flags(i) & GIT_ITERATOR_INCLUDE_TREES);
29 bool v = false;
30
31 if (expected_flat < 0) { v = true; expected_flat = -expected_flat; }
32 if (expected_total < 0) { v = true; expected_total = -expected_total; }
33
34 if (v) fprintf(stderr, "== %s ==\n", no_trees ? "notrees" : "trees");
35
36 count = 0;
37
38 while (!git_iterator_advance(&entry, i)) {
39 if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode);
40
41 if (no_trees)
42 cl_assert(entry->mode != GIT_FILEMODE_TREE);
43
44 if (expected_flat_paths) {
45 const char *expect_path = expected_flat_paths[count];
46 size_t expect_len = strlen(expect_path);
47
48 cl_assert_equal_s(expect_path, entry->path);
49
50 if (expect_path[expect_len - 1] == '/')
51 cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode);
52 else
53 cl_assert(entry->mode != GIT_FILEMODE_TREE);
54 }
55
56 if (++count > expected_flat)
57 break;
58 }
59
60 cl_assert_equal_i(expected_flat, count);
61
62 cl_git_pass(git_iterator_reset(i, NULL, NULL));
63
64 count = 0;
65 cl_git_pass(git_iterator_current(&entry, i));
66
67 if (v) fprintf(stderr, "-- %s --\n", no_trees ? "notrees" : "trees");
68
69 while (entry != NULL) {
70 if (v) fprintf(stderr, " %s %07o\n", entry->path, (int)entry->mode);
71
72 if (no_trees)
73 cl_assert(entry->mode != GIT_FILEMODE_TREE);
74
75 if (expected_total_paths) {
76 const char *expect_path = expected_total_paths[count];
77 size_t expect_len = strlen(expect_path);
78
79 cl_assert_equal_s(expect_path, entry->path);
80
81 if (expect_path[expect_len - 1] == '/')
82 cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode);
83 else
84 cl_assert(entry->mode != GIT_FILEMODE_TREE);
85 }
86
87 if (entry->mode == GIT_FILEMODE_TREE) {
88 error = git_iterator_advance_into(&entry, i);
89
90 /* could return NOTFOUND if directory is empty */
91 cl_assert(!error || error == GIT_ENOTFOUND);
92
93 if (error == GIT_ENOTFOUND) {
94 error = git_iterator_advance(&entry, i);
95 cl_assert(!error || error == GIT_ITEROVER);
96 }
97 } else {
98 error = git_iterator_advance(&entry, i);
99 cl_assert(!error || error == GIT_ITEROVER);
100 }
101
102 if (++count > expected_total)
103 break;
104 }
105
106 cl_assert_equal_i(expected_total, count);
107 }
108
109 /* Index contents (including pseudotrees):
110 *
111 * 0: a 5: F 10: k/ 16: L/
112 * 1: B 6: g 11: k/1 17: L/1
113 * 2: c 7: H 12: k/a 18: L/a
114 * 3: D 8: i 13: k/B 19: L/B
115 * 4: e 9: J 14: k/c 20: L/c
116 * 15: k/D 21: L/D
117 *
118 * 0: B 5: L/ 11: a 16: k/
119 * 1: D 6: L/1 12: c 17: k/1
120 * 2: F 7: L/B 13: e 18: k/B
121 * 3: H 8: L/D 14: g 19: k/D
122 * 4: J 9: L/a 15: i 20: k/a
123 * 10: L/c 21: k/c
124 */
125
126 void test_repo_iterator__index(void)
127 {
128 git_iterator *i;
129 git_index *index;
130
131 g_repo = cl_git_sandbox_init("icase");
132
133 cl_git_pass(git_repository_index(&index, g_repo));
134
135 /* autoexpand with no tree entries for index */
136 cl_git_pass(git_iterator_for_index(&i, index, 0, NULL, NULL));
137 expect_iterator_items(i, 20, NULL, 20, NULL);
138 git_iterator_free(i);
139
140 /* auto expand with tree entries */
141 cl_git_pass(git_iterator_for_index(
142 &i, index, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
143 expect_iterator_items(i, 22, NULL, 22, NULL);
144 git_iterator_free(i);
145
146 /* no auto expand (implies trees included) */
147 cl_git_pass(git_iterator_for_index(
148 &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
149 expect_iterator_items(i, 12, NULL, 22, NULL);
150 git_iterator_free(i);
151
152 git_index_free(index);
153 }
154
155 void test_repo_iterator__index_icase(void)
156 {
157 git_iterator *i;
158 git_index *index;
159 int caps;
160
161 g_repo = cl_git_sandbox_init("icase");
162
163 cl_git_pass(git_repository_index(&index, g_repo));
164 caps = git_index_caps(index);
165
166 /* force case sensitivity */
167 cl_git_pass(git_index_set_caps(index, caps & ~GIT_INDEXCAP_IGNORE_CASE));
168
169 /* autoexpand with no tree entries over range */
170 cl_git_pass(git_iterator_for_index(&i, index, 0, "c", "k/D"));
171 expect_iterator_items(i, 7, NULL, 7, NULL);
172 git_iterator_free(i);
173
174 cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z"));
175 expect_iterator_items(i, 3, NULL, 3, NULL);
176 git_iterator_free(i);
177
178 /* auto expand with tree entries */
179 cl_git_pass(git_iterator_for_index(
180 &i, index, GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
181 expect_iterator_items(i, 8, NULL, 8, NULL);
182 git_iterator_free(i);
183 cl_git_pass(git_iterator_for_index(
184 &i, index, GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
185 expect_iterator_items(i, 4, NULL, 4, NULL);
186 git_iterator_free(i);
187
188 /* no auto expand (implies trees included) */
189 cl_git_pass(git_iterator_for_index(
190 &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
191 expect_iterator_items(i, 5, NULL, 8, NULL);
192 git_iterator_free(i);
193
194 cl_git_pass(git_iterator_for_index(
195 &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
196 expect_iterator_items(i, 1, NULL, 4, NULL);
197 git_iterator_free(i);
198
199 /* force case insensitivity */
200 cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE));
201
202 /* autoexpand with no tree entries over range */
203 cl_git_pass(git_iterator_for_index(&i, index, 0, "c", "k/D"));
204 expect_iterator_items(i, 13, NULL, 13, NULL);
205 git_iterator_free(i);
206
207 cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z"));
208 expect_iterator_items(i, 5, NULL, 5, NULL);
209 git_iterator_free(i);
210
211 /* auto expand with tree entries */
212 cl_git_pass(git_iterator_for_index(
213 &i, index, GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
214 expect_iterator_items(i, 14, NULL, 14, NULL);
215 git_iterator_free(i);
216
217 cl_git_pass(git_iterator_for_index(
218 &i, index, GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
219 expect_iterator_items(i, 6, NULL, 6, NULL);
220 git_iterator_free(i);
221
222 /* no auto expand (implies trees included) */
223 cl_git_pass(git_iterator_for_index(
224 &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
225 expect_iterator_items(i, 9, NULL, 14, NULL);
226 git_iterator_free(i);
227
228 cl_git_pass(git_iterator_for_index(
229 &i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
230 expect_iterator_items(i, 1, NULL, 6, NULL);
231 git_iterator_free(i);
232
233 cl_git_pass(git_index_set_caps(index, caps));
234 git_index_free(index);
235 }
236
237 void test_repo_iterator__tree(void)
238 {
239 git_iterator *i;
240 git_tree *head;
241
242 g_repo = cl_git_sandbox_init("icase");
243
244 cl_git_pass(git_repository_head_tree(&head, g_repo));
245
246 /* auto expand with no tree entries */
247 cl_git_pass(git_iterator_for_tree(&i, head, 0, NULL, NULL));
248 expect_iterator_items(i, 20, NULL, 20, NULL);
249 git_iterator_free(i);
250
251 /* auto expand with tree entries */
252 cl_git_pass(git_iterator_for_tree(
253 &i, head, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
254 expect_iterator_items(i, 22, NULL, 22, NULL);
255 git_iterator_free(i);
256
257 /* no auto expand (implies trees included) */
258 cl_git_pass(git_iterator_for_tree(
259 &i, head, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
260 expect_iterator_items(i, 12, NULL, 22, NULL);
261 git_iterator_free(i);
262
263 git_tree_free(head);
264 }
265
266 void test_repo_iterator__tree_icase(void)
267 {
268 git_iterator *i;
269 git_tree *head;
270 git_iterator_flag_t flag;
271
272 g_repo = cl_git_sandbox_init("icase");
273
274 cl_git_pass(git_repository_head_tree(&head, g_repo));
275
276 flag = GIT_ITERATOR_DONT_IGNORE_CASE;
277
278 /* auto expand with no tree entries */
279 cl_git_pass(git_iterator_for_tree(&i, head, flag, "c", "k/D"));
280 expect_iterator_items(i, 7, NULL, 7, NULL);
281 git_iterator_free(i);
282
283 cl_git_pass(git_iterator_for_tree(&i, head, flag, "k", "k/Z"));
284 expect_iterator_items(i, 3, NULL, 3, NULL);
285 git_iterator_free(i);
286
287 /* auto expand with tree entries */
288 cl_git_pass(git_iterator_for_tree(
289 &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
290 expect_iterator_items(i, 8, NULL, 8, NULL);
291 git_iterator_free(i);
292
293 cl_git_pass(git_iterator_for_tree(
294 &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
295 expect_iterator_items(i, 4, NULL, 4, NULL);
296 git_iterator_free(i);
297
298 /* no auto expand (implies trees included) */
299 cl_git_pass(git_iterator_for_tree(
300 &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
301 expect_iterator_items(i, 5, NULL, 8, NULL);
302 git_iterator_free(i);
303
304 cl_git_pass(git_iterator_for_tree(
305 &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
306 expect_iterator_items(i, 1, NULL, 4, NULL);
307 git_iterator_free(i);
308
309 flag = GIT_ITERATOR_IGNORE_CASE;
310
311 /* auto expand with no tree entries */
312 cl_git_pass(git_iterator_for_tree(&i, head, flag, "c", "k/D"));
313 expect_iterator_items(i, 13, NULL, 13, NULL);
314 git_iterator_free(i);
315
316 cl_git_pass(git_iterator_for_tree(&i, head, flag, "k", "k/Z"));
317 expect_iterator_items(i, 5, NULL, 5, NULL);
318 git_iterator_free(i);
319
320 /* auto expand with tree entries */
321 cl_git_pass(git_iterator_for_tree(
322 &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
323 expect_iterator_items(i, 14, NULL, 14, NULL);
324 git_iterator_free(i);
325
326 cl_git_pass(git_iterator_for_tree(
327 &i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
328 expect_iterator_items(i, 6, NULL, 6, NULL);
329 git_iterator_free(i);
330
331 /* no auto expand (implies trees included) */
332 cl_git_pass(git_iterator_for_tree(
333 &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
334 expect_iterator_items(i, 9, NULL, 14, NULL);
335 git_iterator_free(i);
336
337 cl_git_pass(git_iterator_for_tree(
338 &i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
339 expect_iterator_items(i, 1, NULL, 6, NULL);
340 git_iterator_free(i);
341
342 git_tree_free(head);
343 }
344
345 void test_repo_iterator__tree_more(void)
346 {
347 git_iterator *i;
348 git_tree *head;
349 static const char *expect_basic[] = {
350 "current_file",
351 "file_deleted",
352 "modified_file",
353 "staged_changes",
354 "staged_changes_file_deleted",
355 "staged_changes_modified_file",
356 "staged_delete_file_deleted",
357 "staged_delete_modified_file",
358 "subdir.txt",
359 "subdir/current_file",
360 "subdir/deleted_file",
361 "subdir/modified_file",
362 NULL,
363 };
364 static const char *expect_trees[] = {
365 "current_file",
366 "file_deleted",
367 "modified_file",
368 "staged_changes",
369 "staged_changes_file_deleted",
370 "staged_changes_modified_file",
371 "staged_delete_file_deleted",
372 "staged_delete_modified_file",
373 "subdir.txt",
374 "subdir/",
375 "subdir/current_file",
376 "subdir/deleted_file",
377 "subdir/modified_file",
378 NULL,
379 };
380 static const char *expect_noauto[] = {
381 "current_file",
382 "file_deleted",
383 "modified_file",
384 "staged_changes",
385 "staged_changes_file_deleted",
386 "staged_changes_modified_file",
387 "staged_delete_file_deleted",
388 "staged_delete_modified_file",
389 "subdir.txt",
390 "subdir/",
391 NULL
392 };
393
394 g_repo = cl_git_sandbox_init("status");
395
396 cl_git_pass(git_repository_head_tree(&head, g_repo));
397
398 /* auto expand with no tree entries */
399 cl_git_pass(git_iterator_for_tree(&i, head, 0, NULL, NULL));
400 expect_iterator_items(i, 12, expect_basic, 12, expect_basic);
401 git_iterator_free(i);
402
403 /* auto expand with tree entries */
404 cl_git_pass(git_iterator_for_tree(
405 &i, head, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
406 expect_iterator_items(i, 13, expect_trees, 13, expect_trees);
407 git_iterator_free(i);
408
409 /* no auto expand (implies trees included) */
410 cl_git_pass(git_iterator_for_tree(
411 &i, head, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
412 expect_iterator_items(i, 10, expect_noauto, 13, expect_trees);
413 git_iterator_free(i);
414
415 git_tree_free(head);
416 }
417
418 /* "b=name,t=name", blob_id, tree_id */
419 static void build_test_tree(
420 git_oid *out, git_repository *repo, const char *fmt, ...)
421 {
422 git_oid *id;
423 git_treebuilder *builder;
424 const char *scan = fmt, *next;
425 char type, delimiter;
426 git_filemode_t mode = GIT_FILEMODE_BLOB;
427 git_buf name = GIT_BUF_INIT;
428 va_list arglist;
429
430 cl_git_pass(git_treebuilder_create(&builder, repo, NULL)); /* start builder */
431
432 va_start(arglist, fmt);
433 while (*scan) {
434 switch (type = *scan++) {
435 case 't': case 'T': mode = GIT_FILEMODE_TREE; break;
436 case 'b': case 'B': mode = GIT_FILEMODE_BLOB; break;
437 default:
438 cl_assert(type == 't' || type == 'T' || type == 'b' || type == 'B');
439 }
440
441 delimiter = *scan++; /* read and skip delimiter */
442 for (next = scan; *next && *next != delimiter; ++next)
443 /* seek end */;
444 cl_git_pass(git_buf_set(&name, scan, (size_t)(next - scan)));
445 for (scan = next; *scan && (*scan == delimiter || *scan == ','); ++scan)
446 /* skip delimiter and optional comma */;
447
448 id = va_arg(arglist, git_oid *);
449
450 cl_git_pass(git_treebuilder_insert(NULL, builder, name.ptr, id, mode));
451 }
452 va_end(arglist);
453
454 cl_git_pass(git_treebuilder_write(out, builder));
455
456 git_treebuilder_free(builder);
457 git_buf_free(&name);
458 }
459
460 void test_repo_iterator__tree_case_conflicts_0(void)
461 {
462 const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6";
463 git_tree *tree;
464 git_oid blob_id, biga_id, littlea_id, tree_id;
465 git_iterator *i;
466 const char *expect_cs[] = {
467 "A/1.file", "A/3.file", "a/2.file", "a/4.file" };
468 const char *expect_ci[] = {
469 "A/1.file", "a/2.file", "A/3.file", "a/4.file" };
470 const char *expect_cs_trees[] = {
471 "A/", "A/1.file", "A/3.file", "a/", "a/2.file", "a/4.file" };
472 const char *expect_ci_trees[] = {
473 "A/", "A/1.file", "a/2.file", "A/3.file", "a/4.file" };
474
475 g_repo = cl_git_sandbox_init("icase");
476
477 cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */
478
479 /* create tree with: A/1.file, A/3.file, a/2.file, a/4.file */
480 build_test_tree(
481 &biga_id, g_repo, "b|1.file|,b|3.file|", &blob_id, &blob_id);
482 build_test_tree(
483 &littlea_id, g_repo, "b|2.file|,b|4.file|", &blob_id, &blob_id);
484 build_test_tree(
485 &tree_id, g_repo, "t|A|,t|a|", &biga_id, &littlea_id);
486
487 cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
488
489 cl_git_pass(git_iterator_for_tree(
490 &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
491 expect_iterator_items(i, 4, expect_cs, 4, expect_cs);
492 git_iterator_free(i);
493
494 cl_git_pass(git_iterator_for_tree(
495 &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
496 expect_iterator_items(i, 4, expect_ci, 4, expect_ci);
497 git_iterator_free(i);
498
499 cl_git_pass(git_iterator_for_tree(
500 &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE |
501 GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
502 expect_iterator_items(i, 6, expect_cs_trees, 6, expect_cs_trees);
503 git_iterator_free(i);
504
505 cl_git_pass(git_iterator_for_tree(
506 &i, tree, GIT_ITERATOR_IGNORE_CASE |
507 GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
508 expect_iterator_items(i, 5, expect_ci_trees, 5, expect_ci_trees);
509 git_iterator_free(i);
510
511 git_tree_free(tree);
512 }
513
514 void test_repo_iterator__tree_case_conflicts_1(void)
515 {
516 const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6";
517 git_tree *tree;
518 git_oid blob_id, Ab_id, biga_id, littlea_id, tree_id;
519 git_iterator *i;
520 const char *expect_cs[] = {
521 "A/a", "A/b/1", "A/c", "a/C", "a/a", "a/b" };
522 const char *expect_ci[] = {
523 "A/a", "a/b", "A/b/1", "A/c" };
524 const char *expect_cs_trees[] = {
525 "A/", "A/a", "A/b/", "A/b/1", "A/c", "a/", "a/C", "a/a", "a/b" };
526 const char *expect_ci_trees[] = {
527 "A/", "A/a", "a/b", "A/b/", "A/b/1", "A/c" };
528
529 g_repo = cl_git_sandbox_init("icase");
530
531 cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */
532
533 /* create: A/a A/b/1 A/c a/a a/b a/C */
534 build_test_tree(&Ab_id, g_repo, "b|1|", &blob_id);
535 build_test_tree(
536 &biga_id, g_repo, "b|a|,t|b|,b|c|", &blob_id, &Ab_id, &blob_id);
537 build_test_tree(
538 &littlea_id, g_repo, "b|a|,b|b|,b|C|", &blob_id, &blob_id, &blob_id);
539 build_test_tree(
540 &tree_id, g_repo, "t|A|,t|a|", &biga_id, &littlea_id);
541
542 cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
543
544 cl_git_pass(git_iterator_for_tree(
545 &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
546 expect_iterator_items(i, 6, expect_cs, 6, expect_cs);
547 git_iterator_free(i);
548
549 cl_git_pass(git_iterator_for_tree(
550 &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
551 expect_iterator_items(i, 4, expect_ci, 4, expect_ci);
552 git_iterator_free(i);
553
554 cl_git_pass(git_iterator_for_tree(
555 &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE |
556 GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
557 expect_iterator_items(i, 9, expect_cs_trees, 9, expect_cs_trees);
558 git_iterator_free(i);
559
560 cl_git_pass(git_iterator_for_tree(
561 &i, tree, GIT_ITERATOR_IGNORE_CASE |
562 GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
563 expect_iterator_items(i, 6, expect_ci_trees, 6, expect_ci_trees);
564 git_iterator_free(i);
565
566 git_tree_free(tree);
567 }
568
569 void test_repo_iterator__tree_case_conflicts_2(void)
570 {
571 const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6";
572 git_tree *tree;
573 git_oid blob_id, d1, d2, c1, c2, b1, b2, a1, a2, tree_id;
574 git_iterator *i;
575 const char *expect_cs[] = {
576 "A/B/C/D/16", "A/B/C/D/foo", "A/B/C/d/15", "A/B/C/d/FOO",
577 "A/B/c/D/14", "A/B/c/D/foo", "A/B/c/d/13", "A/B/c/d/FOO",
578 "A/b/C/D/12", "A/b/C/D/foo", "A/b/C/d/11", "A/b/C/d/FOO",
579 "A/b/c/D/10", "A/b/c/D/foo", "A/b/c/d/09", "A/b/c/d/FOO",
580 "a/B/C/D/08", "a/B/C/D/foo", "a/B/C/d/07", "a/B/C/d/FOO",
581 "a/B/c/D/06", "a/B/c/D/foo", "a/B/c/d/05", "a/B/c/d/FOO",
582 "a/b/C/D/04", "a/b/C/D/foo", "a/b/C/d/03", "a/b/C/d/FOO",
583 "a/b/c/D/02", "a/b/c/D/foo", "a/b/c/d/01", "a/b/c/d/FOO", };
584 const char *expect_ci[] = {
585 "a/b/c/d/01", "a/b/c/D/02", "a/b/C/d/03", "a/b/C/D/04",
586 "a/B/c/d/05", "a/B/c/D/06", "a/B/C/d/07", "a/B/C/D/08",
587 "A/b/c/d/09", "A/b/c/D/10", "A/b/C/d/11", "A/b/C/D/12",
588 "A/B/c/d/13", "A/B/c/D/14", "A/B/C/d/15", "A/B/C/D/16",
589 "A/B/C/D/foo", };
590 const char *expect_ci_trees[] = {
591 "A/", "A/B/", "A/B/C/", "A/B/C/D/",
592 "a/b/c/d/01", "a/b/c/D/02", "a/b/C/d/03", "a/b/C/D/04",
593 "a/B/c/d/05", "a/B/c/D/06", "a/B/C/d/07", "a/B/C/D/08",
594 "A/b/c/d/09", "A/b/c/D/10", "A/b/C/d/11", "A/b/C/D/12",
595 "A/B/c/d/13", "A/B/c/D/14", "A/B/C/d/15", "A/B/C/D/16",
596 "A/B/C/D/foo", };
597
598 g_repo = cl_git_sandbox_init("icase");
599
600 cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */
601
602 build_test_tree(&d1, g_repo, "b|16|,b|foo|", &blob_id, &blob_id);
603 build_test_tree(&d2, g_repo, "b|15|,b|FOO|", &blob_id, &blob_id);
604 build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
605 build_test_tree(&d1, g_repo, "b|14|,b|foo|", &blob_id, &blob_id);
606 build_test_tree(&d2, g_repo, "b|13|,b|FOO|", &blob_id, &blob_id);
607 build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
608 build_test_tree(&b1, g_repo, "t|C|,t|c|", &c1, &c2);
609
610 build_test_tree(&d1, g_repo, "b|12|,b|foo|", &blob_id, &blob_id);
611 build_test_tree(&d2, g_repo, "b|11|,b|FOO|", &blob_id, &blob_id);
612 build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
613 build_test_tree(&d1, g_repo, "b|10|,b|foo|", &blob_id, &blob_id);
614 build_test_tree(&d2, g_repo, "b|09|,b|FOO|", &blob_id, &blob_id);
615 build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
616 build_test_tree(&b2, g_repo, "t|C|,t|c|", &c1, &c2);
617
618 build_test_tree(&a1, g_repo, "t|B|,t|b|", &b1, &b2);
619
620 build_test_tree(&d1, g_repo, "b|08|,b|foo|", &blob_id, &blob_id);
621 build_test_tree(&d2, g_repo, "b|07|,b|FOO|", &blob_id, &blob_id);
622 build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
623 build_test_tree(&d1, g_repo, "b|06|,b|foo|", &blob_id, &blob_id);
624 build_test_tree(&d2, g_repo, "b|05|,b|FOO|", &blob_id, &blob_id);
625 build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
626 build_test_tree(&b1, g_repo, "t|C|,t|c|", &c1, &c2);
627
628 build_test_tree(&d1, g_repo, "b|04|,b|foo|", &blob_id, &blob_id);
629 build_test_tree(&d2, g_repo, "b|03|,b|FOO|", &blob_id, &blob_id);
630 build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
631 build_test_tree(&d1, g_repo, "b|02|,b|foo|", &blob_id, &blob_id);
632 build_test_tree(&d2, g_repo, "b|01|,b|FOO|", &blob_id, &blob_id);
633 build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
634 build_test_tree(&b2, g_repo, "t|C|,t|c|", &c1, &c2);
635
636 build_test_tree(&a2, g_repo, "t|B|,t|b|", &b1, &b2);
637
638 build_test_tree(&tree_id, g_repo, "t/A/,t/a/", &a1, &a2);
639
640 cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));
641
642 cl_git_pass(git_iterator_for_tree(
643 &i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
644 expect_iterator_items(i, 32, expect_cs, 32, expect_cs);
645 git_iterator_free(i);
646
647 cl_git_pass(git_iterator_for_tree(
648 &i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
649 expect_iterator_items(i, 17, expect_ci, 17, expect_ci);
650 git_iterator_free(i);
651
652 cl_git_pass(git_iterator_for_tree(
653 &i, tree, GIT_ITERATOR_IGNORE_CASE |
654 GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
655 expect_iterator_items(i, 21, expect_ci_trees, 21, expect_ci_trees);
656 git_iterator_free(i);
657
658 git_tree_free(tree);
659 }
660
661 void test_repo_iterator__workdir(void)
662 {
663 git_iterator *i;
664
665 g_repo = cl_git_sandbox_init("icase");
666
667 /* auto expand with no tree entries */
668 cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, 0, NULL, NULL));
669 expect_iterator_items(i, 20, NULL, 20, NULL);
670 git_iterator_free(i);
671
672 /* auto expand with tree entries */
673 cl_git_pass(git_iterator_for_workdir(
674 &i, g_repo, NULL, NULL, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
675 expect_iterator_items(i, 22, NULL, 22, NULL);
676 git_iterator_free(i);
677
678 /* no auto expand (implies trees included) */
679 cl_git_pass(git_iterator_for_workdir(
680 &i, g_repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
681 expect_iterator_items(i, 12, NULL, 22, NULL);
682 git_iterator_free(i);
683 }
684
685 void test_repo_iterator__workdir_icase(void)
686 {
687 git_iterator *i;
688 git_iterator_flag_t flag;
689
690 g_repo = cl_git_sandbox_init("icase");
691
692 flag = GIT_ITERATOR_DONT_IGNORE_CASE;
693
694 /* auto expand with no tree entries */
695 cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "c", "k/D"));
696 expect_iterator_items(i, 7, NULL, 7, NULL);
697 git_iterator_free(i);
698
699 cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "k", "k/Z"));
700 expect_iterator_items(i, 3, NULL, 3, NULL);
701 git_iterator_free(i);
702
703 /* auto expand with tree entries */
704 cl_git_pass(git_iterator_for_workdir(
705 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
706 expect_iterator_items(i, 8, NULL, 8, NULL);
707 git_iterator_free(i);
708
709 cl_git_pass(git_iterator_for_workdir(
710 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
711 expect_iterator_items(i, 4, NULL, 4, NULL);
712 git_iterator_free(i);
713
714 /* no auto expand (implies trees included) */
715 cl_git_pass(git_iterator_for_workdir(
716 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
717 expect_iterator_items(i, 5, NULL, 8, NULL);
718 git_iterator_free(i);
719
720 cl_git_pass(git_iterator_for_workdir(
721 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
722 expect_iterator_items(i, 1, NULL, 4, NULL);
723 git_iterator_free(i);
724
725 flag = GIT_ITERATOR_IGNORE_CASE;
726
727 /* auto expand with no tree entries */
728 cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "c", "k/D"));
729 expect_iterator_items(i, 13, NULL, 13, NULL);
730 git_iterator_free(i);
731
732 cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, flag, "k", "k/Z"));
733 expect_iterator_items(i, 5, NULL, 5, NULL);
734 git_iterator_free(i);
735
736 /* auto expand with tree entries */
737 cl_git_pass(git_iterator_for_workdir(
738 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
739 expect_iterator_items(i, 14, NULL, 14, NULL);
740 git_iterator_free(i);
741
742 cl_git_pass(git_iterator_for_workdir(
743 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
744 expect_iterator_items(i, 6, NULL, 6, NULL);
745 git_iterator_free(i);
746
747 /* no auto expand (implies trees included) */
748 cl_git_pass(git_iterator_for_workdir(
749 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
750 expect_iterator_items(i, 9, NULL, 14, NULL);
751 git_iterator_free(i);
752
753 cl_git_pass(git_iterator_for_workdir(
754 &i, g_repo, NULL, NULL, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
755 expect_iterator_items(i, 1, NULL, 6, NULL);
756 git_iterator_free(i);
757 }
758
759 static void build_workdir_tree(const char *root, int dirs, int subs)
760 {
761 int i, j;
762 char buf[64], sub[64];
763
764 for (i = 0; i < dirs; ++i) {
765 if (i % 2 == 0) {
766 p_snprintf(buf, sizeof(buf), "%s/dir%02d", root, i);
767 cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH));
768
769 p_snprintf(buf, sizeof(buf), "%s/dir%02d/file", root, i);
770 cl_git_mkfile(buf, buf);
771 buf[strlen(buf) - 5] = '\0';
772 } else {
773 p_snprintf(buf, sizeof(buf), "%s/DIR%02d", root, i);
774 cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH));
775 }
776
777 for (j = 0; j < subs; ++j) {
778 switch (j % 4) {
779 case 0: p_snprintf(sub, sizeof(sub), "%s/sub%02d", buf, j); break;
780 case 1: p_snprintf(sub, sizeof(sub), "%s/sUB%02d", buf, j); break;
781 case 2: p_snprintf(sub, sizeof(sub), "%s/Sub%02d", buf, j); break;
782 case 3: p_snprintf(sub, sizeof(sub), "%s/SUB%02d", buf, j); break;
783 }
784 cl_git_pass(git_futils_mkdir(sub, NULL, 0775, GIT_MKDIR_PATH));
785
786 if (j % 2 == 0) {
787 size_t sublen = strlen(sub);
788 memcpy(&sub[sublen], "/file", sizeof("/file"));
789 cl_git_mkfile(sub, sub);
790 sub[sublen] = '\0';
791 }
792 }
793 }
794 }
795
796 void test_repo_iterator__workdir_depth(void)
797 {
798 git_iterator *iter;
799
800 g_repo = cl_git_sandbox_init("icase");
801
802 build_workdir_tree("icase", 10, 10);
803 build_workdir_tree("icase/DIR01/sUB01", 50, 0);
804 build_workdir_tree("icase/dir02/sUB01", 50, 0);
805
806 /* auto expand with no tree entries */
807 cl_git_pass(git_iterator_for_workdir(&iter, g_repo, NULL, NULL, 0, NULL, NULL));
808 expect_iterator_items(iter, 125, NULL, 125, NULL);
809 git_iterator_free(iter);
810
811 /* auto expand with tree entries (empty dirs silently skipped) */
812 cl_git_pass(git_iterator_for_workdir(
813 &iter, g_repo, NULL, NULL, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
814 expect_iterator_items(iter, 337, NULL, 337, NULL);
815 git_iterator_free(iter);
816 }
817
818 void test_repo_iterator__fs(void)
819 {
820 git_iterator *i;
821 static const char *expect_base[] = {
822 "DIR01/Sub02/file",
823 "DIR01/sub00/file",
824 "current_file",
825 "dir00/Sub02/file",
826 "dir00/file",
827 "dir00/sub00/file",
828 "modified_file",
829 "new_file",
830 NULL,
831 };
832 static const char *expect_trees[] = {
833 "DIR01/",
834 "DIR01/SUB03/",
835 "DIR01/Sub02/",
836 "DIR01/Sub02/file",
837 "DIR01/sUB01/",
838 "DIR01/sub00/",
839 "DIR01/sub00/file",
840 "current_file",
841 "dir00/",
842 "dir00/SUB03/",
843 "dir00/Sub02/",
844 "dir00/Sub02/file",
845 "dir00/file",
846 "dir00/sUB01/",
847 "dir00/sub00/",
848 "dir00/sub00/file",
849 "modified_file",
850 "new_file",
851 NULL,
852 };
853 static const char *expect_noauto[] = {
854 "DIR01/",
855 "current_file",
856 "dir00/",
857 "modified_file",
858 "new_file",
859 NULL,
860 };
861
862 g_repo = cl_git_sandbox_init("status");
863
864 build_workdir_tree("status/subdir", 2, 4);
865
866 cl_git_pass(git_iterator_for_filesystem(
867 &i, "status/subdir", 0, NULL, NULL));
868 expect_iterator_items(i, 8, expect_base, 8, expect_base);
869 git_iterator_free(i);
870
871 cl_git_pass(git_iterator_for_filesystem(
872 &i, "status/subdir", GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
873 expect_iterator_items(i, 18, expect_trees, 18, expect_trees);
874 git_iterator_free(i);
875
876 cl_git_pass(git_iterator_for_filesystem(
877 &i, "status/subdir", GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
878 expect_iterator_items(i, 5, expect_noauto, 18, expect_trees);
879 git_iterator_free(i);
880
881 git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp);
882 git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp);
883 git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp);
884
885 cl_git_pass(git_iterator_for_filesystem(
886 &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
887 expect_iterator_items(i, 8, expect_base, 8, expect_base);
888 git_iterator_free(i);
889
890 cl_git_pass(git_iterator_for_filesystem(
891 &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE |
892 GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
893 expect_iterator_items(i, 18, expect_trees, 18, expect_trees);
894 git_iterator_free(i);
895
896 cl_git_pass(git_iterator_for_filesystem(
897 &i, "status/subdir", GIT_ITERATOR_IGNORE_CASE |
898 GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
899 expect_iterator_items(i, 5, expect_noauto, 18, expect_trees);
900 git_iterator_free(i);
901 }
902
903 void test_repo_iterator__fs2(void)
904 {
905 git_iterator *i;
906 static const char *expect_base[] = {
907 "heads/br2",
908 "heads/dir",
909 "heads/long-file-name",
910 "heads/master",
911 "heads/packed-test",
912 "heads/subtrees",
913 "heads/test",
914 "tags/e90810b",
915 "tags/foo/bar",
916 "tags/foo/foo/bar",
917 "tags/point_to_blob",
918 "tags/test",
919 NULL,
920 };
921
922 g_repo = cl_git_sandbox_init("testrepo");
923
924 cl_git_pass(git_iterator_for_filesystem(
925 &i, "testrepo/.git/refs", 0, NULL, NULL));
926 expect_iterator_items(i, 12, expect_base, 12, expect_base);
927 git_iterator_free(i);
928 }
929
930 void test_repo_iterator__fs_preserves_error(void)
931 {
932 git_iterator *i;
933 const git_index_entry *e;
934
935 if (!cl_is_chmod_supported())
936 return;
937
938 g_repo = cl_git_sandbox_init("empty_standard_repo");
939
940 cl_must_pass(p_mkdir("empty_standard_repo/r", 0777));
941 cl_git_mkfile("empty_standard_repo/r/a", "hello");
942 cl_must_pass(p_mkdir("empty_standard_repo/r/b", 0777));
943 cl_git_mkfile("empty_standard_repo/r/b/problem", "not me");
944 cl_must_pass(p_chmod("empty_standard_repo/r/b", 0000));
945 cl_must_pass(p_mkdir("empty_standard_repo/r/c", 0777));
946 cl_git_mkfile("empty_standard_repo/r/d", "final");
947
948 cl_git_pass(git_iterator_for_filesystem(
949 &i, "empty_standard_repo/r", 0, NULL, NULL));
950
951 cl_git_pass(git_iterator_advance(&e, i)); /* a */
952 cl_git_fail(git_iterator_advance(&e, i)); /* b */
953 cl_assert(giterr_last());
954 cl_assert(giterr_last()->message != NULL);
955 /* skip 'c/' empty directory */
956 cl_git_pass(git_iterator_advance(&e, i)); /* d */
957 cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&e, i));
958
959 cl_must_pass(p_chmod("empty_standard_repo/r/b", 0777));
960
961 git_iterator_free(i);
962 }
963
964 void test_repo_iterator__skips_fifos_and_such(void)
965 {
966 #ifndef GIT_WIN32
967 git_iterator *i;
968 const git_index_entry *e;
969
970 g_repo = cl_git_sandbox_init("empty_standard_repo");
971
972 cl_must_pass(p_mkdir("empty_standard_repo/dir", 0777));
973 cl_git_mkfile("empty_standard_repo/file", "not me");
974
975 cl_assert(!mkfifo("empty_standard_repo/fifo", 0777));
976 cl_assert(!access("empty_standard_repo/fifo", F_OK));
977
978 cl_git_pass(git_iterator_for_filesystem(
979 &i, "empty_standard_repo", GIT_ITERATOR_INCLUDE_TREES |
980 GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
981
982 cl_git_pass(git_iterator_advance(&e, i)); /* .git */
983 cl_assert(S_ISDIR(e->mode));
984 cl_git_pass(git_iterator_advance(&e, i)); /* dir */
985 cl_assert(S_ISDIR(e->mode));
986 /* skips fifo */
987 cl_git_pass(git_iterator_advance(&e, i)); /* file */
988 cl_assert(S_ISREG(e->mode));
989
990 cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&e, i));
991
992 git_iterator_free(i);
993 #endif
994 }