1 #include "clar_libgit2.h"
2 #include "git2/sys/repository.h"
4 #include "diff_helpers.h"
6 #include "repository.h"
9 static git_repository
*g_repo
= NULL
;
11 void test_diff_patch__initialize(void)
15 void test_diff_patch__cleanup(void)
17 cl_git_sandbox_cleanup();
20 #define EXPECTED_HEADER "diff --git a/subdir.txt b/subdir.txt\n" \
21 "deleted file mode 100644\n" \
22 "index e8ee89e..0000000\n" \
23 "--- a/subdir.txt\n" \
26 #define EXPECTED_HUNK "@@ -1,2 +0,0 @@\n"
28 #define UTF8_HUNK_HEADER "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\n"
30 #define UTF8_TRUNCATED_A_HUNK_HEADER "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\n"
32 #define UTF8_TRUNCATED_L_HUNK_HEADER "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E\xE6\x97\xA5\n"
34 static int check_removal_cb(
35 const git_diff_delta
*delta
,
36 const git_diff_hunk
*hunk
,
37 const git_diff_line
*line
,
40 switch (line
->origin
) {
41 case GIT_DIFF_LINE_FILE_HDR
:
42 cl_assert_equal_s(EXPECTED_HEADER
, line
->content
);
43 cl_assert(hunk
== NULL
);
46 case GIT_DIFF_LINE_HUNK_HDR
:
47 cl_assert_equal_s(EXPECTED_HUNK
, line
->content
);
50 case GIT_DIFF_LINE_CONTEXT
:
51 case GIT_DIFF_LINE_DELETION
:
53 return *(int *)payload
;
57 /* unexpected code path */
62 cl_assert(hunk
!= NULL
);
63 cl_assert_equal_i(1, hunk
->old_start
);
64 cl_assert_equal_i(2, hunk
->old_lines
);
65 cl_assert_equal_i(0, hunk
->new_start
);
66 cl_assert_equal_i(0, hunk
->new_lines
);
69 cl_assert_equal_s("subdir.txt", delta
->old_file
.path
);
70 cl_assert_equal_s("subdir.txt", delta
->new_file
.path
);
71 cl_assert_equal_i(GIT_DELTA_DELETED
, delta
->status
);
76 void test_diff_patch__can_properly_display_the_removal_of_a_file(void)
79 * $ git diff 26a125e..735b6a2
80 * diff --git a/subdir.txt b/subdir.txt
81 * deleted file mode 100644
82 * index e8ee89e..0000000
90 const char *one_sha
= "26a125e";
91 const char *another_sha
= "735b6a2";
92 git_tree
*one
, *another
;
95 g_repo
= cl_git_sandbox_init("status");
97 one
= resolve_commit_oid_to_tree(g_repo
, one_sha
);
98 another
= resolve_commit_oid_to_tree(g_repo
, another_sha
);
100 cl_git_pass(git_diff_tree_to_tree(&diff
, g_repo
, one
, another
, NULL
));
102 cl_git_pass(git_diff_print(
103 diff
, GIT_DIFF_FORMAT_PATCH
, check_removal_cb
, NULL
));
107 git_tree_free(another
);
111 void test_diff_patch__can_cancel_diff_print(void)
113 const char *one_sha
= "26a125e";
114 const char *another_sha
= "735b6a2";
115 git_tree
*one
, *another
;
119 g_repo
= cl_git_sandbox_init("status");
121 one
= resolve_commit_oid_to_tree(g_repo
, one_sha
);
122 another
= resolve_commit_oid_to_tree(g_repo
, another_sha
);
124 cl_git_pass(git_diff_tree_to_tree(&diff
, g_repo
, one
, another
, NULL
));
128 cl_git_fail_with(git_diff_print(
129 diff
, GIT_DIFF_FORMAT_PATCH
, check_removal_cb
, &fail_with
),
134 cl_git_fail_with(git_diff_print(
135 diff
, GIT_DIFF_FORMAT_PATCH
, check_removal_cb
, &fail_with
),
140 git_tree_free(another
);
144 void test_diff_patch__to_string(void)
146 const char *one_sha
= "26a125e";
147 const char *another_sha
= "735b6a2";
148 git_tree
*one
, *another
;
151 git_buf buf
= GIT_BUF_INIT
;
152 const char *expected
= "diff --git a/subdir.txt b/subdir.txt\ndeleted file mode 100644\nindex e8ee89e..0000000\n--- a/subdir.txt\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-Is it a bird?\n-Is it a plane?\n";
154 g_repo
= cl_git_sandbox_init("status");
156 one
= resolve_commit_oid_to_tree(g_repo
, one_sha
);
157 another
= resolve_commit_oid_to_tree(g_repo
, another_sha
);
159 cl_git_pass(git_diff_tree_to_tree(&diff
, g_repo
, one
, another
, NULL
));
161 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
163 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
165 cl_git_pass(git_patch_to_buf(&buf
, patch
));
167 cl_assert_equal_s(expected
, buf
.ptr
);
169 cl_assert_equal_sz(31, git_patch_size(patch
, 0, 0, 0));
170 cl_assert_equal_sz(31, git_patch_size(patch
, 1, 0, 0));
171 cl_assert_equal_sz(31 + 16, git_patch_size(patch
, 1, 1, 0));
172 cl_assert_equal_sz(strlen(expected
), git_patch_size(patch
, 1, 1, 1));
174 git_buf_dispose(&buf
);
175 git_patch_free(patch
);
177 git_tree_free(another
);
181 void test_diff_patch__config_options(void)
183 const char *one_sha
= "26a125e"; /* current HEAD */
188 git_buf buf
= GIT_BUF_INIT
;
189 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
190 char *onefile
= "staged_changes_modified_file";
191 const char *expected1
= "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
192 const char *expected2
= "diff --git i/staged_changes_modified_file w/staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- i/staged_changes_modified_file\n+++ w/staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
193 const char *expected3
= "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
194 const char *expected4
= "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 70bd9443ada0..906ee7711f4f 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
196 g_repo
= cl_git_sandbox_init("status");
197 cl_git_pass(git_repository_config(&cfg
, g_repo
));
198 one
= resolve_commit_oid_to_tree(g_repo
, one_sha
);
199 opts
.pathspec
.count
= 1;
200 opts
.pathspec
.strings
= &onefile
;
203 cl_git_pass(git_config_set_string(cfg
, "diff.mnemonicprefix", "true"));
205 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, one
, NULL
, &opts
));
207 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
208 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
209 cl_git_pass(git_patch_to_buf(&buf
, patch
));
210 cl_assert_equal_s(expected1
, buf
.ptr
);
213 git_patch_free(patch
);
216 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
218 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
219 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
220 cl_git_pass(git_patch_to_buf(&buf
, patch
));
221 cl_assert_equal_s(expected2
, buf
.ptr
);
224 git_patch_free(patch
);
228 cl_git_pass(git_config_set_string(cfg
, "diff.noprefix", "true"));
230 cl_git_pass(git_diff_index_to_workdir(&diff
, g_repo
, NULL
, &opts
));
232 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
233 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
234 cl_git_pass(git_patch_to_buf(&buf
, patch
));
235 cl_assert_equal_s(expected3
, buf
.ptr
);
238 git_patch_free(patch
);
242 cl_git_pass(git_config_set_int32(cfg
, "core.abbrev", 12));
244 cl_git_pass(git_diff_tree_to_index(&diff
, g_repo
, one
, NULL
, &opts
));
246 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
247 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
248 cl_git_pass(git_patch_to_buf(&buf
, patch
));
249 cl_assert_equal_s(expected4
, buf
.ptr
);
252 git_patch_free(patch
);
255 git_buf_dispose(&buf
);
257 git_config_free(cfg
);
260 void test_diff_patch__hunks_have_correct_line_numbers(void)
264 git_diff_options opt
= GIT_DIFF_OPTIONS_INIT
;
267 const git_diff_delta
*delta
;
268 const git_diff_hunk
*hunk
;
269 const git_diff_line
*line
;
271 git_buf old_content
= GIT_BUF_INIT
, actual
= GIT_BUF_INIT
;
272 const char *new_content
= "The Song of Seven Cities\n------------------------\n\nI WAS Lord of Cities very sumptuously builded.\nSeven roaring Cities paid me tribute from afar.\nIvory their outposts were--the guardrooms of them gilded,\nAnd garrisoned with Amazons invincible in war.\n\nThis is some new text;\nNot as good as the old text;\nBut here it is.\n\nSo they warred and trafficked only yesterday, my Cities.\nTo-day there is no mark or mound of where my Cities stood.\nFor the River rose at midnight and it washed away my Cities.\nThey are evened with Atlantis and the towns before the Flood.\n\nRain on rain-gorged channels raised the water-levels round them,\nFreshet backed on freshet swelled and swept their world from sight,\nTill the emboldened floods linked arms and, flashing forward, drowned them--\nDrowned my Seven Cities and their peoples in one night!\n\nLow among the alders lie their derelict foundations,\nThe beams wherein they trusted and the plinths whereon they built--\nMy rulers and their treasure and their unborn populations,\nDead, destroyed, aborted, and defiled with mud and silt!\n\nAnother replacement;\nBreaking up the poem;\nGenerating some hunks.\n\nTo the sound of trumpets shall their seed restore my Cities\nWealthy and well-weaponed, that once more may I behold\nAll the world go softly when it walks before my Cities,\nAnd the horses and the chariots fleeing from them as of old!\n\n -- Rudyard Kipling\n";
274 g_repo
= cl_git_sandbox_init("renames");
276 cl_git_pass(git_config_new(&cfg
));
277 git_repository_set_config(g_repo
, cfg
);
278 git_config_free(cfg
);
280 git_repository_reinit_filesystem(g_repo
, false);
283 git_futils_readbuffer(&old_content
, "renames/songof7cities.txt"));
285 cl_git_rewritefile("renames/songof7cities.txt", new_content
);
287 cl_git_pass(git_repository_head_tree(&head
, g_repo
));
289 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, head
, &opt
));
291 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
293 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
294 cl_assert((delta
= git_patch_get_delta(patch
)) != NULL
);
296 cl_assert_equal_i(GIT_DELTA_MODIFIED
, (int)delta
->status
);
297 cl_assert_equal_i(2, (int)git_patch_num_hunks(patch
));
302 git_patch_get_hunk(&hunk
, &hunklen
, patch
, 0));
304 cl_assert_equal_i(18, (int)hunklen
);
306 cl_assert_equal_i(6, (int)hunk
->old_start
);
307 cl_assert_equal_i(15, (int)hunk
->old_lines
);
308 cl_assert_equal_i(6, (int)hunk
->new_start
);
309 cl_assert_equal_i(9, (int)hunk
->new_lines
);
311 cl_assert_equal_i(18, (int)git_patch_num_lines_in_hunk(patch
, 0));
313 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 0));
314 cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT
, (int)line
->origin
);
315 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
316 cl_assert_equal_s("Ivory their outposts were--the guardrooms of them gilded,\n", actual
.ptr
);
317 cl_assert_equal_i(6, line
->old_lineno
);
318 cl_assert_equal_i(6, line
->new_lineno
);
319 cl_assert_equal_i(-1, line
->content_offset
);
321 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 3));
322 cl_assert_equal_i(GIT_DIFF_LINE_DELETION
, (int)line
->origin
);
323 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
324 cl_assert_equal_s("All the world went softly when it walked before my Cities--\n", actual
.ptr
);
325 cl_assert_equal_i(9, line
->old_lineno
);
326 cl_assert_equal_i(-1, line
->new_lineno
);
327 cl_assert_equal_i(252, line
->content_offset
);
329 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 12));
330 cl_assert_equal_i(GIT_DIFF_LINE_ADDITION
, (int)line
->origin
);
331 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
332 cl_assert_equal_s("This is some new text;\n", actual
.ptr
);
333 cl_assert_equal_i(-1, line
->old_lineno
);
334 cl_assert_equal_i(9, line
->new_lineno
);
335 cl_assert_equal_i(252, line
->content_offset
);
339 cl_git_pass(git_patch_get_hunk(&hunk
, &hunklen
, patch
, 1));
341 cl_assert_equal_i(18, (int)hunklen
);
343 cl_assert_equal_i(31, (int)hunk
->old_start
);
344 cl_assert_equal_i(15, (int)hunk
->old_lines
);
345 cl_assert_equal_i(25, (int)hunk
->new_start
);
346 cl_assert_equal_i(9, (int)hunk
->new_lines
);
348 cl_assert_equal_i(18, (int)git_patch_num_lines_in_hunk(patch
, 1));
350 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 1, 0));
351 cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT
, (int)line
->origin
);
352 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
353 cl_assert_equal_s("My rulers and their treasure and their unborn populations,\n", actual
.ptr
);
354 cl_assert_equal_i(31, line
->old_lineno
);
355 cl_assert_equal_i(25, line
->new_lineno
);
356 cl_assert_equal_i(-1, line
->content_offset
);
358 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 1, 3));
359 cl_assert_equal_i(GIT_DIFF_LINE_DELETION
, (int)line
->origin
);
360 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
361 cl_assert_equal_s("The Daughters of the Palace whom they cherished in my Cities,\n", actual
.ptr
);
362 cl_assert_equal_i(34, line
->old_lineno
);
363 cl_assert_equal_i(-1, line
->new_lineno
);
364 cl_assert_equal_i(1468, line
->content_offset
);
366 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 1, 12));
367 cl_assert_equal_i(GIT_DIFF_LINE_ADDITION
, (int)line
->origin
);
368 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
369 cl_assert_equal_s("Another replacement;\n", actual
.ptr
);
370 cl_assert_equal_i(-1, line
->old_lineno
);
371 cl_assert_equal_i(28, line
->new_lineno
);
372 cl_assert_equal_i(1066, line
->content_offset
);
374 git_patch_free(patch
);
377 /* Let's check line numbers when there is no newline */
379 git_buf_rtrim(&old_content
);
380 cl_git_rewritefile("renames/songof7cities.txt", old_content
.ptr
);
382 cl_git_pass(git_diff_tree_to_workdir(&diff
, g_repo
, head
, &opt
));
384 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
386 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
387 cl_assert((delta
= git_patch_get_delta(patch
)) != NULL
);
389 cl_assert_equal_i(GIT_DELTA_MODIFIED
, (int)delta
->status
);
390 cl_assert_equal_i(1, (int)git_patch_num_hunks(patch
));
394 cl_git_pass(git_patch_get_hunk(&hunk
, &hunklen
, patch
, 0));
396 cl_assert_equal_i(6, (int)hunklen
);
398 cl_assert_equal_i(46, (int)hunk
->old_start
);
399 cl_assert_equal_i(4, (int)hunk
->old_lines
);
400 cl_assert_equal_i(46, (int)hunk
->new_start
);
401 cl_assert_equal_i(4, (int)hunk
->new_lines
);
403 cl_assert_equal_i(6, (int)git_patch_num_lines_in_hunk(patch
, 0));
405 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 1));
406 cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT
, (int)line
->origin
);
407 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
408 cl_assert_equal_s("And the horses and the chariots fleeing from them as of old!\n", actual
.ptr
);
409 cl_assert_equal_i(47, line
->old_lineno
);
410 cl_assert_equal_i(47, line
->new_lineno
);
412 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 2));
413 cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT
, (int)line
->origin
);
414 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
415 cl_assert_equal_s("\n", actual
.ptr
);
416 cl_assert_equal_i(48, line
->old_lineno
);
417 cl_assert_equal_i(48, line
->new_lineno
);
419 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 3));
420 cl_assert_equal_i(GIT_DIFF_LINE_DELETION
, (int)line
->origin
);
421 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
422 cl_assert_equal_s(" -- Rudyard Kipling\n", actual
.ptr
);
423 cl_assert_equal_i(49, line
->old_lineno
);
424 cl_assert_equal_i(-1, line
->new_lineno
);
426 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 4));
427 cl_assert_equal_i(GIT_DIFF_LINE_ADDITION
, (int)line
->origin
);
428 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
429 cl_assert_equal_s(" -- Rudyard Kipling", actual
.ptr
);
430 cl_assert_equal_i(-1, line
->old_lineno
);
431 cl_assert_equal_i(49, line
->new_lineno
);
433 cl_git_pass(git_patch_get_line_in_hunk(&line
, patch
, 0, 5));
434 cl_assert_equal_i(GIT_DIFF_LINE_DEL_EOFNL
, (int)line
->origin
);
435 cl_git_pass(git_buf_set(&actual
, line
->content
, line
->content_len
));
436 cl_assert_equal_s("\n\\ No newline at end of file\n", actual
.ptr
);
437 cl_assert_equal_i(-1, line
->old_lineno
);
438 cl_assert_equal_i(49, line
->new_lineno
);
440 git_patch_free(patch
);
443 git_buf_dispose(&actual
);
444 git_buf_dispose(&old_content
);
448 static void check_single_patch_stats(
449 git_repository
*repo
, size_t hunks
,
450 size_t adds
, size_t dels
, size_t ctxt
, size_t *sizes
,
451 const char *expected
)
455 const git_diff_delta
*delta
;
456 size_t actual_ctxt
, actual_adds
, actual_dels
;
458 cl_git_pass(git_diff_index_to_workdir(&diff
, repo
, NULL
, NULL
));
460 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff
));
462 cl_git_pass(git_patch_from_diff(&patch
, diff
, 0));
463 cl_assert((delta
= git_patch_get_delta(patch
)) != NULL
);
464 cl_assert_equal_i(GIT_DELTA_MODIFIED
, (int)delta
->status
);
466 cl_assert_equal_i((int)hunks
, (int)git_patch_num_hunks(patch
));
468 cl_git_pass( git_patch_line_stats(
469 &actual_ctxt
, &actual_adds
, &actual_dels
, patch
) );
471 cl_assert_equal_sz(ctxt
, actual_ctxt
);
472 cl_assert_equal_sz(adds
, actual_adds
);
473 cl_assert_equal_sz(dels
, actual_dels
);
475 if (expected
!= NULL
) {
476 git_buf buf
= GIT_BUF_INIT
;
477 cl_git_pass(git_patch_to_buf(&buf
, patch
));
478 cl_assert_equal_s(expected
, buf
.ptr
);
479 git_buf_dispose(&buf
);
482 strlen(expected
), git_patch_size(patch
, 1, 1, 1));
487 cl_assert_equal_sz(sizes
[0], git_patch_size(patch
, 0, 0, 0));
489 cl_assert_equal_sz(sizes
[1], git_patch_size(patch
, 1, 0, 0));
491 cl_assert_equal_sz(sizes
[2], git_patch_size(patch
, 1, 1, 0));
494 /* walk lines in hunk with basic sanity checks */
495 for (; hunks
> 0; --hunks
) {
497 const git_diff_line
*line
;
498 int last_new_lineno
= -1, last_old_lineno
= -1;
500 max_i
= git_patch_num_lines_in_hunk(patch
, hunks
- 1);
502 for (i
= 0; i
< max_i
; ++i
) {
506 git_patch_get_line_in_hunk(&line
, patch
, hunks
- 1, i
));
508 if (line
->origin
== GIT_DIFF_LINE_ADD_EOFNL
||
509 line
->origin
== GIT_DIFF_LINE_DEL_EOFNL
||
510 line
->origin
== GIT_DIFF_LINE_CONTEXT_EOFNL
)
513 if (line
->old_lineno
>= 0) {
514 if (last_old_lineno
>= 0)
516 expected
, line
->old_lineno
- last_old_lineno
);
517 last_old_lineno
= line
->old_lineno
;
520 if (line
->new_lineno
>= 0) {
521 if (last_new_lineno
>= 0)
523 expected
, line
->new_lineno
- last_new_lineno
);
524 last_new_lineno
= line
->new_lineno
;
529 git_patch_free(patch
);
533 void test_diff_patch__line_counts_with_eofnl(void)
536 git_buf content
= GIT_BUF_INIT
;
539 const char *expected
=
540 /* below is pasted output of 'git diff' with fn context removed */
541 "diff --git a/songof7cities.txt b/songof7cities.txt\n"
542 "index 378a7d9..3d0154e 100644\n"
543 "--- a/songof7cities.txt\n"
544 "+++ b/songof7cities.txt\n"
545 "@@ -42,7 +42,7 @@ With peoples undefeated of the dark, enduring blood.\n"
547 " To the sound of trumpets shall their seed restore my Cities\n"
548 " Wealthy and well-weaponed, that once more may I behold\n"
549 "-All the world go softly when it walks before my Cities,\n"
550 "+#All the world go softly when it walks before my Cities,\n"
551 " And the horses and the chariots fleeing from them as of old!\n"
553 " -- Rudyard Kipling\n"
554 "\\ No newline at end of file\n";
555 size_t expected_sizes
[3] = { 115, 119 + 115 + 114, 119 + 115 + 114 + 71 };
557 g_repo
= cl_git_sandbox_init("renames");
559 cl_git_pass(git_config_new(&cfg
));
560 git_repository_set_config(g_repo
, cfg
);
561 git_config_free(cfg
);
563 git_repository_reinit_filesystem(g_repo
, false);
565 cl_git_pass(git_futils_readbuffer(&content
, "renames/songof7cities.txt"));
567 /* remove first line */
569 end
= git_buf_cstr(&content
) + git_buf_find(&content
, '\n') + 1;
570 git_buf_consume(&content
, end
);
571 cl_git_rewritefile("renames/songof7cities.txt", content
.ptr
);
573 check_single_patch_stats(g_repo
, 1, 0, 1, 3, NULL
, NULL
);
575 /* remove trailing whitespace */
577 git_buf_rtrim(&content
);
578 cl_git_rewritefile("renames/songof7cities.txt", content
.ptr
);
580 check_single_patch_stats(g_repo
, 2, 1, 2, 6, NULL
, NULL
);
582 /* add trailing whitespace */
584 cl_git_pass(git_repository_index(&index
, g_repo
));
585 cl_git_pass(git_index_add_bypath(index
, "songof7cities.txt"));
586 cl_git_pass(git_index_write(index
));
587 git_index_free(index
);
589 cl_git_pass(git_buf_putc(&content
, '\n'));
590 cl_git_rewritefile("renames/songof7cities.txt", content
.ptr
);
592 check_single_patch_stats(g_repo
, 1, 1, 1, 3, NULL
, NULL
);
594 /* no trailing whitespace as context line */
597 /* walk back a couple lines, make space and insert char */
598 char *scan
= content
.ptr
+ content
.size
;
601 for (i
= 0; i
< 5; ++i
) {
602 for (--scan
; scan
> content
.ptr
&& *scan
!= '\n'; --scan
)
603 /* seek to prev \n */;
605 cl_assert(scan
> content
.ptr
);
607 /* overwrite trailing \n with right-shifted content */
608 memmove(scan
+ 1, scan
, content
.size
- (scan
- content
.ptr
) - 1);
609 /* insert '#' char into space we created */
612 cl_git_rewritefile("renames/songof7cities.txt", content
.ptr
);
614 check_single_patch_stats(
615 g_repo
, 1, 1, 1, 6, expected_sizes
, expected
);
617 git_buf_dispose(&content
);
620 void test_diff_patch__can_strip_bad_utf8(void)
622 const char *a
= "A " UTF8_HUNK_HEADER
633 "L " UTF8_HUNK_HEADER
645 const char *b
= "A " UTF8_HUNK_HEADER
656 "L " UTF8_HUNK_HEADER
668 const char *expected
= "diff --git a/file b/file\n"
669 "index d0647c4..7827ce5 100644\n"
672 "@@ -2,7 +2,7 @@ A " UTF8_TRUNCATED_A_HUNK_HEADER
681 "@@ -13,7 +13,7 @@ L " UTF8_TRUNCATED_L_HUNK_HEADER
691 git_diff_options opts
;
693 git_buf buf
= GIT_BUF_INIT
;
695 cl_git_pass(git_diff_init_options(&opts
, GIT_DIFF_OPTIONS_VERSION
));
697 cl_git_pass(git_patch_from_buffers(&patch
, a
, strlen(a
), NULL
, b
, strlen(b
), NULL
, &opts
));
698 cl_git_pass(git_patch_to_buf(&buf
, patch
));
700 cl_assert_equal_s(expected
, buf
.ptr
);
702 git_patch_free(patch
);
703 git_buf_dispose(&buf
);