iterator.c 22.7 KB
Newer Older
1 2 3
#include "clar_libgit2.h"
#include "diff_helpers.h"
#include "iterator.h"
4
#include "tree.h"
5 6 7 8 9 10 11 12 13 14 15 16

void test_diff_iterator__initialize(void)
{
	/* since we are doing tests with different sandboxes, defer setup
	 * to the actual tests.  cleanup will still be done in the global
	 * cleanup function so that assertion failures don't result in a
	 * missed cleanup.
	 */
}

void test_diff_iterator__cleanup(void)
{
17
	cl_git_sandbox_cleanup();
18 19 20 21 22 23 24 25
}


/* -- TREE ITERATOR TESTS -- */

static void tree_iterator_test(
	const char *sandbox,
	const char *treeish,
26 27
	const char *start,
	const char *end,
28 29 30 31 32 33
	int expected_count,
	const char **expected_values)
{
	git_tree *t;
	git_iterator *i;
	const git_index_entry *entry;
34
	int error, count = 0, count_post_reset = 0;
35
	git_repository *repo = cl_git_sandbox_init(sandbox);
36

37
	cl_assert(t = resolve_commit_oid_to_tree(repo, treeish));
38
	cl_git_pass(git_iterator_for_tree(
39
		&i, t, GIT_ITERATOR_DONT_IGNORE_CASE, start, end));
40

41
	/* test loop */
42 43
	while (!(error = git_iterator_advance(&entry, i))) {
		cl_assert(entry);
44
		if (expected_values != NULL)
45
			cl_assert_equal_s(expected_values[count], entry->path);
46
		count++;
47
	}
48 49 50
	cl_assert_equal_i(GIT_ITEROVER, error);
	cl_assert(!entry);
	cl_assert_equal_i(expected_count, count);
51

52 53
	/* test reset */
	cl_git_pass(git_iterator_reset(i, NULL, NULL));
54 55 56

	while (!(error = git_iterator_advance(&entry, i))) {
		cl_assert(entry);
57 58 59
		if (expected_values != NULL)
			cl_assert_equal_s(expected_values[count_post_reset], entry->path);
		count_post_reset++;
60
	}
61 62
	cl_assert_equal_i(GIT_ITEROVER, error);
	cl_assert(!entry);
63
	cl_assert_equal_i(count, count_post_reset);
64

65
	git_iterator_free(i);
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
	git_tree_free(t);
}

/* results of: git ls-tree -r --name-only 605812a */
const char *expected_tree_0[] = {
	".gitattributes",
	"attr0",
	"attr1",
	"attr2",
	"attr3",
	"binfile",
	"macro_test",
	"root_test1",
	"root_test2",
	"root_test3",
	"root_test4.txt",
	"subdir/.gitattributes",
	"subdir/abc",
	"subdir/subdir_test1",
	"subdir/subdir_test2.txt",
	"subdir2/subdir2_test1",
	NULL
};

void test_diff_iterator__tree_0(void)
{
92
	tree_iterator_test("attr", "605812a", NULL, NULL, 16, expected_tree_0);
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
}

/* results of: git ls-tree -r --name-only 6bab5c79 */
const char *expected_tree_1[] = {
	".gitattributes",
	"attr0",
	"attr1",
	"attr2",
	"attr3",
	"root_test1",
	"root_test2",
	"root_test3",
	"root_test4.txt",
	"subdir/.gitattributes",
	"subdir/subdir_test1",
	"subdir/subdir_test2.txt",
	"subdir2/subdir2_test1",
	NULL
};

void test_diff_iterator__tree_1(void)
{
115
	tree_iterator_test("attr", "6bab5c79cd5", NULL, NULL, 13, expected_tree_1);
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
}

/* results of: git ls-tree -r --name-only 26a125ee1 */
const char *expected_tree_2[] = {
	"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
};

void test_diff_iterator__tree_2(void)
{
137
	tree_iterator_test("status", "26a125ee1", NULL, NULL, 12, expected_tree_2);
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
}

/* $ git ls-tree -r --name-only 0017bd4ab1e */
const char *expected_tree_3[] = {
	"current_file",
	"file_deleted",
	"modified_file",
	"staged_changes",
	"staged_changes_file_deleted",
	"staged_changes_modified_file",
	"staged_delete_file_deleted",
	"staged_delete_modified_file"
};

void test_diff_iterator__tree_3(void)
{
154
	tree_iterator_test("status", "0017bd4ab1e", NULL, NULL, 8, expected_tree_3);
155 156
}

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
/* $ git ls-tree -r --name-only 24fa9a9fc4e202313e24b648087495441dab432b */
const char *expected_tree_4[] = {
	"attr0",
	"attr1",
	"attr2",
	"attr3",
	"binfile",
	"gitattributes",
	"macro_bad",
	"macro_test",
	"root_test1",
	"root_test2",
	"root_test3",
	"root_test4.txt",
	"sub/abc",
	"sub/file",
	"sub/sub/file",
	"sub/sub/subsub.txt",
	"sub/subdir_test1",
	"sub/subdir_test2.txt",
	"subdir/.gitattributes",
	"subdir/abc",
	"subdir/subdir_test1",
	"subdir/subdir_test2.txt",
	"subdir2/subdir2_test1",
	NULL
};

void test_diff_iterator__tree_4(void)
{
	tree_iterator_test(
188
		"attr", "24fa9a9fc4e202313e24b648087495441dab432b", NULL, NULL,
189 190
		23, expected_tree_4);
}
191

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
void test_diff_iterator__tree_4_ranged(void)
{
	tree_iterator_test(
		"attr", "24fa9a9fc4e202313e24b648087495441dab432b",
		"sub", "sub",
		11, &expected_tree_4[12]);
}

const char *expected_tree_ranged_0[] = {
	"gitattributes",
	"macro_bad",
	"macro_test",
	"root_test1",
	"root_test2",
	"root_test3",
	"root_test4.txt",
	NULL
};

void test_diff_iterator__tree_ranged_0(void)
{
	tree_iterator_test(
		"attr", "24fa9a9fc4e202313e24b648087495441dab432b",
		"git", "root",
		7, expected_tree_ranged_0);
}

const char *expected_tree_ranged_1[] = {
	"sub/subdir_test2.txt",
	NULL
};

void test_diff_iterator__tree_ranged_1(void)
{
	tree_iterator_test(
		"attr", "24fa9a9fc4e202313e24b648087495441dab432b",
		"sub/subdir_test2.txt", "sub/subdir_test2.txt",
		1, expected_tree_ranged_1);
}

void test_diff_iterator__tree_range_empty_0(void)
{
	tree_iterator_test(
		"attr", "24fa9a9fc4e202313e24b648087495441dab432b",
		"empty", "empty", 0, NULL);
}

void test_diff_iterator__tree_range_empty_1(void)
{
	tree_iterator_test(
		"attr", "24fa9a9fc4e202313e24b648087495441dab432b",
		"z_empty_after", NULL, 0, NULL);
}

void test_diff_iterator__tree_range_empty_2(void)
{
	tree_iterator_test(
		"attr", "24fa9a9fc4e202313e24b648087495441dab432b",
		NULL, ".aaa_empty_before", 0, NULL);
}

253 254 255 256 257 258 259 260 261 262 263 264
static void check_tree_entry(
	git_iterator *i,
	const char *oid,
	const char *oid_p,
	const char *oid_pp,
	const char *oid_ppp)
{
	const git_index_entry *ie;
	const git_tree_entry *te;
	const git_tree *tree;
	git_buf path = GIT_BUF_INIT;

265
	cl_git_pass(git_iterator_current_tree_entry(&te, i));
266 267 268
	cl_assert(te);
	cl_assert(git_oid_streq(&te->oid, oid) == 0);

269
	cl_git_pass(git_iterator_current(&ie, i));
270 271 272 273
	cl_git_pass(git_buf_sets(&path, ie->path));

	if (oid_p) {
		git_buf_rtruncate_at_char(&path, '/');
274
		cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr));
275 276 277 278 279 280
		cl_assert(tree);
		cl_assert(git_oid_streq(git_tree_id(tree), oid_p) == 0);
	}

	if (oid_pp) {
		git_buf_rtruncate_at_char(&path, '/');
281
		cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr));
282 283 284 285 286 287
		cl_assert(tree);
		cl_assert(git_oid_streq(git_tree_id(tree), oid_pp) == 0);
	}

	if (oid_ppp) {
		git_buf_rtruncate_at_char(&path, '/');
288
		cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr));
289 290 291 292 293 294 295 296 297 298 299 300 301
		cl_assert(tree);
		cl_assert(git_oid_streq(git_tree_id(tree), oid_ppp) == 0);
	}

	git_buf_free(&path);
}

void test_diff_iterator__tree_special_functions(void)
{
	git_tree *t;
	git_iterator *i;
	const git_index_entry *entry;
	git_repository *repo = cl_git_sandbox_init("attr");
302
	int error, cases = 0;
303 304 305 306 307 308
	const char *rootoid = "ce39a97a7fb1fa90bcf5e711249c1e507476ae0e";

	t = resolve_commit_oid_to_tree(
		repo, "24fa9a9fc4e202313e24b648087495441dab432b");
	cl_assert(t != NULL);

309
	cl_git_pass(git_iterator_for_tree(
310
		&i, t, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL));
311

312 313 314
	while (!(error = git_iterator_advance(&entry, i))) {
		cl_assert(entry);

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
		if (strcmp(entry->path, "sub/file") == 0) {
			cases++;
			check_tree_entry(
				i, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057",
				"ecb97df2a174987475ac816e3847fc8e9f6c596b",
				rootoid, NULL);
		}
		else if (strcmp(entry->path, "sub/sub/subsub.txt") == 0) {
			cases++;
			check_tree_entry(
				i, "9e5bdc47d6a80f2be0ea3049ad74231b94609242",
				"4e49ba8c5b6c32ff28cd9dcb60be34df50fcc485",
				"ecb97df2a174987475ac816e3847fc8e9f6c596b", rootoid);
		}
		else if (strcmp(entry->path, "subdir/.gitattributes") == 0) {
			cases++;
			check_tree_entry(
				i, "99eae476896f4907224978b88e5ecaa6c5bb67a9",
				"9fb40b6675dde60b5697afceae91b66d908c02d9",
				rootoid, NULL);
		}
		else if (strcmp(entry->path, "subdir2/subdir2_test1") == 0) {
			cases++;
			check_tree_entry(
				i, "dccada462d3df8ac6de596fb8c896aba9344f941",
				"2929de282ce999e95183aedac6451d3384559c4b",
				rootoid, NULL);
		}
	}
344 345
	cl_assert_equal_i(GIT_ITEROVER, error);
	cl_assert(!entry);
346
	cl_assert_equal_i(4, cases);
347

348 349 350 351
	git_iterator_free(i);
	git_tree_free(t);
}

352 353 354 355
/* -- INDEX ITERATOR TESTS -- */

static void index_iterator_test(
	const char *sandbox,
356 357
	const char *start,
	const char *end,
358 359 360 361
	int expected_count,
	const char **expected_names,
	const char **expected_oids)
{
362
	git_index *index;
363 364
	git_iterator *i;
	const git_index_entry *entry;
365
	int error, count = 0;
366
	git_repository *repo = cl_git_sandbox_init(sandbox);
367

368
	cl_git_pass(git_repository_index(&index, repo));
369
	cl_git_pass(git_iterator_for_index(&i, index, 0, start, end));
370

371 372 373
	while (!(error = git_iterator_advance(&entry, i))) {
		cl_assert(entry);

374
		if (expected_names != NULL)
375
			cl_assert_equal_s(expected_names[count], entry->path);
376 377 378 379

		if (expected_oids != NULL) {
			git_oid oid;
			cl_git_pass(git_oid_fromstr(&oid, expected_oids[count]));
380
			cl_assert_equal_i(git_oid_cmp(&oid, &entry->id), 0);
381 382 383 384 385
		}

		count++;
	}

386 387 388 389
	cl_assert_equal_i(GIT_ITEROVER, error);
	cl_assert(!entry);
	cl_assert_equal_i(expected_count, count);

390
	git_iterator_free(i);
391
	git_index_free(index);
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
}

static const char *expected_index_0[] = {
	"attr0",
	"attr1",
	"attr2",
	"attr3",
	"binfile",
	"gitattributes",
	"macro_bad",
	"macro_test",
	"root_test1",
	"root_test2",
	"root_test3",
	"root_test4.txt",
407 408 409 410 411 412
	"sub/abc",
	"sub/file",
	"sub/sub/file",
	"sub/sub/subsub.txt",
	"sub/subdir_test1",
	"sub/subdir_test2.txt",
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
	"subdir/.gitattributes",
	"subdir/abc",
	"subdir/subdir_test1",
	"subdir/subdir_test2.txt",
	"subdir2/subdir2_test1",
};

static const char *expected_index_oids_0[] = {
	"556f8c827b8e4a02ad5cab77dca2bcb3e226b0b3",
	"3b74db7ab381105dc0d28f8295a77f6a82989292",
	"2c66e14f77196ea763fb1e41612c1aa2bc2d8ed2",
	"c485abe35abd4aa6fd83b076a78bbea9e2e7e06c",
	"d800886d9c86731ae5c4a62b0b77c437015e00d2",
	"2b40c5aca159b04ea8d20ffe36cdf8b09369b14a",
	"5819a185d77b03325aaf87cafc771db36f6ddca7",
	"ff69f8639ce2e6010b3f33a74160aad98b48da2b",
	"45141a79a77842c59a63229403220a4e4be74e3d",
430 431
	"4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d",
	"108bb4e7fd7b16490dc33ff7d972151e73d7166e",
432
	"a0f7217ae99f5ac3e88534f5cea267febc5fa85b",
433 434 435 436 437 438
	"3e42ffc54a663f9401cc25843d6c0e71a33e4249",
	"45b983be36b73c0788dc9cbcb76cbb80fc7bb057",
	"45b983be36b73c0788dc9cbcb76cbb80fc7bb057",
	"9e5bdc47d6a80f2be0ea3049ad74231b94609242",
	"e563cf4758f0d646f1b14b76016aa17fa9e549a4",
	"fb5067b1aef3ac1ada4b379dbcb7d17255df7d78",
439 440 441 442 443 444 445 446 447
	"99eae476896f4907224978b88e5ecaa6c5bb67a9",
	"3e42ffc54a663f9401cc25843d6c0e71a33e4249",
	"e563cf4758f0d646f1b14b76016aa17fa9e549a4",
	"fb5067b1aef3ac1ada4b379dbcb7d17255df7d78",
	"dccada462d3df8ac6de596fb8c896aba9344f941"
};

void test_diff_iterator__index_0(void)
{
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
	index_iterator_test(
		"attr", NULL, NULL, 23, expected_index_0, expected_index_oids_0);
}

static const char *expected_index_range[] = {
	"root_test1",
	"root_test2",
	"root_test3",
	"root_test4.txt",
};

static const char *expected_index_oids_range[] = {
	"45141a79a77842c59a63229403220a4e4be74e3d",
	"4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d",
	"108bb4e7fd7b16490dc33ff7d972151e73d7166e",
463
	"a0f7217ae99f5ac3e88534f5cea267febc5fa85b",
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
};

void test_diff_iterator__index_range(void)
{
	index_iterator_test(
		"attr", "root", "root", 4, expected_index_range, expected_index_oids_range);
}

void test_diff_iterator__index_range_empty_0(void)
{
	index_iterator_test(
		"attr", "empty", "empty", 0, NULL, NULL);
}

void test_diff_iterator__index_range_empty_1(void)
{
	index_iterator_test(
		"attr", "z_empty_after", NULL, 0, NULL, NULL);
}

void test_diff_iterator__index_range_empty_2(void)
{
	index_iterator_test(
		"attr", NULL, ".aaa_empty_before", 0, NULL, NULL);
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
}

static const char *expected_index_1[] = {
	"current_file",
	"file_deleted",
	"modified_file",
	"staged_changes",
	"staged_changes_file_deleted",
	"staged_changes_modified_file",
	"staged_new_file",
	"staged_new_file_deleted_file",
	"staged_new_file_modified_file",
	"subdir.txt",
	"subdir/current_file",
	"subdir/deleted_file",
	"subdir/modified_file",
};

static const char* expected_index_oids_1[] = {
	"a0de7e0ac200c489c41c59dfa910154a70264e6e",
	"5452d32f1dd538eb0405e8a83cc185f79e25e80f",
	"452e4244b5d083ddf0460acf1ecc74db9dcfa11a",
	"55d316c9ba708999f1918e9677d01dfcae69c6b9",
	"a6be623522ce87a1d862128ac42672604f7b468b",
	"906ee7711f4f4928ddcb2a5f8fbc500deba0d2a8",
	"529a16e8e762d4acb7b9636ff540a00831f9155a",
	"90b8c29d8ba39434d1c63e1b093daaa26e5bd972",
	"ed062903b8f6f3dccb2fa81117ba6590944ef9bd",
	"e8ee89e15bbe9b20137715232387b3de5b28972e",
	"53ace0d1cc1145a5f4fe4f78a186a60263190733",
	"1888c805345ba265b0ee9449b8877b6064592058",
	"a6191982709b746d5650e93c2acf34ef74e11504"
};

void test_diff_iterator__index_1(void)
{
524 525
	index_iterator_test(
		"status", NULL, NULL, 13, expected_index_1, expected_index_oids_1);
526 527 528 529 530 531 532
}


/* -- WORKDIR ITERATOR TESTS -- */

static void workdir_iterator_test(
	const char *sandbox,
533 534
	const char *start,
	const char *end,
535 536 537 538 539 540 541
	int expected_count,
	int expected_ignores,
	const char **expected_names,
	const char *an_ignored_name)
{
	git_iterator *i;
	const git_index_entry *entry;
542
	int error, count = 0, count_all = 0, count_all_post_reset = 0;
543
	git_repository *repo = cl_git_sandbox_init(sandbox);
544

545 546
	cl_git_pass(git_iterator_for_workdir(
		&i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, start, end));
547 548 549 550

	error = git_iterator_current(&entry, i);
	cl_assert((error == 0 && entry != NULL) ||
			  (error == GIT_ITEROVER && entry == NULL));
551 552 553 554

	while (entry != NULL) {
		int ignored = git_iterator_current_is_ignored(i);

555
		if (S_ISDIR(entry->mode)) {
556
			cl_git_pass(git_iterator_advance_into(&entry, i));
557 558 559
			continue;
		}

560
		if (expected_names != NULL)
561
			cl_assert_equal_s(expected_names[count_all], entry->path);
562 563 564 565 566 567 568 569

		if (an_ignored_name && strcmp(an_ignored_name,entry->path)==0)
			cl_assert(ignored);

		if (!ignored)
			count++;
		count_all++;

570 571 572 573
		error = git_iterator_advance(&entry, i);

		cl_assert((error == 0 && entry != NULL) ||
				  (error == GIT_ITEROVER && entry == NULL));
574 575
	}

576 577 578
	cl_assert_equal_i(expected_count, count);
	cl_assert_equal_i(expected_count + expected_ignores, count_all);

579
	cl_git_pass(git_iterator_reset(i, NULL, NULL));
580 581 582 583

	error = git_iterator_current(&entry, i);
	cl_assert((error == 0 && entry != NULL) ||
			  (error == GIT_ITEROVER && entry == NULL));
584 585 586

	while (entry != NULL) {
		if (S_ISDIR(entry->mode)) {
587
			cl_git_pass(git_iterator_advance_into(&entry, i));
588 589
			continue;
		}
590

591 592 593 594 595
		if (expected_names != NULL)
			cl_assert_equal_s(
				expected_names[count_all_post_reset], entry->path);
		count_all_post_reset++;

596 597 598
		error = git_iterator_advance(&entry, i);
		cl_assert(error == 0 || error == GIT_ITEROVER);
	}
599

600
	cl_assert_equal_i(count_all, count_all_post_reset);
601 602

	git_iterator_free(i);
603 604 605 606
}

void test_diff_iterator__workdir_0(void)
{
607
	workdir_iterator_test("attr", NULL, NULL, 27, 1, NULL, "ign");
608 609 610 611 612 613 614 615 616 617 618 619
}

static const char *status_paths[] = {
	"current_file",
	"ignored_file",
	"modified_file",
	"new_file",
	"staged_changes",
	"staged_changes_modified_file",
	"staged_delete_modified_file",
	"staged_new_file",
	"staged_new_file_modified_file",
620
	"subdir.txt",
621 622 623
	"subdir/current_file",
	"subdir/modified_file",
	"subdir/new_file",
624
	"\xe8\xbf\x99",
625 626 627 628 629
	NULL
};

void test_diff_iterator__workdir_1(void)
{
630
	workdir_iterator_test(
631
		"status", NULL, NULL, 13, 1, status_paths, "ignored_file");
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 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
}

static const char *status_paths_range_0[] = {
	"staged_changes",
	"staged_changes_modified_file",
	"staged_delete_modified_file",
	"staged_new_file",
	"staged_new_file_modified_file",
	NULL
};

void test_diff_iterator__workdir_1_ranged_0(void)
{
	workdir_iterator_test(
		"status", "staged", "staged", 5, 0, status_paths_range_0, NULL);
}

static const char *status_paths_range_1[] = {
	"modified_file", NULL
};

void test_diff_iterator__workdir_1_ranged_1(void)
{
	workdir_iterator_test(
		"status", "modified_file", "modified_file",
		1, 0, status_paths_range_1, NULL);
}

static const char *status_paths_range_3[] = {
	"subdir.txt",
	"subdir/current_file",
	"subdir/modified_file",
	NULL
};

void test_diff_iterator__workdir_1_ranged_3(void)
{
	workdir_iterator_test(
		"status", "subdir", "subdir/modified_file",
		3, 0, status_paths_range_3, NULL);
}

static const char *status_paths_range_4[] = {
	"subdir/current_file",
	"subdir/modified_file",
	"subdir/new_file",
678
	"\xe8\xbf\x99",
679 680 681 682 683 684
	NULL
};

void test_diff_iterator__workdir_1_ranged_4(void)
{
	workdir_iterator_test(
685
		"status", "subdir/", NULL, 4, 0, status_paths_range_4, NULL);
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
}

static const char *status_paths_range_5[] = {
	"subdir/modified_file",
	NULL
};

void test_diff_iterator__workdir_1_ranged_5(void)
{
	workdir_iterator_test(
		"status", "subdir/modified_file", "subdir/modified_file",
		1, 0, status_paths_range_5, NULL);
}

void test_diff_iterator__workdir_1_ranged_empty_0(void)
{
	workdir_iterator_test(
703
		"status", "\xff_does_not_exist", NULL,
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
		0, 0, NULL, NULL);
}

void test_diff_iterator__workdir_1_ranged_empty_1(void)
{
	workdir_iterator_test(
		"status", "empty", "empty",
		0, 0, NULL, NULL);
}

void test_diff_iterator__workdir_1_ranged_empty_2(void)
{
	workdir_iterator_test(
		"status", NULL, "aaaa_empty_before",
		0, 0, NULL, NULL);
719
}
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739

void test_diff_iterator__workdir_builtin_ignores(void)
{
	git_repository *repo = cl_git_sandbox_init("attr");
	git_iterator *i;
	const git_index_entry *entry;
	int idx;
	static struct {
		const char *path;
		bool ignored;
	} expected[] = {
		{ "dir/", true },
		{ "file", false },
		{ "ign", true },
		{ "macro_bad", false },
		{ "macro_test", false },
		{ "root_test1", false },
		{ "root_test2", false },
		{ "root_test3", false },
		{ "root_test4.txt", false },
740
		{ "sub", false },
741 742 743 744 745
		{ "sub/.gitattributes", false },
		{ "sub/abc", false },
		{ "sub/dir/", true },
		{ "sub/file", false },
		{ "sub/ign/", true },
746
		{ "sub/sub", false },
747 748 749 750 751 752 753 754 755
		{ "sub/sub/.gitattributes", false },
		{ "sub/sub/dir", false }, /* file is not actually a dir */
		{ "sub/sub/file", false },
		{ NULL, false }
	};

	cl_git_pass(p_mkdir("attr/sub/sub/.git", 0777));
	cl_git_mkfile("attr/sub/.git", "whatever");

756 757
	cl_git_pass(git_iterator_for_workdir(
		&i, repo, GIT_ITERATOR_DONT_AUTOEXPAND, "dir", "sub/sub/file"));
758
	cl_git_pass(git_iterator_current(&entry, i));
759 760 761 762 763 764 765

	for (idx = 0; entry != NULL; ++idx) {
		int ignored = git_iterator_current_is_ignored(i);

		cl_assert_equal_s(expected[idx].path, entry->path);
		cl_assert_(ignored == expected[idx].ignored, expected[idx].path);

766 767 768 769 770
		if (!ignored &&
			(entry->mode == GIT_FILEMODE_TREE ||
			 entry->mode == GIT_FILEMODE_COMMIT))
		{
			/* it is possible to advance "into" a submodule */
771
			cl_git_pass(git_iterator_advance_into(&entry, i));
772 773 774 775
		} else {
			int error = git_iterator_advance(&entry, i);
			cl_assert(!error || error == GIT_ITEROVER);
		}
776 777 778 779 780 781
	}

	cl_assert(expected[idx].path == NULL);

	git_iterator_free(i);
}
782

783
static void check_wd_first_through_third_range(
784 785 786 787
	git_repository *repo, const char *start, const char *end)
{
	git_iterator *i;
	const git_index_entry *entry;
788
	int error, idx;
789
	static const char *expected[] = { "FIRST", "second", "THIRD", NULL };
790

791
	cl_git_pass(git_iterator_for_workdir(
792
		&i, repo, GIT_ITERATOR_IGNORE_CASE, start, end));
793
	cl_git_pass(git_iterator_current(&entry, i));
794 795 796 797

	for (idx = 0; entry != NULL; ++idx) {
		cl_assert_equal_s(expected[idx], entry->path);

798 799
		error = git_iterator_advance(&entry, i);
		cl_assert(!error || error == GIT_ITEROVER);
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
	}

	cl_assert(expected[idx] == NULL);

	git_iterator_free(i);
}

void test_diff_iterator__workdir_handles_icase_range(void)
{
	git_repository *repo;

	repo = cl_git_sandbox_init("empty_standard_repo");
	cl_git_remove_placeholders(git_repository_path(repo), "dummy-marker.txt");

	cl_git_mkfile("empty_standard_repo/before", "whatever\n");
	cl_git_mkfile("empty_standard_repo/FIRST", "whatever\n");
	cl_git_mkfile("empty_standard_repo/second", "whatever\n");
	cl_git_mkfile("empty_standard_repo/THIRD", "whatever\n");
	cl_git_mkfile("empty_standard_repo/zafter", "whatever\n");
	cl_git_mkfile("empty_standard_repo/Zlast", "whatever\n");

821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
	check_wd_first_through_third_range(repo, "first", "third");
	check_wd_first_through_third_range(repo, "FIRST", "THIRD");
	check_wd_first_through_third_range(repo, "first", "THIRD");
	check_wd_first_through_third_range(repo, "FIRST", "third");
	check_wd_first_through_third_range(repo, "FirSt", "tHiRd");
}

static void check_tree_range(
	git_repository *repo,
	const char *start,
	const char *end,
	bool ignore_case,
	int expected_count)
{
	git_tree *head;
	git_iterator *i;
837
	int error, count;
838 839 840

	cl_git_pass(git_repository_head_tree(&head, repo));

841
	cl_git_pass(git_iterator_for_tree(
842 843 844 845
		&i, head,
		ignore_case ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE,
		start, end));

846 847
	for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count)
		/* count em up */;
848

849
	cl_assert_equal_i(GIT_ITEROVER, error);
850 851 852 853 854 855 856 857 858 859 860 861 862 863
	cl_assert_equal_i(expected_count, count);

	git_iterator_free(i);
	git_tree_free(head);
}

void test_diff_iterator__tree_handles_icase_range(void)
{
	git_repository *repo;

	repo = cl_git_sandbox_init("testrepo");

	check_tree_range(repo, "B", "C", false, 0);
	check_tree_range(repo, "B", "C", true, 1);
864 865 866
	check_tree_range(repo, "b", "c", false, 1);
	check_tree_range(repo, "b", "c", true, 1);

867 868
	check_tree_range(repo, "a", "z", false, 3);
	check_tree_range(repo, "a", "z", true, 4);
869 870 871 872 873 874 875 876 877 878 879
	check_tree_range(repo, "A", "Z", false, 1);
	check_tree_range(repo, "A", "Z", true, 4);
	check_tree_range(repo, "a", "Z", false, 0);
	check_tree_range(repo, "a", "Z", true, 4);
	check_tree_range(repo, "A", "z", false, 4);
	check_tree_range(repo, "A", "z", true, 4);

	check_tree_range(repo, "new.txt", "new.txt", true, 1);
	check_tree_range(repo, "new.txt", "new.txt", false, 1);
	check_tree_range(repo, "README", "README", true, 1);
	check_tree_range(repo, "README", "README", false, 1);
880 881 882 883 884 885 886 887 888 889 890
}

static void check_index_range(
	git_repository *repo,
	const char *start,
	const char *end,
	bool ignore_case,
	int expected_count)
{
	git_index *index;
	git_iterator *i;
891
	int error, count, caps;
892 893 894 895 896 897 898 899 900 901
	bool is_ignoring_case;

	cl_git_pass(git_repository_index(&index, repo));

	caps = git_index_caps(index);
	is_ignoring_case = ((caps & GIT_INDEXCAP_IGNORE_CASE) != 0);

	if (ignore_case != is_ignoring_case)
		cl_git_pass(git_index_set_caps(index, caps ^ GIT_INDEXCAP_IGNORE_CASE));

902
	cl_git_pass(git_iterator_for_index(&i, index, 0, start, end));
903 904 905

	cl_assert(git_iterator_ignore_case(i) == ignore_case);

906 907
	for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count)
		/* count em up */;
908

909
	cl_assert_equal_i(GIT_ITEROVER, error);
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
	cl_assert_equal_i(expected_count, count);

	git_iterator_free(i);
	git_index_free(index);
}

void test_diff_iterator__index_handles_icase_range(void)
{
	git_repository *repo;
	git_index *index;
	git_tree *head;

	repo = cl_git_sandbox_init("testrepo");

	/* reset index to match HEAD */
	cl_git_pass(git_repository_head_tree(&head, repo));
	cl_git_pass(git_repository_index(&index, repo));
	cl_git_pass(git_index_read_tree(index, head));
	cl_git_pass(git_index_write(index));
	git_tree_free(head);
	git_index_free(index);

	/* do some ranged iterator checks toggling case sensitivity */
	check_index_range(repo, "B", "C", false, 0);
	check_index_range(repo, "B", "C", true, 1);
	check_index_range(repo, "a", "z", false, 3);
	check_index_range(repo, "a", "z", true, 4);
937
}