iterator.c 28.6 KB
Newer Older
1 2 3
#include "clar_libgit2.h"
#include "iterator.h"
#include "repository.h"
4
#include "fileops.h"
5
#include <stdarg.h>
6 7 8 9 10 11 12 13 14 15 16 17 18 19

static git_repository *g_repo;

void test_repo_iterator__initialize(void)
{
}

void test_repo_iterator__cleanup(void)
{
	cl_git_sandbox_cleanup();
	g_repo = NULL;
}

static void expect_iterator_items(
20 21 22 23 24
	git_iterator *i,
	int expected_flat,
	const char **expected_flat_paths,
	int expected_total,
	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 30 31 32
	bool v = false;

	if (expected_flat < 0) { v = true; expected_flat = -expected_flat; }
	if (expected_total < 0) { v = true; expected_total = -expected_total; }
33

34 35
	if (v) fprintf(stderr, "== %s ==\n", no_trees ? "notrees" : "trees");

36 37 38
	count = 0;

	while (!git_iterator_advance(&entry, i)) {
39 40
		if (v) fprintf(stderr, "  %s %07o\n", entry->path, (int)entry->mode);

41 42 43
		if (no_trees)
			cl_assert(entry->mode != GIT_FILEMODE_TREE);

44 45 46 47 48 49 50 51 52 53 54
		if (expected_flat_paths) {
			const char *expect_path = expected_flat_paths[count];
			size_t expect_len = strlen(expect_path);

			cl_assert_equal_s(expect_path, entry->path);

			if (expect_path[expect_len - 1] == '/')
				cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode);
			else
				cl_assert(entry->mode != GIT_FILEMODE_TREE);
		}
55

56
		if (++count > expected_flat)
57 58 59 60 61 62 63 64 65 66
			break;
	}

	cl_assert_equal_i(expected_flat, count);

	cl_git_pass(git_iterator_reset(i, NULL, NULL));

	count = 0;
	cl_git_pass(git_iterator_current(&entry, i));

67 68
	if (v) fprintf(stderr, "-- %s --\n", no_trees ? "notrees" : "trees");

69
	while (entry != NULL) {
70 71
		if (v) fprintf(stderr, "  %s %07o\n", entry->path, (int)entry->mode);

72 73 74
		if (no_trees)
			cl_assert(entry->mode != GIT_FILEMODE_TREE);

75 76 77 78 79 80 81 82 83 84 85
		if (expected_total_paths) {
			const char *expect_path = expected_total_paths[count];
			size_t expect_len = strlen(expect_path);

			cl_assert_equal_s(expect_path, entry->path);

			if (expect_path[expect_len - 1] == '/')
				cl_assert_equal_i(GIT_FILEMODE_TREE, entry->mode);
			else
				cl_assert(entry->mode != GIT_FILEMODE_TREE);
		}
86

87 88 89 90 91 92
		if (entry->mode == GIT_FILEMODE_TREE) {
			error = git_iterator_advance_into(&entry, i);

			/* could return NOTFOUND if directory is empty */
			cl_assert(!error || error == GIT_ENOTFOUND);

93 94 95 96 97 98 99 100
			if (error == GIT_ENOTFOUND) {
				error = git_iterator_advance(&entry, i);
				cl_assert(!error || error == GIT_ITEROVER);
			}
		} else {
			error = git_iterator_advance(&entry, i);
			cl_assert(!error || error == GIT_ITEROVER);
		}
101

102
		if (++count > expected_total)
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
			break;
	}

	cl_assert_equal_i(expected_total, count);
}

/* Index contents (including pseudotrees):
 *
 * 0: a     5: F     10: k/      16: L/
 * 1: B     6: g     11: k/1     17: L/1
 * 2: c     7: H     12: k/a     18: L/a
 * 3: D     8: i     13: k/B     19: L/B
 * 4: e     9: J     14: k/c     20: L/c
 *                   15: k/D     21: L/D
 *
 * 0: B     5: L/    11: a       16: k/
 * 1: D     6: L/1   12: c       17: k/1
 * 2: F     7: L/B   13: e       18: k/B
 * 3: H     8: L/D   14: g       19: k/D
 * 4: J     9: L/a   15: i       20: k/a
 *         10: L/c               21: k/c
 */

void test_repo_iterator__index(void)
{
	git_iterator *i;
	git_index *index;

131 132
	g_repo = cl_git_sandbox_init("icase");

133 134
	cl_git_pass(git_repository_index(&index, g_repo));

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 139
	git_iterator_free(i);

140 141 142
	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
143
	expect_iterator_items(i, 22, NULL, 22, NULL);
144 145 146 147 148
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
149
	expect_iterator_items(i, 12, NULL, 22, NULL);
150 151
	git_iterator_free(i);

152 153 154 155 156 157 158
	git_index_free(index);
}

void test_repo_iterator__index_icase(void)
{
	git_iterator *i;
	git_index *index;
Russell Belfer committed
159
	int caps;
160

161 162
	g_repo = cl_git_sandbox_init("icase");

163 164 165 166 167 168
	cl_git_pass(git_repository_index(&index, g_repo));
	caps = git_index_caps(index);

	/* force case sensitivity */
	cl_git_pass(git_index_set_caps(index, caps & ~GIT_INDEXCAP_IGNORE_CASE));

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 173 174
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z"));
175
	expect_iterator_items(i, 3, NULL, 3, NULL);
176 177
	git_iterator_free(i);

178 179 180
	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
181
	expect_iterator_items(i, 8, NULL, 8, NULL);
182 183 184
	git_iterator_free(i);
	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
185
	expect_iterator_items(i, 4, NULL, 4, NULL);
186 187 188 189 190
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
191
	expect_iterator_items(i, 5, NULL, 8, NULL);
192 193 194 195
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
196
	expect_iterator_items(i, 1, NULL, 4, NULL);
197 198
	git_iterator_free(i);

199 200 201
	/* force case insensitivity */
	cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE));

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 206 207
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_index(&i, index, 0, "k", "k/Z"));
208
	expect_iterator_items(i, 5, NULL, 5, NULL);
209 210
	git_iterator_free(i);

211 212 213
	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
214
	expect_iterator_items(i, 14, NULL, 14, NULL);
215 216 217 218
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
219
	expect_iterator_items(i, 6, NULL, 6, NULL);
220 221 222 223 224
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
225
	expect_iterator_items(i, 9, NULL, 14, NULL);
226 227 228 229
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_index(
		&i, index, GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
230
	expect_iterator_items(i, 1, NULL, 6, NULL);
231 232
	git_iterator_free(i);

233 234 235 236 237 238 239 240 241
	cl_git_pass(git_index_set_caps(index, caps));
	git_index_free(index);
}

void test_repo_iterator__tree(void)
{
	git_iterator *i;
	git_tree *head;

242 243
	g_repo = cl_git_sandbox_init("icase");

244 245
	cl_git_pass(git_repository_head_tree(&head, g_repo));

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 250
	git_iterator_free(i);

251 252 253
	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_tree(
		&i, head, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
254
	expect_iterator_items(i, 22, NULL, 22, NULL);
255 256 257 258 259
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_tree(
		&i, head, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
260
	expect_iterator_items(i, 12, NULL, 22, NULL);
261 262
	git_iterator_free(i);

263 264 265 266 267 268 269 270 271
	git_tree_free(head);
}

void test_repo_iterator__tree_icase(void)
{
	git_iterator *i;
	git_tree *head;
	git_iterator_flag_t flag;

272 273
	g_repo = cl_git_sandbox_init("icase");

274 275 276 277
	cl_git_pass(git_repository_head_tree(&head, g_repo));

	flag = GIT_ITERATOR_DONT_IGNORE_CASE;

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 282 283
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(&i, head, flag, "k", "k/Z"));
284
	expect_iterator_items(i, 3, NULL, 3, NULL);
285 286
	git_iterator_free(i);

287 288 289
	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
290
	expect_iterator_items(i, 8, NULL, 8, NULL);
291 292 293 294
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
295
	expect_iterator_items(i, 4, NULL, 4, NULL);
296 297 298 299 300
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
301
	expect_iterator_items(i, 5, NULL, 8, NULL);
302 303 304 305
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
306
	expect_iterator_items(i, 1, NULL, 4, NULL);
307 308
	git_iterator_free(i);

309 310
	flag = GIT_ITERATOR_IGNORE_CASE;

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 315 316
	git_iterator_free(i);

	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 321 322

	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
323
	expect_iterator_items(i, 14, NULL, 14, NULL);
324 325 326 327
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
328
	expect_iterator_items(i, 6, NULL, 6, NULL);
329 330 331 332 333
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
334
	expect_iterator_items(i, 9, NULL, 14, NULL);
335 336 337 338
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, head, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
339 340
	expect_iterator_items(i, 1, NULL, 6, NULL);
	git_iterator_free(i);
341 342

	git_tree_free(head);
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
}

void test_repo_iterator__tree_more(void)
{
	git_iterator *i;
	git_tree *head;
	static const char *expect_basic[] = {
		"current_file",
		"file_deleted",
		"modified_file",
		"staged_changes",
		"staged_changes_file_deleted",
		"staged_changes_modified_file",
		"staged_delete_file_deleted",
		"staged_delete_modified_file",
		"subdir.txt",
		"subdir/current_file",
		"subdir/deleted_file",
		"subdir/modified_file",
		NULL,
	};
	static const char *expect_trees[] = {
		"current_file",
		"file_deleted",
		"modified_file",
		"staged_changes",
		"staged_changes_file_deleted",
		"staged_changes_modified_file",
		"staged_delete_file_deleted",
		"staged_delete_modified_file",
		"subdir.txt",
		"subdir/",
		"subdir/current_file",
		"subdir/deleted_file",
		"subdir/modified_file",
		NULL,
	};
	static const char *expect_noauto[] = {
		"current_file",
		"file_deleted",
		"modified_file",
		"staged_changes",
		"staged_changes_file_deleted",
		"staged_changes_modified_file",
		"staged_delete_file_deleted",
		"staged_delete_modified_file",
		"subdir.txt",
		"subdir/",
		NULL
	};

	g_repo = cl_git_sandbox_init("status");

	cl_git_pass(git_repository_head_tree(&head, g_repo));

	/* auto expand with no tree entries */
	cl_git_pass(git_iterator_for_tree(&i, head, 0, NULL, NULL));
	expect_iterator_items(i, 12, expect_basic, 12, expect_basic);
	git_iterator_free(i);

	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_tree(
		&i, head, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 13, expect_trees, 13, expect_trees);
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_tree(
		&i, head, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
	expect_iterator_items(i, 10, expect_noauto, 13, expect_trees);
413
	git_iterator_free(i);
414 415

	git_tree_free(head);
416 417
}

418 419 420 421 422 423 424 425
/* "b=name,t=name", blob_id, tree_id */
static void build_test_tree(
	git_oid *out, git_repository *repo, const char *fmt, ...)
{
	git_oid *id;
	git_treebuilder *builder;
	const char *scan = fmt, *next;
	char type, delimiter;
426
	git_filemode_t mode = GIT_FILEMODE_BLOB;
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
	git_buf name = GIT_BUF_INIT;
	va_list arglist;

	cl_git_pass(git_treebuilder_create(&builder, NULL)); /* start builder */

	va_start(arglist, fmt);
	while (*scan) {
		switch (type = *scan++) {
		case 't': case 'T': mode = GIT_FILEMODE_TREE; break;
		case 'b': case 'B': mode = GIT_FILEMODE_BLOB; break;
		default:
			cl_assert(type == 't' || type == 'T' || type == 'b' || type == 'B');
		}

		delimiter = *scan++; /* read and skip delimiter */
		for (next = scan; *next && *next != delimiter; ++next)
			/* seek end */;
		cl_git_pass(git_buf_set(&name, scan, (size_t)(next - scan)));
		for (scan = next; *scan && (*scan == delimiter || *scan == ','); ++scan)
			/* skip delimiter and optional comma */;

		id = va_arg(arglist, git_oid *);

		cl_git_pass(git_treebuilder_insert(NULL, builder, name.ptr, id, mode));
	}
	va_end(arglist);

	cl_git_pass(git_treebuilder_write(out, repo, builder));

	git_treebuilder_free(builder);
	git_buf_free(&name);
}

460
void test_repo_iterator__tree_case_conflicts_0(void)
461 462 463 464 465 466 467 468
{
	const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6";
	git_tree *tree;
	git_oid blob_id, biga_id, littlea_id, tree_id;
	git_iterator *i;
	const char *expect_cs[] = {
		"A/1.file", "A/3.file", "a/2.file", "a/4.file" };
	const char *expect_ci[] = {
469
		"A/1.file", "a/2.file", "A/3.file", "a/4.file" };
470 471 472 473
	const char *expect_cs_trees[] = {
		"A/", "A/1.file", "A/3.file", "a/", "a/2.file", "a/4.file" };
	const char *expect_ci_trees[] = {
		"A/", "A/1.file", "a/2.file", "A/3.file", "a/4.file" };
474 475 476 477 478 479 480

	g_repo = cl_git_sandbox_init("icase");

	cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */

	/* create tree with: A/1.file, A/3.file, a/2.file, a/4.file */
	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 488 489 490 491 492 493 494 495

	cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
	expect_iterator_items(i, 4, expect_cs, 4, expect_cs);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
496
	expect_iterator_items(i, 4, expect_ci, 4, expect_ci);
497 498
	git_iterator_free(i);

499 500 501 502 503 504 505 506 507 508 509 510
	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_DONT_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 6, expect_cs_trees, 6, expect_cs_trees);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 5, expect_ci_trees, 5, expect_ci_trees);
	git_iterator_free(i);

511 512 513
	git_tree_free(tree);
}

514
void test_repo_iterator__tree_case_conflicts_1(void)
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
{
	const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6";
	git_tree *tree;
	git_oid blob_id, Ab_id, biga_id, littlea_id, tree_id;
	git_iterator *i;
	const char *expect_cs[] = {
		"A/a", "A/b/1", "A/c", "a/C", "a/a", "a/b" };
	const char *expect_ci[] = {
		"A/a", "a/b", "A/b/1", "A/c" };
	const char *expect_cs_trees[] = {
		"A/", "A/a", "A/b/", "A/b/1", "A/c", "a/", "a/C", "a/a", "a/b" };
	const char *expect_ci_trees[] = {
		"A/", "A/a", "a/b", "A/b/", "A/b/1", "A/c" };

	g_repo = cl_git_sandbox_init("icase");

	cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */

	/* 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 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568

	cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
	expect_iterator_items(i, 6, expect_cs, 6, expect_cs);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
	expect_iterator_items(i, 4, expect_ci, 4, expect_ci);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_DONT_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 9, expect_cs_trees, 9, expect_cs_trees);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 6, expect_ci_trees, 6, expect_ci_trees);
	git_iterator_free(i);

	git_tree_free(tree);
}

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
void test_repo_iterator__tree_case_conflicts_2(void)
{
	const char *blob_sha = "d44e18fb93b7107b5cd1b95d601591d77869a1b6";
	git_tree *tree;
	git_oid blob_id, d1, d2, c1, c2, b1, b2, a1, a2, tree_id;
	git_iterator *i;
	const char *expect_cs[] = {
		"A/B/C/D/16", "A/B/C/D/foo", "A/B/C/d/15",  "A/B/C/d/FOO",
		"A/B/c/D/14", "A/B/c/D/foo", "A/B/c/d/13",  "A/B/c/d/FOO",
		"A/b/C/D/12", "A/b/C/D/foo", "A/b/C/d/11",  "A/b/C/d/FOO",
		"A/b/c/D/10", "A/b/c/D/foo", "A/b/c/d/09",  "A/b/c/d/FOO",
		"a/B/C/D/08", "a/B/C/D/foo", "a/B/C/d/07", "a/B/C/d/FOO",
		"a/B/c/D/06", "a/B/c/D/foo", "a/B/c/d/05", "a/B/c/d/FOO",
		"a/b/C/D/04", "a/b/C/D/foo", "a/b/C/d/03", "a/b/C/d/FOO",
		"a/b/c/D/02", "a/b/c/D/foo", "a/b/c/d/01", "a/b/c/d/FOO", };
	const char *expect_ci[] = {
		"a/b/c/d/01", "a/b/c/D/02", "a/b/C/d/03", "a/b/C/D/04",
		"a/B/c/d/05", "a/B/c/D/06", "a/B/C/d/07", "a/B/C/D/08",
		"A/b/c/d/09", "A/b/c/D/10", "A/b/C/d/11", "A/b/C/D/12",
		"A/B/c/d/13", "A/B/c/D/14", "A/B/C/d/15", "A/B/C/D/16",
		"A/B/C/D/foo", };
	const char *expect_ci_trees[] = {
		"A/", "A/B/", "A/B/C/", "A/B/C/D/",
		"a/b/c/d/01", "a/b/c/D/02", "a/b/C/d/03", "a/b/C/D/04",
		"a/B/c/d/05", "a/B/c/D/06", "a/B/C/d/07", "a/B/C/D/08",
		"A/b/c/d/09", "A/b/c/D/10", "A/b/C/d/11", "A/b/C/D/12",
		"A/B/c/d/13", "A/B/c/D/14", "A/B/C/d/15", "A/B/C/D/16",
		"A/B/C/D/foo", };

	g_repo = cl_git_sandbox_init("icase");

	cl_git_pass(git_oid_fromstr(&blob_id, blob_sha)); /* lookup blob */

	build_test_tree(&d1, g_repo, "b|16|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|15|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&d1, g_repo, "b|14|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|13|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&b1, g_repo, "t|C|,t|c|", &c1, &c2);

	build_test_tree(&d1, g_repo, "b|12|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|11|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&d1, g_repo, "b|10|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|09|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&b2, g_repo, "t|C|,t|c|", &c1, &c2);

	build_test_tree(&a1, g_repo, "t|B|,t|b|", &b1, &b2);

	build_test_tree(&d1, g_repo, "b|08|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|07|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&d1, g_repo, "b|06|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|05|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&b1, g_repo, "t|C|,t|c|", &c1, &c2);

	build_test_tree(&d1, g_repo, "b|04|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|03|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c1, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&d1, g_repo, "b|02|,b|foo|", &blob_id, &blob_id);
	build_test_tree(&d2, g_repo, "b|01|,b|FOO|", &blob_id, &blob_id);
	build_test_tree(&c2, g_repo, "t|D|,t|d|", &d1, &d2);
	build_test_tree(&b2, g_repo, "t|C|,t|c|", &c1, &c2);

	build_test_tree(&a2, g_repo, "t|B|,t|b|", &b1, &b2);

	build_test_tree(&tree_id, g_repo, "t/A/,t/a/", &a1, &a2);

	cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id));

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
	expect_iterator_items(i, 32, expect_cs, 32, expect_cs);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
	expect_iterator_items(i, 17, expect_ci, 17, expect_ci);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_tree(
		&i, tree, GIT_ITERATOR_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 21, expect_ci_trees, 21, expect_ci_trees);
	git_iterator_free(i);

	git_tree_free(tree);
}

661 662 663 664
void test_repo_iterator__workdir(void)
{
	git_iterator *i;

665 666
	g_repo = cl_git_sandbox_init("icase");

667 668
	/* auto expand with no tree entries */
	cl_git_pass(git_iterator_for_workdir(&i, g_repo, 0, NULL, NULL));
669
	expect_iterator_items(i, 20, NULL, 20, NULL);
670 671 672 673 674
	git_iterator_free(i);

	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
675
	expect_iterator_items(i, 22, NULL, 22, NULL);
676 677 678
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
679
	cl_git_pass(git_iterator_for_workdir(
680
		&i, g_repo, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
681
	expect_iterator_items(i, 12, NULL, 22, NULL);
682 683 684 685 686 687 688 689
	git_iterator_free(i);
}

void test_repo_iterator__workdir_icase(void)
{
	git_iterator *i;
	git_iterator_flag_t flag;

690 691
	g_repo = cl_git_sandbox_init("icase");

692 693
	flag = GIT_ITERATOR_DONT_IGNORE_CASE;

694
	/* auto expand with no tree entries */
695
	cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D"));
696
	expect_iterator_items(i, 7, NULL, 7, NULL);
697 698 699
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z"));
700
	expect_iterator_items(i, 3, NULL, 3, NULL);
701 702 703 704 705
	git_iterator_free(i);

	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
706
	expect_iterator_items(i, 8, NULL, 8, NULL);
707 708 709 710
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
711
	expect_iterator_items(i, 4, NULL, 4, NULL);
712 713 714 715 716
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
717
	expect_iterator_items(i, 5, NULL, 8, NULL);
718 719 720 721
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
722
	expect_iterator_items(i, 1, NULL, 4, NULL);
723 724 725 726
	git_iterator_free(i);

	flag = GIT_ITERATOR_IGNORE_CASE;

727
	/* auto expand with no tree entries */
728
	cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "c", "k/D"));
729
	expect_iterator_items(i, 13, NULL, 13, NULL);
730 731 732
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_workdir(&i, g_repo, flag, "k", "k/Z"));
733
	expect_iterator_items(i, 5, NULL, 5, NULL);
734 735 736 737 738
	git_iterator_free(i);

	/* auto expand with tree entries */
	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "c", "k/D"));
739
	expect_iterator_items(i, 14, NULL, 14, NULL);
740 741 742 743
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_INCLUDE_TREES, "k", "k/Z"));
744
	expect_iterator_items(i, 6, NULL, 6, NULL);
745 746 747 748 749
	git_iterator_free(i);

	/* no auto expand (implies trees included) */
	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "c", "k/D"));
750
	expect_iterator_items(i, 9, NULL, 14, NULL);
751 752 753 754
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_workdir(
		&i, g_repo, flag | GIT_ITERATOR_DONT_AUTOEXPAND, "k", "k/Z"));
755
	expect_iterator_items(i, 1, NULL, 6, NULL);
756 757
	git_iterator_free(i);
}
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 767 768 769
			p_snprintf(buf, sizeof(buf), "%s/dir%02d", root, i);
			cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH));

			p_snprintf(buf, sizeof(buf), "%s/dir%02d/file", root, i);
770
			cl_git_mkfile(buf, buf);
771 772 773 774
			buf[strlen(buf) - 5] = '\0';
		} else {
			p_snprintf(buf, sizeof(buf), "%s/DIR%02d", root, i);
			cl_git_pass(git_futils_mkdir(buf, NULL, 0775, GIT_MKDIR_PATH));
775 776
		}

777 778 779 780 781 782 783 784
		for (j = 0; j < subs; ++j) {
			switch (j % 4) {
			case 0: p_snprintf(sub, sizeof(sub), "%s/sub%02d", buf, j); break;
			case 1: p_snprintf(sub, sizeof(sub), "%s/sUB%02d", buf, j); break;
			case 2: p_snprintf(sub, sizeof(sub), "%s/Sub%02d", buf, j); break;
			case 3: p_snprintf(sub, sizeof(sub), "%s/SUB%02d", buf, j); break;
			}
			cl_git_pass(git_futils_mkdir(sub, NULL, 0775, GIT_MKDIR_PATH));
785 786

			if (j % 2 == 0) {
787 788 789 790
				size_t sublen = strlen(sub);
				memcpy(&sub[sublen], "/file", sizeof("/file"));
				cl_git_mkfile(sub, sub);
				sub[sublen] = '\0';
791 792 793
			}
		}
	}
794
}
795

796 797 798
void test_repo_iterator__workdir_depth(void)
{
	git_iterator *iter;
799

800 801 802
	g_repo = cl_git_sandbox_init("icase");

	build_workdir_tree("icase", 10, 10);
803 804
	build_workdir_tree("icase/DIR01/sUB01", 50, 0);
	build_workdir_tree("icase/dir02/sUB01", 50, 0);
805 806 807 808 809 810 811 812 813 814 815 816

	/* auto expand with no tree entries */
	cl_git_pass(git_iterator_for_workdir(&iter, g_repo, 0, NULL, NULL));
	expect_iterator_items(iter, 125, NULL, 125, NULL);
	git_iterator_free(iter);

	/* auto expand with tree entries (empty dirs silently skipped) */
	cl_git_pass(git_iterator_for_workdir(
		&iter, g_repo, GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(iter, 337, NULL, 337, NULL);
	git_iterator_free(iter);
}
817 818 819 820

void test_repo_iterator__fs(void)
{
	git_iterator *i;
821 822 823
	static const char *expect_base[] = {
		"DIR01/Sub02/file",
		"DIR01/sub00/file",
824
		"current_file",
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
		"dir00/Sub02/file",
		"dir00/file",
		"dir00/sub00/file",
		"modified_file",
		"new_file",
		NULL,
	};
	static const char *expect_trees[] = {
		"DIR01/",
		"DIR01/SUB03/",
		"DIR01/Sub02/",
		"DIR01/Sub02/file",
		"DIR01/sUB01/",
		"DIR01/sub00/",
		"DIR01/sub00/file",
		"current_file",
		"dir00/",
		"dir00/SUB03/",
		"dir00/Sub02/",
		"dir00/Sub02/file",
		"dir00/file",
		"dir00/sUB01/",
		"dir00/sub00/",
		"dir00/sub00/file",
		"modified_file",
		"new_file",
		NULL,
	};
	static const char *expect_noauto[] = {
		"DIR01/",
		"current_file",
		"dir00/",
857 858 859 860 861 862 863
		"modified_file",
		"new_file",
		NULL,
	};

	g_repo = cl_git_sandbox_init("status");

864 865
	build_workdir_tree("status/subdir", 2, 4);

866 867
	cl_git_pass(git_iterator_for_filesystem(
		&i, "status/subdir", 0, NULL, NULL));
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
	expect_iterator_items(i, 8, expect_base, 8, expect_base);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_filesystem(
		&i, "status/subdir", GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 18, expect_trees, 18, expect_trees);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_filesystem(
		&i, "status/subdir", GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
	expect_iterator_items(i, 5, expect_noauto, 18, expect_trees);
	git_iterator_free(i);

	git__tsort((void **)expect_base, 8, (git__tsort_cmp)git__strcasecmp);
	git__tsort((void **)expect_trees, 18, (git__tsort_cmp)git__strcasecmp);
	git__tsort((void **)expect_noauto, 5, (git__tsort_cmp)git__strcasecmp);

	cl_git_pass(git_iterator_for_filesystem(
		&i, "status/subdir", GIT_ITERATOR_IGNORE_CASE, NULL, NULL));
	expect_iterator_items(i, 8, expect_base, 8, expect_base);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_filesystem(
		&i, "status/subdir", GIT_ITERATOR_IGNORE_CASE |
		GIT_ITERATOR_INCLUDE_TREES, NULL, NULL));
	expect_iterator_items(i, 18, expect_trees, 18, expect_trees);
	git_iterator_free(i);

	cl_git_pass(git_iterator_for_filesystem(
		&i, "status/subdir", GIT_ITERATOR_IGNORE_CASE |
		GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL));
	expect_iterator_items(i, 5, expect_noauto, 18, expect_trees);
900 901 902 903 904 905
	git_iterator_free(i);
}

void test_repo_iterator__fs2(void)
{
	git_iterator *i;
906
	static const char *expect_base[] = {
907 908
		"heads/br2",
		"heads/dir",
909
		"heads/long-file-name",
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
		"heads/master",
		"heads/packed-test",
		"heads/subtrees",
		"heads/test",
		"tags/e90810b",
		"tags/foo/bar",
		"tags/foo/foo/bar",
		"tags/point_to_blob",
		"tags/test",
		NULL,
	};

	g_repo = cl_git_sandbox_init("testrepo");

	cl_git_pass(git_iterator_for_filesystem(
		&i, "testrepo/.git/refs", 0, NULL, NULL));
926
	expect_iterator_items(i, 12, expect_base, 12, expect_base);
927 928
	git_iterator_free(i);
}
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962

void test_repo_iterator__fs_preserves_error(void)
{
	git_iterator *i;
	const git_index_entry *e;

	if (!cl_is_chmod_supported())
		return;

	g_repo = cl_git_sandbox_init("empty_standard_repo");

	cl_must_pass(p_mkdir("empty_standard_repo/r", 0777));
	cl_git_mkfile("empty_standard_repo/r/a", "hello");
	cl_must_pass(p_mkdir("empty_standard_repo/r/b", 0777));
	cl_git_mkfile("empty_standard_repo/r/b/problem", "not me");
	cl_must_pass(p_chmod("empty_standard_repo/r/b", 0000));
	cl_must_pass(p_mkdir("empty_standard_repo/r/c", 0777));
	cl_git_mkfile("empty_standard_repo/r/d", "final");

	cl_git_pass(git_iterator_for_filesystem(
		&i, "empty_standard_repo/r", 0, NULL, NULL));

	cl_git_pass(git_iterator_advance(&e, i)); /* a */
	cl_git_fail(git_iterator_advance(&e, i)); /* b */
	cl_assert(giterr_last());
	cl_assert(giterr_last()->message != NULL);
	/* skip 'c/' empty directory */
	cl_git_pass(git_iterator_advance(&e, i)); /* d */
	cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&e, i));

	cl_must_pass(p_chmod("empty_standard_repo/r/b", 0777));

	git_iterator_free(i);
}