iterator.c 24 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
	git_iterator_flag_t flags,
359 360 361 362
	int expected_count,
	const char **expected_names,
	const char **expected_oids)
{
363
	git_index *index;
364 365
	git_iterator *i;
	const git_index_entry *entry;
366
	int error, count = 0, caps;
367
	git_repository *repo = cl_git_sandbox_init(sandbox);
368

369
	cl_git_pass(git_repository_index(&index, repo));
370 371 372
	caps = git_index_caps(index);

	cl_git_pass(git_iterator_for_index(&i, index, flags, start, end));
373

374 375 376
	while (!(error = git_iterator_advance(&entry, i))) {
		cl_assert(entry);

377
		if (expected_names != NULL)
378
			cl_assert_equal_s(expected_names[count], entry->path);
379 380 381 382

		if (expected_oids != NULL) {
			git_oid oid;
			cl_git_pass(git_oid_fromstr(&oid, expected_oids[count]));
383
			cl_assert_equal_oid(&oid, &entry->id);
384 385 386 387 388
		}

		count++;
	}

389 390 391 392
	cl_assert_equal_i(GIT_ITEROVER, error);
	cl_assert(!entry);
	cl_assert_equal_i(expected_count, count);

393
	git_iterator_free(i);
394 395

	cl_assert(caps == git_index_caps(index));
396
	git_index_free(index);
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
}

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",
412 413 414 415 416 417
	"sub/abc",
	"sub/file",
	"sub/sub/file",
	"sub/sub/subsub.txt",
	"sub/subdir_test1",
	"sub/subdir_test2.txt",
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
	"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",
435 436
	"4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d",
	"108bb4e7fd7b16490dc33ff7d972151e73d7166e",
437
	"a0f7217ae99f5ac3e88534f5cea267febc5fa85b",
438 439 440 441 442 443
	"3e42ffc54a663f9401cc25843d6c0e71a33e4249",
	"45b983be36b73c0788dc9cbcb76cbb80fc7bb057",
	"45b983be36b73c0788dc9cbcb76cbb80fc7bb057",
	"9e5bdc47d6a80f2be0ea3049ad74231b94609242",
	"e563cf4758f0d646f1b14b76016aa17fa9e549a4",
	"fb5067b1aef3ac1ada4b379dbcb7d17255df7d78",
444 445 446 447 448 449 450 451 452
	"99eae476896f4907224978b88e5ecaa6c5bb67a9",
	"3e42ffc54a663f9401cc25843d6c0e71a33e4249",
	"e563cf4758f0d646f1b14b76016aa17fa9e549a4",
	"fb5067b1aef3ac1ada4b379dbcb7d17255df7d78",
	"dccada462d3df8ac6de596fb8c896aba9344f941"
};

void test_diff_iterator__index_0(void)
{
453
	index_iterator_test(
454 455
		"attr", NULL, NULL, 0, ARRAY_SIZE(expected_index_0),
		expected_index_0, expected_index_oids_0);
456 457 458 459 460 461 462 463 464 465 466 467 468
}

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",
469
	"a0f7217ae99f5ac3e88534f5cea267febc5fa85b",
470 471 472 473 474
};

void test_diff_iterator__index_range(void)
{
	index_iterator_test(
475 476
		"attr", "root", "root", 0, ARRAY_SIZE(expected_index_range),
		expected_index_range, expected_index_oids_range);
477 478 479 480 481
}

void test_diff_iterator__index_range_empty_0(void)
{
	index_iterator_test(
482
		"attr", "empty", "empty", 0, 0, NULL, NULL);
483 484 485 486 487
}

void test_diff_iterator__index_range_empty_1(void)
{
	index_iterator_test(
488
		"attr", "z_empty_after", NULL, 0, 0, NULL, NULL);
489 490 491 492 493
}

void test_diff_iterator__index_range_empty_2(void)
{
	index_iterator_test(
494
		"attr", NULL, ".aaa_empty_before", 0, 0, NULL, NULL);
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 524 525 526 527 528 529 530
}

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)
{
531
	index_iterator_test(
532 533
		"status", NULL, NULL, 0, ARRAY_SIZE(expected_index_1),
		expected_index_1, expected_index_oids_1);
534 535
}

536 537 538 539 540 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 569 570
static const char *expected_index_cs[] = {
	"B", "D", "F", "H", "J", "L/1", "L/B", "L/D", "L/a", "L/c",
	"a", "c", "e", "g", "i", "k/1", "k/B", "k/D", "k/a", "k/c",
};

static const char *expected_index_ci[] = {
	"a", "B", "c", "D", "e", "F", "g", "H", "i", "J",
	"k/1", "k/a", "k/B", "k/c", "k/D", "L/1", "L/a", "L/B", "L/c", "L/D",
};

void test_diff_iterator__index_case_folding(void)
{
	git_buf path = GIT_BUF_INIT;
	int fs_is_ci = 0;

	cl_git_pass(git_buf_joinpath(&path, cl_fixture("icase"), ".gitted/CoNfIg"));
	fs_is_ci = git_path_exists(path.ptr);
	git_buf_free(&path);

	index_iterator_test(
		"icase", NULL, NULL, 0, ARRAY_SIZE(expected_index_cs),
		fs_is_ci ? expected_index_ci : expected_index_cs, NULL);

	cl_git_sandbox_cleanup();

	index_iterator_test(
		"icase", NULL, NULL, GIT_ITERATOR_IGNORE_CASE,
		ARRAY_SIZE(expected_index_ci), expected_index_ci, NULL);

	cl_git_sandbox_cleanup();

	index_iterator_test(
		"icase", NULL, NULL, GIT_ITERATOR_DONT_IGNORE_CASE,
		ARRAY_SIZE(expected_index_cs), expected_index_cs, NULL);
}
571 572 573 574 575

/* -- WORKDIR ITERATOR TESTS -- */

static void workdir_iterator_test(
	const char *sandbox,
576 577
	const char *start,
	const char *end,
578 579 580 581 582 583 584
	int expected_count,
	int expected_ignores,
	const char **expected_names,
	const char *an_ignored_name)
{
	git_iterator *i;
	const git_index_entry *entry;
585
	int error, count = 0, count_all = 0, count_all_post_reset = 0;
586
	git_repository *repo = cl_git_sandbox_init(sandbox);
587

588
	cl_git_pass(git_iterator_for_workdir(
589
		&i, repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, start, end));
590 591 592 593

	error = git_iterator_current(&entry, i);
	cl_assert((error == 0 && entry != NULL) ||
			  (error == GIT_ITEROVER && entry == NULL));
594 595 596 597

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

598
		if (S_ISDIR(entry->mode)) {
599
			cl_git_pass(git_iterator_advance_into(&entry, i));
600 601 602
			continue;
		}

603
		if (expected_names != NULL)
604
			cl_assert_equal_s(expected_names[count_all], entry->path);
605 606 607 608 609 610 611 612

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

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

613 614 615 616
		error = git_iterator_advance(&entry, i);

		cl_assert((error == 0 && entry != NULL) ||
				  (error == GIT_ITEROVER && entry == NULL));
617 618
	}

619 620 621
	cl_assert_equal_i(expected_count, count);
	cl_assert_equal_i(expected_count + expected_ignores, count_all);

622
	cl_git_pass(git_iterator_reset(i, NULL, NULL));
623 624 625 626

	error = git_iterator_current(&entry, i);
	cl_assert((error == 0 && entry != NULL) ||
			  (error == GIT_ITEROVER && entry == NULL));
627 628 629

	while (entry != NULL) {
		if (S_ISDIR(entry->mode)) {
630
			cl_git_pass(git_iterator_advance_into(&entry, i));
631 632
			continue;
		}
633

634 635 636 637 638
		if (expected_names != NULL)
			cl_assert_equal_s(
				expected_names[count_all_post_reset], entry->path);
		count_all_post_reset++;

639 640 641
		error = git_iterator_advance(&entry, i);
		cl_assert(error == 0 || error == GIT_ITEROVER);
	}
642

643
	cl_assert_equal_i(count_all, count_all_post_reset);
644 645

	git_iterator_free(i);
646 647 648 649
}

void test_diff_iterator__workdir_0(void)
{
650
	workdir_iterator_test("attr", NULL, NULL, 23, 5, NULL, "ign");
651 652 653 654 655 656 657 658 659 660 661 662
}

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",
663
	"subdir.txt",
664 665 666
	"subdir/current_file",
	"subdir/modified_file",
	"subdir/new_file",
667
	"\xe8\xbf\x99",
668 669 670 671 672
	NULL
};

void test_diff_iterator__workdir_1(void)
{
673
	workdir_iterator_test(
674
		"status", NULL, NULL, 13, 1, status_paths, "ignored_file");
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
}

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",
721
	"\xe8\xbf\x99",
722 723 724 725 726 727
	NULL
};

void test_diff_iterator__workdir_1_ranged_4(void)
{
	workdir_iterator_test(
728
		"status", "subdir/", NULL, 4, 0, status_paths_range_4, NULL);
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
}

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(
746
		"status", "\xff_does_not_exist", NULL,
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
		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);
762
}
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782

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 },
783
		{ "sub/", false },
784 785 786 787 788
		{ "sub/.gitattributes", false },
		{ "sub/abc", false },
		{ "sub/dir/", true },
		{ "sub/file", false },
		{ "sub/ign/", true },
789
		{ "sub/sub/", false },
790 791 792 793 794 795 796 797 798
		{ "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");

799
	cl_git_pass(git_iterator_for_workdir(
800
		&i, repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, "dir", "sub/sub/file"));
801
	cl_git_pass(git_iterator_current(&entry, i));
802 803 804 805 806 807 808

	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);

809 810 811 812 813
		if (!ignored &&
			(entry->mode == GIT_FILEMODE_TREE ||
			 entry->mode == GIT_FILEMODE_COMMIT))
		{
			/* it is possible to advance "into" a submodule */
814
			cl_git_pass(git_iterator_advance_into(&entry, i));
815 816 817 818
		} else {
			int error = git_iterator_advance(&entry, i);
			cl_assert(!error || error == GIT_ITEROVER);
		}
819 820 821 822 823 824
	}

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

	git_iterator_free(i);
}
825

826
static void check_wd_first_through_third_range(
827 828 829 830
	git_repository *repo, const char *start, const char *end)
{
	git_iterator *i;
	const git_index_entry *entry;
831
	int error, idx;
832
	static const char *expected[] = { "FIRST", "second", "THIRD", NULL };
833

834
	cl_git_pass(git_iterator_for_workdir(
835
		&i, repo, NULL, NULL, GIT_ITERATOR_IGNORE_CASE, start, end));
836
	cl_git_pass(git_iterator_current(&entry, i));
837 838 839 840

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

841 842
		error = git_iterator_advance(&entry, i);
		cl_assert(!error || error == GIT_ITEROVER);
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863
	}

	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");

864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
	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;
880
	int error, count;
881 882 883

	cl_git_pass(git_repository_head_tree(&head, repo));

884
	cl_git_pass(git_iterator_for_tree(
885 886 887 888
		&i, head,
		ignore_case ? GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE,
		start, end));

889 890
	for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count)
		/* count em up */;
891

892
	cl_assert_equal_i(GIT_ITEROVER, error);
893 894 895 896 897 898 899 900 901 902 903 904 905 906
	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);
907 908 909
	check_tree_range(repo, "b", "c", false, 1);
	check_tree_range(repo, "b", "c", true, 1);

910 911
	check_tree_range(repo, "a", "z", false, 3);
	check_tree_range(repo, "a", "z", true, 4);
912 913 914 915 916 917 918 919 920 921 922
	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);
923 924 925 926 927 928 929 930 931 932 933
}

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;
934
	int error, count, caps;
935 936 937 938 939 940 941 942 943 944
	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));

945
	cl_git_pass(git_iterator_for_index(&i, index, 0, start, end));
946 947 948

	cl_assert(git_iterator_ignore_case(i) == ignore_case);

949 950
	for (count = 0; !(error = git_iterator_advance(NULL, i)); ++count)
		/* count em up */;
951

952
	cl_assert_equal_i(GIT_ITEROVER, error);
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
	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);
980
}