blob.c 31.4 KB
Newer Older
1 2 3
#include "clar_libgit2.h"
#include "diff_helpers.h"

4 5 6 7 8 9 10 11 12 13 14 15 16
#define BLOB_DIFF \
    "diff --git a/file b/file\n" \
    "index 45141a7..4d713dc 100644\n" \
    "--- a/file\n" \
    "+++ b/file\n" \
    "@@ -1 +1,6 @@\n" \
    " Hello from the root\n" \
    "+\n" \
    "+Some additional lines\n" \
    "+\n" \
    "+Down here below\n" \
    "+\n"

17
static git_repository *g_repo = NULL;
nulltoken committed
18
static diff_expects expected;
19
static git_diff_options opts;
20
static git_blob *d, *alien;
21

22 23 24 25 26 27 28 29 30 31 32
static void quick_diff_blob_to_str(
	const git_blob *blob, const char *blob_path,
	const char *str, size_t len, const char *str_path)
{
	memset(&expected, 0, sizeof(expected));

	if (str && !len)
		len = strlen(str);

	cl_git_pass(git_diff_blob_to_buffer(
		blob, blob_path, str, len, str_path,
33
		&opts, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
34 35
}

36 37
void test_diff_blob__initialize(void)
{
38
	git_oid oid;
39

40
	g_repo = cl_git_sandbox_init("attr");
41

42
	cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION));
43 44
	opts.context_lines = 1;

nulltoken committed
45
	memset(&expected, 0, sizeof(expected));
46 47

	/* tests/resources/attr/root_test4.txt */
48
	cl_git_pass(git_oid_fromstrn(&oid, "a0f7217a", 8));
49
	cl_git_pass(git_blob_lookup_prefix(&d, g_repo, &oid, 8));
50 51 52

	/* alien.png */
	cl_git_pass(git_oid_fromstrn(&oid, "edf3dcee", 8));
53
	cl_git_pass(git_blob_lookup_prefix(&alien, g_repo, &oid, 8));
54 55 56 57
}

void test_diff_blob__cleanup(void)
{
58
	git_blob_free(d);
59 60
	d = NULL;

61
	git_blob_free(alien);
62
	alien = NULL;
63

64
	cl_git_sandbox_cleanup();
65 66
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80
static void assert_one_modified(
	int hunks, int lines, int ctxt, int adds, int dels, diff_expects *exp)
{
	cl_assert_equal_i(1, exp->files);
	cl_assert_equal_i(1, exp->file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(0, exp->files_binary);

	cl_assert_equal_i(hunks, exp->hunks);
	cl_assert_equal_i(lines, exp->lines);
	cl_assert_equal_i(ctxt,  exp->line_ctxt);
	cl_assert_equal_i(adds,  exp->line_adds);
	cl_assert_equal_i(dels,  exp->line_dels);
}

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
void test_diff_blob__patch_with_freed_blobs(void)
{
	git_oid a_oid, b_oid;
	git_blob *a, *b;
	git_patch *p;
	git_buf buf = GIT_BUF_INIT;

	/* tests/resources/attr/root_test1 */
	cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
	/* tests/resources/attr/root_test2 */
	cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
	cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));

	cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, NULL));

	git_blob_free(a);
	git_blob_free(b);

	cl_git_pass(git_patch_to_buf(&buf, p));
	cl_assert_equal_s(buf.ptr, BLOB_DIFF);

	git_patch_free(p);
104
	git_buf_dispose(&buf);
105 106
}

107
void test_diff_blob__can_compare_text_blobs(void)
108
{
109 110
	git_blob *a, *b, *c;
	git_oid a_oid, b_oid, c_oid;
111 112 113 114 115 116 117 118 119 120 121

	/* tests/resources/attr/root_test1 */
	cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));

	/* tests/resources/attr/root_test2 */
	cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
	cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));

	/* tests/resources/attr/root_test3 */
	cl_git_pass(git_oid_fromstrn(&c_oid, "c96bbb2c2557a832", 16));
122
	cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 16));
123 124 125

	/* Doing the equivalent of a `git diff -U1` on these files */

126
	/* diff on tests/resources/attr/root_test1 */
127
	memset(&expected, 0, sizeof(expected));
128
	cl_git_pass(git_diff_blobs(
129
		a, NULL, b, NULL, &opts,
130
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
131
	assert_one_modified(1, 6, 1, 5, 0, &expected);
132

133 134 135 136 137
	/* same diff but use direct buffers */
	memset(&expected, 0, sizeof(expected));
	cl_git_pass(git_diff_buffers(
		git_blob_rawcontent(a), (size_t)git_blob_rawsize(a), NULL,
		git_blob_rawcontent(b), (size_t)git_blob_rawsize(b), NULL, &opts,
138
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
139
	assert_one_modified(1, 6, 1, 5, 0, &expected);
140

141
	/* diff on tests/resources/attr/root_test2 */
nulltoken committed
142
	memset(&expected, 0, sizeof(expected));
143
	cl_git_pass(git_diff_blobs(
144
		b, NULL, c, NULL, &opts,
145
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
146
	assert_one_modified(1, 15, 3, 9, 3, &expected);
147

148
	/* diff on tests/resources/attr/root_test3 */
nulltoken committed
149
	memset(&expected, 0, sizeof(expected));
150
	cl_git_pass(git_diff_blobs(
151
		a, NULL, c, NULL, &opts,
152
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
153
	assert_one_modified(1, 13, 0, 12, 1, &expected);
154

nulltoken committed
155
	memset(&expected, 0, sizeof(expected));
156
	cl_git_pass(git_diff_blobs(
157
		c, NULL, d, NULL, &opts,
158
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
159
	assert_one_modified(2, 14, 4, 6, 4, &expected);
160 161 162 163 164 165

	git_blob_free(a);
	git_blob_free(b);
	git_blob_free(c);
}

166 167 168 169 170 171 172 173 174 175 176 177 178
static void assert_patch_matches_blobs(
	git_patch *p, git_blob *a, git_blob *b,
	int hunks, int l0, int l1, int ctxt, int adds, int dels)
{
	const git_diff_delta *delta;
	size_t tc, ta, td;

	cl_assert(p != NULL);

	delta = git_patch_get_delta(p);
	cl_assert(delta != NULL);

	cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
179
	cl_assert_equal_oid(git_blob_id(a), &delta->old_file.id);
180
	cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
181
	cl_assert_equal_oid(git_blob_id(b), &delta->new_file.id);
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
	cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size);

	cl_assert_equal_i(hunks, (int)git_patch_num_hunks(p));

	if (hunks > 0)
		cl_assert_equal_i(l0, git_patch_num_lines_in_hunk(p, 0));
	if (hunks > 1)
		cl_assert_equal_i(l1, git_patch_num_lines_in_hunk(p, 1));

	cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(ctxt, (int)tc);
	cl_assert_equal_i(adds, (int)ta);
	cl_assert_equal_i(dels, (int)td);
}

197 198 199 200
void test_diff_blob__can_compare_text_blobs_with_patch(void)
{
	git_blob *a, *b, *c;
	git_oid a_oid, b_oid, c_oid;
201
	git_patch *p;
202 203 204

	/* tests/resources/attr/root_test1 */
	cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
205
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
206 207 208

	/* tests/resources/attr/root_test2 */
	cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
209
	cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 8));
210 211 212

	/* tests/resources/attr/root_test3 */
	cl_git_pass(git_oid_fromstrn(&c_oid, "c96bbb2c2557a832", 16));
213
	cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 16));
214 215 216 217

	/* Doing the equivalent of a `git diff -U1` on these files */

	/* diff on tests/resources/attr/root_test1 */
218
	cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, &opts));
219
	assert_patch_matches_blobs(p, a, b, 1, 6, 0, 1, 5, 0);
220
	git_patch_free(p);
221 222

	/* diff on tests/resources/attr/root_test2 */
223
	cl_git_pass(git_patch_from_blobs(&p, b, NULL, c, NULL, &opts));
224
	assert_patch_matches_blobs(p, b, c, 1, 15, 0, 3, 9, 3);
225
	git_patch_free(p);
226 227

	/* diff on tests/resources/attr/root_test3 */
228
	cl_git_pass(git_patch_from_blobs(&p, a, NULL, c, NULL, &opts));
229
	assert_patch_matches_blobs(p, a, c, 1, 13, 0, 0, 12, 1);
230
	git_patch_free(p);
231 232

	/* one more */
233
	cl_git_pass(git_patch_from_blobs(&p, c, NULL, d, NULL, &opts));
234
	assert_patch_matches_blobs(p, c, d, 2, 5, 9, 4, 6, 4);
235
	git_patch_free(p);
236 237 238 239 240 241

	git_blob_free(a);
	git_blob_free(b);
	git_blob_free(c);
}

242 243 244 245 246
void test_diff_blob__can_compare_against_null_blobs(void)
{
	git_blob *e = NULL;

	cl_git_pass(git_diff_blobs(
247
		d, NULL, e, NULL, &opts,
248
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
249

Russell Belfer committed
250
	cl_assert_equal_i(1, expected.files);
251 252
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_DELETED]);
	cl_assert_equal_i(0, expected.files_binary);
253

Russell Belfer committed
254 255 256 257
	cl_assert_equal_i(1, expected.hunks);
	cl_assert_equal_i(14, expected.hunk_old_lines);
	cl_assert_equal_i(14, expected.lines);
	cl_assert_equal_i(14, expected.line_dels);
258 259

	opts.flags |= GIT_DIFF_REVERSE;
nulltoken committed
260
	memset(&expected, 0, sizeof(expected));
261 262

	cl_git_pass(git_diff_blobs(
263
		d, NULL, e, NULL, &opts,
264
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
265

Russell Belfer committed
266
	cl_assert_equal_i(1, expected.files);
267 268
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_ADDED]);
	cl_assert_equal_i(0, expected.files_binary);
269

Russell Belfer committed
270 271 272 273
	cl_assert_equal_i(1, expected.hunks);
	cl_assert_equal_i(14, expected.hunk_new_lines);
	cl_assert_equal_i(14, expected.lines);
	cl_assert_equal_i(14, expected.line_adds);
274 275

	opts.flags ^= GIT_DIFF_REVERSE;
nulltoken committed
276
	memset(&expected, 0, sizeof(expected));
277 278

	cl_git_pass(git_diff_blobs(
279
		alien, NULL, NULL, NULL, &opts,
280
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
281

Russell Belfer committed
282
	cl_assert_equal_i(1, expected.files);
283 284
	cl_assert_equal_i(1, expected.files_binary);
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_DELETED]);
Russell Belfer committed
285 286
	cl_assert_equal_i(0, expected.hunks);
	cl_assert_equal_i(0, expected.lines);
287

nulltoken committed
288
	memset(&expected, 0, sizeof(expected));
289 290

	cl_git_pass(git_diff_blobs(
291
		NULL, NULL, alien, NULL, &opts,
292
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
293

Russell Belfer committed
294
	cl_assert_equal_i(1, expected.files);
295 296
	cl_assert_equal_i(1, expected.files_binary);
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_ADDED]);
Russell Belfer committed
297 298
	cl_assert_equal_i(0, expected.hunks);
	cl_assert_equal_i(0, expected.lines);
299 300
}

301 302 303
void test_diff_blob__can_compare_against_null_blobs_with_patch(void)
{
	git_blob *e = NULL;
304
	git_patch *p;
305
	const git_diff_delta *delta;
306 307
	const git_diff_line *line;
	int l, max_l;
308

309
	cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts));
310 311

	cl_assert(p != NULL);
312

Russell Belfer committed
313
	delta = git_patch_get_delta(p);
314 315
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
316
	cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id);
317
	cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size);
318
	cl_assert(git_oid_iszero(&delta->new_file.id));
319 320
	cl_assert_equal_sz(0, delta->new_file.size);

321 322
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0));
323

324 325 326 327
	max_l = git_patch_num_lines_in_hunk(p, 0);
	for (l = 0; l < max_l; ++l) {
		cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l));
		cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin);
328 329
	}

330
	git_patch_free(p);
331 332 333

	opts.flags |= GIT_DIFF_REVERSE;

334
	cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts));
335 336

	cl_assert(p != NULL);
337

Russell Belfer committed
338
	delta = git_patch_get_delta(p);
339 340
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
341
	cl_assert(git_oid_iszero(&delta->old_file.id));
342
	cl_assert_equal_sz(0, delta->old_file.size);
343
	cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id);
344 345
	cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size);

346 347
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0));
348

349 350 351 352
	max_l = git_patch_num_lines_in_hunk(p, 0);
	for (l = 0; l < max_l; ++l) {
		cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l));
		cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin);
353 354
	}

355
	git_patch_free(p);
356 357 358

	opts.flags ^= GIT_DIFF_REVERSE;

359
	cl_git_pass(git_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts));
360 361

	cl_assert(p != NULL);
362

Russell Belfer committed
363
	delta = git_patch_get_delta(p);
364 365 366 367
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
	cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);

368
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
369

370
	git_patch_free(p);
371

372
	cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts));
373 374

	cl_assert(p != NULL);
375

Russell Belfer committed
376
	delta = git_patch_get_delta(p);
377 378 379 380
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
	cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);

381
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
382

383
	git_patch_free(p);
384 385
}

386
static void assert_identical_blobs_comparison(diff_expects *expected)
387
{
388 389 390 391
	cl_assert_equal_i(1, expected->files);
	cl_assert_equal_i(1, expected->file_status[GIT_DELTA_UNMODIFIED]);
	cl_assert_equal_i(0, expected->hunks);
	cl_assert_equal_i(0, expected->lines);
392 393 394 395
}

void test_diff_blob__can_compare_identical_blobs(void)
{
396 397
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;

398
	cl_git_pass(git_diff_blobs(
399
		d, NULL, d, NULL, &opts,
400
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
401

402
	assert_identical_blobs_comparison(&expected);
403
	cl_assert_equal_i(0, expected.files_binary);
404

nulltoken committed
405
	memset(&expected, 0, sizeof(expected));
406
	cl_git_pass(git_diff_blobs(
407
		NULL, NULL, NULL, NULL, &opts,
408
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
409

410
	assert_identical_blobs_comparison(&expected);
411
	cl_assert_equal_i(0, expected.files_binary);
412

nulltoken committed
413
	memset(&expected, 0, sizeof(expected));
414
	cl_git_pass(git_diff_blobs(
415
		alien, NULL, alien, NULL, &opts,
416
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
417

418
	assert_identical_blobs_comparison(&expected);
419
	cl_assert(expected.files_binary > 0);
420 421
}

422 423
void test_diff_blob__can_compare_identical_blobs_with_patch(void)
{
424
	git_patch *p;
425
	const git_diff_delta *delta;
426

427
	cl_git_pass(git_patch_from_blobs(&p, d, NULL, d, NULL, &opts));
428
	cl_assert(p != NULL);
429

Russell Belfer committed
430
	delta = git_patch_get_delta(p);
431 432 433
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
	cl_assert_equal_sz(delta->old_file.size, git_blob_rawsize(d));
434
	cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id);
435
	cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d));
436
	cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id);
437

438 439
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);
440

441
	cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, NULL, NULL, &opts));
442
	cl_assert(p != NULL);
443

Russell Belfer committed
444
	delta = git_patch_get_delta(p);
445 446 447
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
	cl_assert_equal_sz(0, delta->old_file.size);
448
	cl_assert(git_oid_iszero(&delta->old_file.id));
449
	cl_assert_equal_sz(0, delta->new_file.size);
450
	cl_assert(git_oid_iszero(&delta->new_file.id));
451

452 453
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);
454

455
	cl_git_pass(git_patch_from_blobs(&p, alien, NULL, alien, NULL, &opts));
456
	cl_assert(p != NULL);
Russell Belfer committed
457
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status);
458 459
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);
460 461
}

462
static void assert_binary_blobs_comparison(diff_expects *expected)
463
{
464
	cl_assert(expected->files_binary > 0);
465

466 467 468 469
	cl_assert_equal_i(1, expected->files);
	cl_assert_equal_i(1, expected->file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(0, expected->hunks);
	cl_assert_equal_i(0, expected->lines);
470 471 472 473 474 475 476 477 478
}

void test_diff_blob__can_compare_two_binary_blobs(void)
{
	git_blob *heart;
	git_oid h_oid;

	/* heart.png */
	cl_git_pass(git_oid_fromstrn(&h_oid, "de863bff", 8));
479
	cl_git_pass(git_blob_lookup_prefix(&heart, g_repo, &h_oid, 8));
480 481

	cl_git_pass(git_diff_blobs(
482
		alien, NULL, heart, NULL, &opts,
483
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
484

485
	assert_binary_blobs_comparison(&expected);
486

nulltoken committed
487
	memset(&expected, 0, sizeof(expected));
488 489

	cl_git_pass(git_diff_blobs(
490
		heart, NULL, alien, NULL, &opts,
491
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
492

493
	assert_binary_blobs_comparison(&expected);
494 495 496 497 498 499 500

	git_blob_free(heart);
}

void test_diff_blob__can_compare_a_binary_blob_and_a_text_blob(void)
{
	cl_git_pass(git_diff_blobs(
501
		alien, NULL, d, NULL, &opts,
502
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
503

504
	assert_binary_blobs_comparison(&expected);
505

nulltoken committed
506
	memset(&expected, 0, sizeof(expected));
507 508

	cl_git_pass(git_diff_blobs(
509
		d, NULL, alien, NULL, &opts,
510
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
511

512
	assert_binary_blobs_comparison(&expected);
513
}
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546

/*
 * $ git diff fe773770 a0f7217
 * diff --git a/fe773770 b/a0f7217
 * index fe77377..a0f7217 100644
 * --- a/fe773770
 * +++ b/a0f7217
 * @@ -1,6 +1,6 @@
 *  Here is some stuff at the start
 * 
 * -This should go in one hunk
 * +This should go in one hunk (first)
 * 
 *  Some additional lines
 * 
 * @@ -8,7 +8,7 @@ Down here below the other lines
 * 
 *  With even more at the end
 * 
 * -Followed by a second hunk of stuff
 * +Followed by a second hunk of stuff (second)
 * 
 *  That happens down here
 */
void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void)
{
	git_blob *old_d;
	git_oid old_d_oid;

	opts.context_lines = 3;

	/* tests/resources/attr/root_test1 from commit f5b0af1 */
	cl_git_pass(git_oid_fromstrn(&old_d_oid, "fe773770", 8));
547
	cl_git_pass(git_blob_lookup_prefix(&old_d, g_repo, &old_d_oid, 8));
548 549 550

	/* Test with default inter-hunk-context (not set) => default is 0 */
	cl_git_pass(git_diff_blobs(
551
		old_d, NULL, d, NULL, &opts,
552
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
553

Russell Belfer committed
554
	cl_assert_equal_i(2, expected.hunks);
555 556 557 558 559

	/* Test with inter-hunk-context explicitly set to 0 */
	opts.interhunk_lines = 0;
	memset(&expected, 0, sizeof(expected));
	cl_git_pass(git_diff_blobs(
560
		old_d, NULL, d, NULL, &opts,
561
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
562

Russell Belfer committed
563
	cl_assert_equal_i(2, expected.hunks);
564 565 566 567 568

	/* Test with inter-hunk-context explicitly set to 1 */
	opts.interhunk_lines = 1;
	memset(&expected, 0, sizeof(expected));
	cl_git_pass(git_diff_blobs(
569
		old_d, NULL, d, NULL, &opts,
570
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
571

Russell Belfer committed
572
	cl_assert_equal_i(1, expected.hunks);
573 574 575

	git_blob_free(old_d);
}
576 577 578 579 580 581 582

void test_diff_blob__checks_options_version_too_low(void)
{
	const git_error *err;

	opts.version = 0;
	cl_git_fail(git_diff_blobs(
583
		d, NULL, alien, NULL, &opts,
584
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
585 586 587 588 589 590 591 592 593 594
	err = giterr_last();
	cl_assert_equal_i(GITERR_INVALID, err->klass);
}

void test_diff_blob__checks_options_version_too_high(void)
{
	const git_error *err;

	opts.version = 1024;
	cl_git_fail(git_diff_blobs(
595
		d, NULL, alien, NULL, &opts,
596
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
597 598 599
	err = giterr_last();
	cl_assert_equal_i(GITERR_INVALID, err->klass);
}
600 601 602 603 604 605 606 607 608 609 610 611

void test_diff_blob__can_correctly_detect_a_binary_blob_as_binary(void)
{
	/* alien.png */
	cl_assert_equal_i(true, git_blob_is_binary(alien));
}

void test_diff_blob__can_correctly_detect_a_textual_blob_as_non_binary(void)
{
	/* tests/resources/attr/root_test4.txt */
	cl_assert_equal_i(false, git_blob_is_binary(d));
}
612 613 614 615 616

/*
 * git_diff_blob_to_buffer tests
 */

617 618 619 620 621 622 623 624 625 626 627 628 629 630
static void assert_changed_single_one_line_file(
	diff_expects *expected, git_delta_t mod)
{
	cl_assert_equal_i(1, expected->files);
	cl_assert_equal_i(1, expected->file_status[mod]);
	cl_assert_equal_i(1, expected->hunks);
	cl_assert_equal_i(1, expected->lines);

	if (mod == GIT_DELTA_ADDED)
		cl_assert_equal_i(1, expected->line_adds);
	else if (mod == GIT_DELTA_DELETED)
		cl_assert_equal_i(1, expected->line_dels);
}

631 632 633 634 635 636 637 638 639
void test_diff_blob__can_compare_blob_to_buffer(void)
{
	git_blob *a;
	git_oid a_oid;
	const char *a_content = "Hello from the root\n";
	const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";

	/* tests/resources/attr/root_test1 */
	cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
640
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
641 642

	/* diff from blob a to content of b */
643
	quick_diff_blob_to_str(a, NULL, b_content, 0, NULL);
644
	assert_one_modified(1, 6, 1, 5, 0, &expected);
645 646

	/* diff from blob a to content of a */
647 648
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
	quick_diff_blob_to_str(a, NULL, a_content, 0, NULL);
649 650
	assert_identical_blobs_comparison(&expected);

651
	/* diff from NULL blob to content of a */
652
	memset(&expected, 0, sizeof(expected));
653
	quick_diff_blob_to_str(NULL, NULL, a_content, 0, NULL);
654
	assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
655 656 657

	/* diff from blob a to NULL buffer */
	memset(&expected, 0, sizeof(expected));
658
	quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
659
	assert_changed_single_one_line_file(&expected, GIT_DELTA_DELETED);
660 661 662 663 664

	/* diff with reverse */
	opts.flags ^= GIT_DIFF_REVERSE;

	memset(&expected, 0, sizeof(expected));
665
	quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
666
	assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
667 668 669

	git_blob_free(a);
}
670

671 672
void test_diff_blob__can_compare_blob_to_buffer_with_patch(void)
{
673
	git_patch *p;
674 675 676 677 678 679 680 681
	git_blob *a;
	git_oid a_oid;
	const char *a_content = "Hello from the root\n";
	const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";
	size_t tc, ta, td;

	/* tests/resources/attr/root_test1 */
	cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
682
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
683 684

	/* diff from blob a to content of b */
685
	cl_git_pass(git_patch_from_blob_and_buffer(
686
		&p, a, NULL, b_content, strlen(b_content), NULL, &opts));
687 688

	cl_assert(p != NULL);
Russell Belfer committed
689
	cl_assert_equal_i(GIT_DELTA_MODIFIED, git_patch_get_delta(p)->status);
690 691
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(6, git_patch_num_lines_in_hunk(p, 0));
692

693
	cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
694 695 696 697
	cl_assert_equal_i(1, (int)tc);
	cl_assert_equal_i(5, (int)ta);
	cl_assert_equal_i(0, (int)td);

698
	git_patch_free(p);
699 700

	/* diff from blob a to content of a */
701
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
702
	cl_git_pass(git_patch_from_blob_and_buffer(
703
		&p, a, NULL, a_content, strlen(a_content), NULL, &opts));
704
	cl_assert(p != NULL);
Russell Belfer committed
705
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status);
706 707
	cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
	git_patch_free(p);
708 709

	/* diff from NULL blob to content of a */
710
	cl_git_pass(git_patch_from_blob_and_buffer(
711
		&p, NULL, NULL, a_content, strlen(a_content), NULL, &opts));
712
	cl_assert(p != NULL);
Russell Belfer committed
713
	cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
714 715 716
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
	git_patch_free(p);
717 718

	/* diff from blob a to NULL buffer */
719
	cl_git_pass(git_patch_from_blob_and_buffer(
720
		&p, a, NULL, NULL, 0, NULL, &opts));
721
	cl_assert(p != NULL);
Russell Belfer committed
722
	cl_assert_equal_i(GIT_DELTA_DELETED, git_patch_get_delta(p)->status);
723 724 725
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
	git_patch_free(p);
726 727 728 729

	/* diff with reverse */
	opts.flags ^= GIT_DIFF_REVERSE;

730
	cl_git_pass(git_patch_from_blob_and_buffer(
731
		&p, a, NULL, NULL, 0, NULL, &opts));
732
	cl_assert(p != NULL);
Russell Belfer committed
733
	cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
734 735 736
	cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
	cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
	git_patch_free(p);
737 738 739

	git_blob_free(a);
}
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757

static void assert_one_modified_with_lines(diff_expects *expected, int lines)
{
	cl_assert_equal_i(1, expected->files);
	cl_assert_equal_i(1, expected->file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(0, expected->files_binary);
	cl_assert_equal_i(lines, expected->lines);
}

void test_diff_blob__binary_data_comparisons(void)
{
	git_blob *bin, *nonbin;
	git_oid oid;
	const char *nonbin_content = "Hello from the root\n";
	size_t nonbin_len = 20;
	const char *bin_content = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n";
	size_t bin_len = 33;

758 759
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;

760
	cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8));
761
	cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8));
762 763

	cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
764
	cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8));
765 766 767

	/* non-binary to reference content */

768
	quick_diff_blob_to_str(nonbin, NULL, nonbin_content, nonbin_len, NULL);
769 770 771 772 773
	assert_identical_blobs_comparison(&expected);
	cl_assert_equal_i(0, expected.files_binary);

	/* binary to reference content */

774
	quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
775 776 777 778 779 780
	assert_identical_blobs_comparison(&expected);

	cl_assert_equal_i(1, expected.files_binary);

	/* non-binary to binary content */

781
	quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
782 783 784 785
	assert_binary_blobs_comparison(&expected);

	/* binary to non-binary content */

786
	quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
787 788 789 790 791 792
	assert_binary_blobs_comparison(&expected);

	/* non-binary to binary blob */

	memset(&expected, 0, sizeof(expected));
	cl_git_pass(git_diff_blobs(
793
		bin, NULL, nonbin, NULL, &opts,
794
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
795 796 797 798 799 800 801 802
	assert_binary_blobs_comparison(&expected);

	/*
	 * repeat with FORCE_TEXT
	 */

	opts.flags |= GIT_DIFF_FORCE_TEXT;

803
	quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
804 805
	assert_identical_blobs_comparison(&expected);

806
	quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
807 808
	assert_one_modified_with_lines(&expected, 4);

809
	quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
810 811 812 813
	assert_one_modified_with_lines(&expected, 4);

	memset(&expected, 0, sizeof(expected));
	cl_git_pass(git_diff_blobs(
814
		bin, NULL, nonbin, NULL, &opts,
815
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
816 817 818 819 820 821
	assert_one_modified_with_lines(&expected, 4);

	/* cleanup */
	git_blob_free(bin);
	git_blob_free(nonbin);
}
822 823 824 825 826 827 828 829 830 831 832

void test_diff_blob__using_path_and_attributes(void)
{
	git_config *cfg;
	git_blob *bin, *nonbin;
	git_oid oid;
	const char *nonbin_content = "Hello from the root\n";
	const char *bin_content =
		"0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n";
	size_t bin_len = 33;
	const char *changed;
833
	git_patch *p;
Nicolas Hake committed
834
	git_buf buf = GIT_BUF_INIT;
835 836 837 838 839 840 841

	/* set up custom diff drivers and 'diff' attribute mappings for them */

	cl_git_pass(git_repository_config(&cfg, g_repo));
	cl_git_pass(git_config_set_bool(cfg, "diff.iam_binary.binary", 1));
	cl_git_pass(git_config_set_bool(cfg, "diff.iam_text.binary", 0));
	cl_git_pass(git_config_set_string(
842
		cfg, "diff.iam_alphactx.xfuncname", "^[A-Za-z].*$"));
843 844
	cl_git_pass(git_config_set_bool(cfg, "diff.iam_textalpha.binary", 0));
	cl_git_pass(git_config_set_string(
845
		cfg, "diff.iam_textalpha.xfuncname", "^[A-Za-z].*$"));
846
	cl_git_pass(git_config_set_string(
847
		cfg, "diff.iam_numctx.funcname", "^[0-9][0-9]*"));
848 849
	cl_git_pass(git_config_set_bool(cfg, "diff.iam_textnum.binary", 0));
	cl_git_pass(git_config_set_string(
850
		cfg, "diff.iam_textnum.funcname", "^[0-9][0-9]*"));
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
	git_config_free(cfg);

	cl_git_append2file(
		"attr/.gitattributes",
		"\n\n# test_diff_blob__using_path_and_attributes extra\n\n"
		"*.binary  diff=iam_binary\n"
		"*.textary diff=iam_text\n"
		"*.alphary diff=iam_alphactx\n"
		"*.textalphary diff=iam_textalpha\n"
		"*.textnumary diff=iam_textnum\n"
		"*.numary  diff=iam_numctx\n\n");

	opts.context_lines = 0;
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;

	cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8));
867
	cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8));
868 869 870
	/* 20b: "Hello from the root\n" */

	cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
871
	cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8));
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
	/* 33b: "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\n0123456789\n" */

	/* non-binary to reference content */

	quick_diff_blob_to_str(nonbin, NULL, nonbin_content, 0, NULL);
	assert_identical_blobs_comparison(&expected);
	cl_assert_equal_i(0, expected.files_binary);

	/* binary to reference content */

	quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
	assert_identical_blobs_comparison(&expected);
	cl_assert_equal_i(1, expected.files_binary);

	/* add some text */

	changed = "Hello from the root\nMore lines\nAnd more\nGo here\n";

	quick_diff_blob_to_str(nonbin, NULL, changed, 0, NULL);
891
	assert_one_modified(1, 3, 0, 3, 0, &expected);
892 893 894 895 896 897 898 899 900

	quick_diff_blob_to_str(nonbin, "foo/bar.binary", changed, 0, NULL);
	cl_assert_equal_i(1, expected.files);
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(1, expected.files_binary);
	cl_assert_equal_i(0, expected.hunks);
	cl_assert_equal_i(0, expected.lines);

	quick_diff_blob_to_str(nonbin, "foo/bar.textary", changed, 0, NULL);
901
	assert_one_modified(1, 3, 0, 3, 0, &expected);
902 903

	quick_diff_blob_to_str(nonbin, "foo/bar.alphary", changed, 0, NULL);
904
	assert_one_modified(1, 3, 0, 3, 0, &expected);
905

906
	cl_git_pass(git_patch_from_blob_and_buffer(
907
		&p, nonbin, "zzz.normal", changed, strlen(changed), NULL, &opts));
Nicolas Hake committed
908
	cl_git_pass(git_patch_to_buf(&buf, p));
909 910 911 912 913 914 915 916
	cl_assert_equal_s(
		"diff --git a/zzz.normal b/zzz.normal\n"
		"index 45141a7..75b0dbb 100644\n"
		"--- a/zzz.normal\n"
		"+++ b/zzz.normal\n"
		"@@ -1,0 +2,3 @@ Hello from the root\n"
		"+More lines\n"
		"+And more\n"
Nicolas Hake committed
917 918
		"+Go here\n", buf.ptr);
	git_buf_clear(&buf);
919
	git_patch_free(p);
920

921
	cl_git_pass(git_patch_from_blob_and_buffer(
922
		&p, nonbin, "zzz.binary", changed, strlen(changed), NULL, &opts));
Nicolas Hake committed
923
	cl_git_pass(git_patch_to_buf(&buf, p));
924 925 926
	cl_assert_equal_s(
		"diff --git a/zzz.binary b/zzz.binary\n"
		"index 45141a7..75b0dbb 100644\n"
Nicolas Hake committed
927 928
		"Binary files a/zzz.binary and b/zzz.binary differ\n", buf.ptr);
	git_buf_clear(&buf);
929
	git_patch_free(p);
930

931
	cl_git_pass(git_patch_from_blob_and_buffer(
932
		&p, nonbin, "zzz.alphary", changed, strlen(changed), NULL, &opts));
Nicolas Hake committed
933
	cl_git_pass(git_patch_to_buf(&buf, p));
934 935 936 937 938 939 940 941
	cl_assert_equal_s(
		"diff --git a/zzz.alphary b/zzz.alphary\n"
		"index 45141a7..75b0dbb 100644\n"
		"--- a/zzz.alphary\n"
		"+++ b/zzz.alphary\n"
		"@@ -1,0 +2,3 @@ Hello from the root\n"
		"+More lines\n"
		"+And more\n"
Nicolas Hake committed
942 943
		"+Go here\n", buf.ptr);
	git_buf_clear(&buf);
944
	git_patch_free(p);
945

946
	cl_git_pass(git_patch_from_blob_and_buffer(
947
		&p, nonbin, "zzz.numary", changed, strlen(changed), NULL, &opts));
Nicolas Hake committed
948
	cl_git_pass(git_patch_to_buf(&buf, p));
949 950 951 952 953 954 955 956
	cl_assert_equal_s(
		"diff --git a/zzz.numary b/zzz.numary\n"
		"index 45141a7..75b0dbb 100644\n"
		"--- a/zzz.numary\n"
		"+++ b/zzz.numary\n"
		"@@ -1,0 +2,3 @@\n"
		"+More lines\n"
		"+And more\n"
Nicolas Hake committed
957 958
		"+Go here\n", buf.ptr);
	git_buf_clear(&buf);
959
	git_patch_free(p);
960 961 962 963 964 965 966

	/* "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n"
	 * 33 bytes
	 */

	changed = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\nreplace a line\n";

967
	cl_git_pass(git_patch_from_blob_and_buffer(
968
		&p, bin, "zzz.normal", changed, 37, NULL, &opts));
Nicolas Hake committed
969
	cl_git_pass(git_patch_to_buf(&buf, p));
970 971 972
	cl_assert_equal_s(
		"diff --git a/zzz.normal b/zzz.normal\n"
		"index b435cd5..1604519 100644\n"
Nicolas Hake committed
973 974
		"Binary files a/zzz.normal and b/zzz.normal differ\n", buf.ptr);
	git_buf_clear(&buf);
975
	git_patch_free(p);
976

977
	cl_git_pass(git_patch_from_blob_and_buffer(
978
		&p, bin, "zzz.textary", changed, 37, NULL, &opts));
Nicolas Hake committed
979
	cl_git_pass(git_patch_to_buf(&buf, p));
980 981 982 983 984 985 986
	cl_assert_equal_s(
		"diff --git a/zzz.textary b/zzz.textary\n"
		"index b435cd5..1604519 100644\n"
		"--- a/zzz.textary\n"
		"+++ b/zzz.textary\n"
		"@@ -3 +3 @@\n"
		"-0123456789\n"
Nicolas Hake committed
987 988
		"+replace a line\n", buf.ptr);
	git_buf_clear(&buf);
989
	git_patch_free(p);
990

991
	cl_git_pass(git_patch_from_blob_and_buffer(
992
		&p, bin, "zzz.textalphary", changed, 37, NULL, &opts));
Nicolas Hake committed
993
	cl_git_pass(git_patch_to_buf(&buf, p));
994 995 996 997 998 999 1000
	cl_assert_equal_s(
		"diff --git a/zzz.textalphary b/zzz.textalphary\n"
		"index b435cd5..1604519 100644\n"
		"--- a/zzz.textalphary\n"
		"+++ b/zzz.textalphary\n"
		"@@ -3 +3 @@\n"
		"-0123456789\n"
Nicolas Hake committed
1001 1002
		"+replace a line\n", buf.ptr);
	git_buf_clear(&buf);
1003
	git_patch_free(p);
1004

1005
	cl_git_pass(git_patch_from_blob_and_buffer(
1006
		&p, bin, "zzz.textnumary", changed, 37, NULL, &opts));
Nicolas Hake committed
1007
	cl_git_pass(git_patch_to_buf(&buf, p));
1008 1009 1010 1011 1012 1013 1014
	cl_assert_equal_s(
		"diff --git a/zzz.textnumary b/zzz.textnumary\n"
		"index b435cd5..1604519 100644\n"
		"--- a/zzz.textnumary\n"
		"+++ b/zzz.textnumary\n"
		"@@ -3 +3 @@ 0123456789\n"
		"-0123456789\n"
Nicolas Hake committed
1015 1016
		"+replace a line\n", buf.ptr);
	git_buf_clear(&buf);
1017
	git_patch_free(p);
1018

1019
	git_buf_dispose(&buf);
1020 1021 1022
	git_blob_free(nonbin);
	git_blob_free(bin);
}
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034

void test_diff_blob__can_compare_buffer_to_buffer(void)
{
	const char *a = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n";
	const char *b = "a\nB\nc\nd\nE\nF\nh\nj\nk\n";

	opts.interhunk_lines = 0;
	opts.context_lines = 0;

	memset(&expected, 0, sizeof(expected));

	cl_git_pass(git_diff_buffers(
1035 1036
		a, strlen(a), NULL, b, strlen(b), NULL, &opts,
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
1037 1038 1039 1040 1041 1042 1043
	assert_one_modified(4, 9, 0, 4, 5, &expected);

	opts.flags ^= GIT_DIFF_REVERSE;

	memset(&expected, 0, sizeof(expected));

	cl_git_pass(git_diff_buffers(
1044 1045
		a, strlen(a), NULL, b, strlen(b), NULL, &opts,
		diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
1046 1047
	assert_one_modified(4, 9, 0, 5, 4, &expected);
}