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

static git_repository *g_repo = NULL;
nulltoken committed
5
static diff_expects expected;
6
static git_diff_options opts;
7
static git_blob *d, *alien;
8

9 10 11 12 13 14 15 16 17 18 19 20 21 22
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,
		&opts, diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
}

23 24
void test_diff_blob__initialize(void)
{
25
	git_oid oid;
26

27
	g_repo = cl_git_sandbox_init("attr");
28

Ben Straub committed
29
	GIT_INIT_STRUCTURE(&opts, GIT_DIFF_OPTIONS_VERSION);
30
	opts.context_lines = 1;
31
	opts.interhunk_lines = 0;
32

nulltoken committed
33
	memset(&expected, 0, sizeof(expected));
34 35

	/* tests/resources/attr/root_test4.txt */
36 37
	cl_git_pass(git_oid_fromstrn(&oid, "a0f7217a", 8));
	cl_git_pass(git_blob_lookup_prefix(&d, g_repo, &oid, 4));
38 39 40 41

	/* alien.png */
	cl_git_pass(git_oid_fromstrn(&oid, "edf3dcee", 8));
	cl_git_pass(git_blob_lookup_prefix(&alien, g_repo, &oid, 4));
42 43 44 45
}

void test_diff_blob__cleanup(void)
{
46
	git_blob_free(d);
47 48
	d = NULL;

49
	git_blob_free(alien);
50
	alien = NULL;
51

52
	cl_git_sandbox_cleanup();
53 54
}

55
void test_diff_blob__can_compare_text_blobs(void)
56
{
57 58
	git_blob *a, *b, *c;
	git_oid a_oid, b_oid, c_oid;
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

	/* 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));
	cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 8));

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

74
	/* diff on tests/resources/attr/root_test1 */
75
	cl_git_pass(git_diff_blobs(
76 77
		a, NULL, b, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
78

Russell Belfer committed
79
	cl_assert_equal_i(1, expected.files);
80 81
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(0, expected.files_binary);
82

Russell Belfer committed
83 84 85 86 87
	cl_assert_equal_i(1, expected.hunks);
	cl_assert_equal_i(6, expected.lines);
	cl_assert_equal_i(1, expected.line_ctxt);
	cl_assert_equal_i(5, expected.line_adds);
	cl_assert_equal_i(0, expected.line_dels);
88

89
	/* diff on tests/resources/attr/root_test2 */
nulltoken committed
90
	memset(&expected, 0, sizeof(expected));
91
	cl_git_pass(git_diff_blobs(
92 93
		b, NULL, c, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
94

Russell Belfer committed
95
	cl_assert_equal_i(1, expected.files);
96 97
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(0, expected.files_binary);
98

Russell Belfer committed
99 100 101 102 103
	cl_assert_equal_i(1, expected.hunks);
	cl_assert_equal_i(15, expected.lines);
	cl_assert_equal_i(3, expected.line_ctxt);
	cl_assert_equal_i(9, expected.line_adds);
	cl_assert_equal_i(3, expected.line_dels);
104

105
	/* diff on tests/resources/attr/root_test3 */
nulltoken committed
106
	memset(&expected, 0, sizeof(expected));
107
	cl_git_pass(git_diff_blobs(
108 109
		a, NULL, c, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
110

Russell Belfer committed
111
	cl_assert_equal_i(1, expected.files);
112 113
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(0, expected.files_binary);
114

Russell Belfer committed
115 116 117 118 119
	cl_assert_equal_i(1, expected.hunks);
	cl_assert_equal_i(13, expected.lines);
	cl_assert_equal_i(0, expected.line_ctxt);
	cl_assert_equal_i(12, expected.line_adds);
	cl_assert_equal_i(1, expected.line_dels);
120

nulltoken committed
121
	memset(&expected, 0, sizeof(expected));
122
	cl_git_pass(git_diff_blobs(
123 124
		c, NULL, d, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
125

Russell Belfer committed
126
	cl_assert_equal_i(1, expected.files);
127 128
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
	cl_assert_equal_i(0, expected.files_binary);
129

Russell Belfer committed
130 131 132 133 134
	cl_assert_equal_i(2, expected.hunks);
	cl_assert_equal_i(14, expected.lines);
	cl_assert_equal_i(4, expected.line_ctxt);
	cl_assert_equal_i(6, expected.line_adds);
	cl_assert_equal_i(4, expected.line_dels);
135 136 137 138 139 140

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

141 142 143 144 145
void test_diff_blob__can_compare_text_blobs_with_patch(void)
{
	git_blob *a, *b, *c;
	git_oid a_oid, b_oid, c_oid;
	git_diff_patch *p;
146
	const git_diff_delta *delta;
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	size_t tc, ta, td;

	/* 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));
	cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 8));

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

	/* diff on tests/resources/attr/root_test1 */
164
	cl_git_pass(git_diff_patch_from_blobs(&p, a, NULL, b, NULL, &opts));
165 166

	cl_assert(p != NULL);
167 168 169 170 171 172 173 174 175

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
	cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
	cl_assert(git_oid_equal(git_blob_id(b), &delta->new_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size);

176 177 178 179 180 181 182 183 184 185 186
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(6, git_diff_patch_num_lines_in_hunk(p, 0));

	cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(1, (int)tc);
	cl_assert_equal_i(5, (int)ta);
	cl_assert_equal_i(0, (int)td);

	git_diff_patch_free(p);

	/* diff on tests/resources/attr/root_test2 */
187
	cl_git_pass(git_diff_patch_from_blobs(&p, b, NULL, c, NULL, &opts));
188 189

	cl_assert(p != NULL);
190 191 192 193 194 195 196 197 198

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
	cl_assert(git_oid_equal(git_blob_id(b), &delta->old_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(b), delta->old_file.size);
	cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size);

199 200 201 202 203 204 205 206 207 208 209
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(15, git_diff_patch_num_lines_in_hunk(p, 0));

	cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(3, (int)tc);
	cl_assert_equal_i(9, (int)ta);
	cl_assert_equal_i(3, (int)td);

	git_diff_patch_free(p);

	/* diff on tests/resources/attr/root_test3 */
210
	cl_git_pass(git_diff_patch_from_blobs(&p, a, NULL, c, NULL, &opts));
211 212

	cl_assert(p != NULL);
213 214 215 216 217 218 219 220

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
	cl_assert(git_oid_equal(git_blob_id(a), &delta->old_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
	cl_assert(git_oid_equal(git_blob_id(c), &delta->new_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(c), delta->new_file.size);
221 222 223 224 225 226 227 228 229

	cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(0, (int)tc);
	cl_assert_equal_i(12, (int)ta);
	cl_assert_equal_i(1, (int)td);

	git_diff_patch_free(p);

	/* one more */
230
	cl_git_pass(git_diff_patch_from_blobs(&p, c, NULL, d, NULL, &opts));
231 232

	cl_assert(p != NULL);
233 234 235 236 237 238 239 240 241

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
	cl_assert(git_oid_equal(git_blob_id(c), &delta->old_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(c), delta->old_file.size);
	cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size);

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
	cl_assert_equal_i(2, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(5, git_diff_patch_num_lines_in_hunk(p, 0));
	cl_assert_equal_i(9, git_diff_patch_num_lines_in_hunk(p, 1));

	cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(4, (int)tc);
	cl_assert_equal_i(6, (int)ta);
	cl_assert_equal_i(4, (int)td);

	git_diff_patch_free(p);

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

258 259 260 261 262
void test_diff_blob__can_compare_against_null_blobs(void)
{
	git_blob *e = NULL;

	cl_git_pass(git_diff_blobs(
263 264
		d, NULL, e, NULL, &opts,
		diff_file_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_DELETED]);
	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_old_lines);
	cl_assert_equal_i(14, expected.lines);
	cl_assert_equal_i(14, expected.line_dels);
274 275

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

	cl_git_pass(git_diff_blobs(
279 280
		d, NULL, e, NULL, &opts,
		diff_file_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.file_status[GIT_DELTA_ADDED]);
	cl_assert_equal_i(0, expected.files_binary);
285

Russell Belfer committed
286 287 288 289
	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);
290 291

	opts.flags ^= GIT_DIFF_REVERSE;
nulltoken committed
292
	memset(&expected, 0, sizeof(expected));
293 294

	cl_git_pass(git_diff_blobs(
295 296
		alien, NULL, NULL, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
297

Russell Belfer committed
298
	cl_assert_equal_i(1, expected.files);
299 300
	cl_assert_equal_i(1, expected.files_binary);
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_DELETED]);
Russell Belfer committed
301 302
	cl_assert_equal_i(0, expected.hunks);
	cl_assert_equal_i(0, expected.lines);
303

nulltoken committed
304
	memset(&expected, 0, sizeof(expected));
305 306

	cl_git_pass(git_diff_blobs(
307 308
		NULL, NULL, alien, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
309

Russell Belfer committed
310
	cl_assert_equal_i(1, expected.files);
311 312
	cl_assert_equal_i(1, expected.files_binary);
	cl_assert_equal_i(1, expected.file_status[GIT_DELTA_ADDED]);
Russell Belfer committed
313 314
	cl_assert_equal_i(0, expected.hunks);
	cl_assert_equal_i(0, expected.lines);
315 316
}

317 318 319 320
void test_diff_blob__can_compare_against_null_blobs_with_patch(void)
{
	git_blob *e = NULL;
	git_diff_patch *p;
321
	const git_diff_delta *delta;
322 323 324
	int line;
	char origin;

325
	cl_git_pass(git_diff_patch_from_blobs(&p, d, NULL, e, NULL, &opts));
326 327

	cl_assert(p != NULL);
328 329 330 331 332 333 334 335 336

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
	cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size);
	cl_assert(git_oid_iszero(&delta->new_file.oid));
	cl_assert_equal_sz(0, delta->new_file.size);

337 338 339 340 341 342 343 344 345 346 347 348 349
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(14, git_diff_patch_num_lines_in_hunk(p, 0));

	for (line = 0; line < git_diff_patch_num_lines_in_hunk(p, 0); ++line) {
		cl_git_pass(git_diff_patch_get_line_in_hunk(
			&origin, NULL, NULL, NULL, NULL, p, 0, line));
		cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin);
	}

	git_diff_patch_free(p);

	opts.flags |= GIT_DIFF_REVERSE;

350
	cl_git_pass(git_diff_patch_from_blobs(&p, d, NULL, e, NULL, &opts));
351 352

	cl_assert(p != NULL);
353 354 355 356 357 358 359 360 361

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
	cl_assert(git_oid_iszero(&delta->old_file.oid));
	cl_assert_equal_sz(0, delta->old_file.size);
	cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid));
	cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size);

362 363 364 365 366 367 368 369 370 371 372 373 374
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(14, git_diff_patch_num_lines_in_hunk(p, 0));

	for (line = 0; line < git_diff_patch_num_lines_in_hunk(p, 0); ++line) {
		cl_git_pass(git_diff_patch_get_line_in_hunk(
			&origin, NULL, NULL, NULL, NULL, p, 0, line));
		cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin);
	}

	git_diff_patch_free(p);

	opts.flags ^= GIT_DIFF_REVERSE;

375
	cl_git_pass(git_diff_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts));
376 377

	cl_assert(p != NULL);
378 379 380 381 382 383

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
	cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);

384 385 386 387
	cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));

	git_diff_patch_free(p);

388
	cl_git_pass(git_diff_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts));
389 390

	cl_assert(p != NULL);
391 392 393 394 395 396

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
	cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);

397 398 399 400 401
	cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));

	git_diff_patch_free(p);
}

402
static void assert_identical_blobs_comparison(diff_expects *expected)
403
{
404 405 406 407
	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);
408 409 410 411
}

void test_diff_blob__can_compare_identical_blobs(void)
{
412 413
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;

414
	cl_git_pass(git_diff_blobs(
415 416
		d, NULL, d, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
417

418
	assert_identical_blobs_comparison(&expected);
419
	cl_assert_equal_i(0, expected.files_binary);
420

nulltoken committed
421
	memset(&expected, 0, sizeof(expected));
422
	cl_git_pass(git_diff_blobs(
423 424
		NULL, NULL, NULL, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
425

426
	assert_identical_blobs_comparison(&expected);
427
	cl_assert_equal_i(0, expected.files_binary);
428

nulltoken committed
429
	memset(&expected, 0, sizeof(expected));
430
	cl_git_pass(git_diff_blobs(
431 432
		alien, NULL, alien, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
433

434
	assert_identical_blobs_comparison(&expected);
435
	cl_assert(expected.files_binary > 0);
436 437
}

438 439 440
void test_diff_blob__can_compare_identical_blobs_with_patch(void)
{
	git_diff_patch *p;
441
	const git_diff_delta *delta;
442

443
	cl_git_pass(git_diff_patch_from_blobs(&p, d, NULL, d, NULL, &opts));
444
	cl_assert(p != NULL);
445 446 447 448 449 450 451 452 453

	delta = git_diff_patch_delta(p);
	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));
	cl_assert(git_oid_equal(git_blob_id(d), &delta->old_file.oid));
	cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d));
	cl_assert(git_oid_equal(git_blob_id(d), &delta->new_file.oid));

454 455 456
	cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
	git_diff_patch_free(p);

457
	cl_git_pass(git_diff_patch_from_blobs(&p, NULL, NULL, NULL, NULL, &opts));
458
	cl_assert(p != NULL);
459 460 461 462 463 464 465 466 467

	delta = git_diff_patch_delta(p);
	cl_assert(delta != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
	cl_assert_equal_sz(0, delta->old_file.size);
	cl_assert(git_oid_iszero(&delta->old_file.oid));
	cl_assert_equal_sz(0, delta->new_file.size);
	cl_assert(git_oid_iszero(&delta->new_file.oid));

468 469 470
	cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
	git_diff_patch_free(p);

471
	cl_git_pass(git_diff_patch_from_blobs(&p, alien, NULL, alien, NULL, &opts));
472 473 474 475 476 477
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status);
	cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
	git_diff_patch_free(p);
}

478
static void assert_binary_blobs_comparison(diff_expects *expected)
479
{
480
	cl_assert(expected->files_binary > 0);
481

482 483 484 485
	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);
486 487 488 489 490 491 492 493 494 495 496 497
}

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));
	cl_git_pass(git_blob_lookup_prefix(&heart, g_repo, &h_oid, 4));

	cl_git_pass(git_diff_blobs(
498 499
		alien, NULL, heart, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
500

501
	assert_binary_blobs_comparison(&expected);
502

nulltoken committed
503
	memset(&expected, 0, sizeof(expected));
504 505

	cl_git_pass(git_diff_blobs(
506 507
		heart, NULL, alien, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
508

509
	assert_binary_blobs_comparison(&expected);
510 511 512 513 514 515 516

	git_blob_free(heart);
}

void test_diff_blob__can_compare_a_binary_blob_and_a_text_blob(void)
{
	cl_git_pass(git_diff_blobs(
517 518
		alien, NULL, d, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
519

520
	assert_binary_blobs_comparison(&expected);
521

nulltoken committed
522
	memset(&expected, 0, sizeof(expected));
523 524

	cl_git_pass(git_diff_blobs(
525 526
		d, NULL, alien, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
527

528
	assert_binary_blobs_comparison(&expected);
529
}
530 531 532 533 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

/*
 * $ 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));
	cl_git_pass(git_blob_lookup_prefix(&old_d, g_repo, &old_d_oid, 4));

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

Russell Belfer committed
570
	cl_assert_equal_i(2, expected.hunks);
571 572 573 574 575

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

Russell Belfer committed
579
	cl_assert_equal_i(2, expected.hunks);
580 581 582 583 584

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

Russell Belfer committed
588
	cl_assert_equal_i(1, expected.hunks);
589 590 591

	git_blob_free(old_d);
}
592 593 594 595 596 597 598

void test_diff_blob__checks_options_version_too_low(void)
{
	const git_error *err;

	opts.version = 0;
	cl_git_fail(git_diff_blobs(
599 600
		d, NULL, alien, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
601 602 603 604 605 606 607 608 609 610
	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(
611 612
		d, NULL, alien, NULL, &opts,
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
613 614 615
	err = giterr_last();
	cl_assert_equal_i(GITERR_INVALID, err->klass);
}
616 617 618 619 620 621 622 623 624 625 626 627

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));
}
628 629 630 631 632

/*
 * git_diff_blob_to_buffer tests
 */

633 634 635 636 637 638 639 640 641 642 643 644 645 646
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);
}

647 648 649 650 651 652 653 654 655 656 657 658
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));
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));

	/* diff from blob a to content of b */
659
	quick_diff_blob_to_str(a, NULL, b_content, 0, NULL);
660 661 662 663 664 665 666 667 668 669
	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(1, expected.hunks);
	cl_assert_equal_i(6, expected.lines);
	cl_assert_equal_i(1, expected.line_ctxt);
	cl_assert_equal_i(5, expected.line_adds);
	cl_assert_equal_i(0, expected.line_dels);

	/* diff from blob a to content of a */
670 671
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
	quick_diff_blob_to_str(a, NULL, a_content, 0, NULL);
672 673
	assert_identical_blobs_comparison(&expected);

674
	/* diff from NULL blob to content of a */
675
	memset(&expected, 0, sizeof(expected));
676
	quick_diff_blob_to_str(NULL, NULL, a_content, 0, NULL);
677
	assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
678 679 680

	/* diff from blob a to NULL buffer */
	memset(&expected, 0, sizeof(expected));
681
	quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
682
	assert_changed_single_one_line_file(&expected, GIT_DELTA_DELETED);
683 684 685 686 687

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

	memset(&expected, 0, sizeof(expected));
688
	quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
689
	assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
690 691 692

	git_blob_free(a);
}
693

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
void test_diff_blob__can_compare_blob_to_buffer_with_patch(void)
{
	git_diff_patch *p;
	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));
	cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));

	/* diff from blob a to content of b */
	cl_git_pass(git_diff_patch_from_blob_and_buffer(
709
		&p, a, NULL, b_content, strlen(b_content), NULL, &opts));
710 711 712 713 714 715 716 717 718 719 720 721 722 723

	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_MODIFIED, git_diff_patch_delta(p)->status);
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(6, git_diff_patch_num_lines_in_hunk(p, 0));

	cl_git_pass(git_diff_patch_line_stats(&tc, &ta, &td, p));
	cl_assert_equal_i(1, (int)tc);
	cl_assert_equal_i(5, (int)ta);
	cl_assert_equal_i(0, (int)td);

	git_diff_patch_free(p);

	/* diff from blob a to content of a */
724
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
725
	cl_git_pass(git_diff_patch_from_blob_and_buffer(
726
		&p, a, NULL, a_content, strlen(a_content), NULL, &opts));
727 728 729 730 731 732 733
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_diff_patch_delta(p)->status);
	cl_assert_equal_i(0, (int)git_diff_patch_num_hunks(p));
	git_diff_patch_free(p);

	/* diff from NULL blob to content of a */
	cl_git_pass(git_diff_patch_from_blob_and_buffer(
734
		&p, NULL, NULL, a_content, strlen(a_content), NULL, &opts));
735 736 737 738 739 740 741 742
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status);
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0));
	git_diff_patch_free(p);

	/* diff from blob a to NULL buffer */
	cl_git_pass(git_diff_patch_from_blob_and_buffer(
743
		&p, a, NULL, NULL, 0, NULL, &opts));
744 745 746 747 748 749 750 751 752 753
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_DELETED, git_diff_patch_delta(p)->status);
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0));
	git_diff_patch_free(p);

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

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
754
		&p, a, NULL, NULL, 0, NULL, &opts));
755 756 757 758 759 760 761 762
	cl_assert(p != NULL);
	cl_assert_equal_i(GIT_DELTA_ADDED, git_diff_patch_delta(p)->status);
	cl_assert_equal_i(1, (int)git_diff_patch_num_hunks(p));
	cl_assert_equal_i(1, git_diff_patch_num_lines_in_hunk(p, 0));
	git_diff_patch_free(p);

	git_blob_free(a);
}
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780

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;

781 782
	opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;

783 784 785 786 787 788 789 790
	cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8));
	cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 4));

	cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
	cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 4));

	/* non-binary to reference content */

791
	quick_diff_blob_to_str(nonbin, NULL, nonbin_content, nonbin_len, NULL);
792 793 794 795 796
	assert_identical_blobs_comparison(&expected);
	cl_assert_equal_i(0, expected.files_binary);

	/* binary to reference content */

797
	quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
798 799 800 801 802 803
	assert_identical_blobs_comparison(&expected);

	cl_assert_equal_i(1, expected.files_binary);

	/* non-binary to binary content */

804
	quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
805 806 807 808
	assert_binary_blobs_comparison(&expected);

	/* binary to non-binary content */

809
	quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
810 811 812 813 814 815
	assert_binary_blobs_comparison(&expected);

	/* non-binary to binary blob */

	memset(&expected, 0, sizeof(expected));
	cl_git_pass(git_diff_blobs(
816
		bin, NULL, nonbin, NULL, &opts,
817 818 819 820 821 822 823 824 825
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
	assert_binary_blobs_comparison(&expected);

	/*
	 * repeat with FORCE_TEXT
	 */

	opts.flags |= GIT_DIFF_FORCE_TEXT;

826
	quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
827 828
	assert_identical_blobs_comparison(&expected);

829
	quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
830 831
	assert_one_modified_with_lines(&expected, 4);

832
	quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
833 834 835 836
	assert_one_modified_with_lines(&expected, 4);

	memset(&expected, 0, sizeof(expected));
	cl_git_pass(git_diff_blobs(
837
		bin, NULL, nonbin, NULL, &opts,
838 839 840 841 842 843 844
		diff_file_cb, diff_hunk_cb, diff_line_cb, &expected));
	assert_one_modified_with_lines(&expected, 4);

	/* cleanup */
	git_blob_free(bin);
	git_blob_free(nonbin);
}
845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 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 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068

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;
	git_diff_patch *p;
	char *pout;

	/* 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(
		cfg, "diff.iam_alphactx.xfuncname", "^[A-Za-z]"));
	cl_git_pass(git_config_set_bool(cfg, "diff.iam_textalpha.binary", 0));
	cl_git_pass(git_config_set_string(
		cfg, "diff.iam_textalpha.xfuncname", "^[A-Za-z]"));
	cl_git_pass(git_config_set_string(
		cfg, "diff.iam_numctx.funcname", "^[0-9]"));
	cl_git_pass(git_config_set_bool(cfg, "diff.iam_textnum.binary", 0));
	cl_git_pass(git_config_set_string(
		cfg, "diff.iam_textnum.funcname", "^[0-9]"));
	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));
	cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 4));
	/* 20b: "Hello from the root\n" */

	cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
	cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 4));
	/* 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);
	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(1, expected.hunks);
	cl_assert_equal_i(3, expected.lines);
	cl_assert_equal_i(0, expected.line_ctxt);
	cl_assert_equal_i(3, expected.line_adds);
	cl_assert_equal_i(0, expected.line_dels);

	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);
	cl_assert_equal_i(0, expected.line_ctxt);
	cl_assert_equal_i(0, expected.line_adds);
	cl_assert_equal_i(0, expected.line_dels);

	quick_diff_blob_to_str(nonbin, "foo/bar.textary", 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(0, expected.files_binary);
	cl_assert_equal_i(1, expected.hunks);
	cl_assert_equal_i(3, expected.lines);
	cl_assert_equal_i(0, expected.line_ctxt);
	cl_assert_equal_i(3, expected.line_adds);
	cl_assert_equal_i(0, expected.line_dels);

	quick_diff_blob_to_str(nonbin, "foo/bar.alphary", 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(0, expected.files_binary);
	cl_assert_equal_i(1, expected.hunks);
	cl_assert_equal_i(3, expected.lines);
	cl_assert_equal_i(0, expected.line_ctxt);
	cl_assert_equal_i(3, expected.line_adds);
	cl_assert_equal_i(0, expected.line_dels);

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, nonbin, "zzz.normal", changed, strlen(changed), NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	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"
		"+Go here\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, nonbin, "zzz.binary", changed, strlen(changed), NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	cl_assert_equal_s(
		"diff --git a/zzz.binary b/zzz.binary\n"
		"index 45141a7..75b0dbb 100644\n"
		"Binary files a/zzz.binary and b/zzz.binary differ\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, nonbin, "zzz.alphary", changed, strlen(changed), NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	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"
		"+Go here\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, nonbin, "zzz.numary", changed, strlen(changed), NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	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"
		"+Go here\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	/* "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";

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, bin, "zzz.normal", changed, 37, NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	cl_assert_equal_s(
		"diff --git a/zzz.normal b/zzz.normal\n"
		"index b435cd5..1604519 100644\n"
		"Binary files a/zzz.normal and b/zzz.normal differ\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, bin, "zzz.textary", changed, 37, NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	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"
		"+replace a line\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, bin, "zzz.textalphary", changed, 37, NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	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"
		"+replace a line\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	cl_git_pass(git_diff_patch_from_blob_and_buffer(
		&p, bin, "zzz.textnumary", changed, 37, NULL, &opts));
	cl_git_pass(git_diff_patch_to_str(&pout, p));
	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"
		"+replace a line\n", pout);
	git__free(pout);
	git_diff_patch_free(p);

	git_blob_free(nonbin);
	git_blob_free(bin);
}