]> git.proxmox.com Git - libgit2.git/blame - tests-clar/diff/patch.c
Add diff rename tests with partial similarity
[libgit2.git] / tests-clar / diff / patch.c
CommitLineData
eb3d71a5 1#include "clar_libgit2.h"
2#include "diff_helpers.h"
805c476c
RB
3#include "repository.h"
4#include "buf_text.h"
eb3d71a5 5
6static git_repository *g_repo = NULL;
7
8void test_diff_patch__initialize(void)
9{
eb3d71a5 10}
11
12void test_diff_patch__cleanup(void)
13{
14 cl_git_sandbox_cleanup();
15}
16
1d2dd864 17#define EXPECTED_HEADER "diff --git a/subdir.txt b/subdir.txt\n" \
eb3d71a5 18 "deleted file mode 100644\n" \
19 "index e8ee89e..0000000\n" \
20 "--- a/subdir.txt\n" \
21 "+++ /dev/null\n"
22
1d2dd864 23#define EXPECTED_HUNK "@@ -1,2 +0,0 @@\n"
24
eb3d71a5 25static int check_removal_cb(
bae957b9
RB
26 const git_diff_delta *delta,
27 const git_diff_range *range,
eb3d71a5 28 char line_origin,
1d2dd864 29 const char *formatted_output,
793c4385
RB
30 size_t output_len,
31 void *payload)
eb3d71a5 32{
793c4385 33 GIT_UNUSED(payload);
52877c89 34 GIT_UNUSED(output_len);
eb3d71a5 35
1d2dd864 36 switch (line_origin) {
37 case GIT_DIFF_LINE_FILE_HDR:
38 cl_assert_equal_s(EXPECTED_HEADER, formatted_output);
39 cl_assert(range == NULL);
40 goto check_delta;
41
42 case GIT_DIFF_LINE_HUNK_HDR:
43 cl_assert_equal_s(EXPECTED_HUNK, formatted_output);
44 /* Fall through */
45
46 case GIT_DIFF_LINE_CONTEXT:
47 case GIT_DIFF_LINE_DELETION:
48 goto check_range;
49
50 default:
51 /* unexpected code path */
52 return -1;
53 }
54
55check_range:
56 cl_assert(range != NULL);
57 cl_assert_equal_i(1, range->old_start);
58 cl_assert_equal_i(2, range->old_lines);
59 cl_assert_equal_i(0, range->new_start);
60 cl_assert_equal_i(0, range->new_lines);
eb3d71a5 61
1d2dd864 62check_delta:
16b83019
RB
63 cl_assert_equal_s("subdir.txt", delta->old_file.path);
64 cl_assert_equal_s("subdir.txt", delta->new_file.path);
1d2dd864 65 cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
eb3d71a5 66
1d2dd864 67 return 0;
eb3d71a5 68}
69
70void test_diff_patch__can_properly_display_the_removal_of_a_file(void)
71{
72 /*
73 * $ git diff 26a125e..735b6a2
74 * diff --git a/subdir.txt b/subdir.txt
75 * deleted file mode 100644
76 * index e8ee89e..0000000
77 * --- a/subdir.txt
78 * +++ /dev/null
79 * @@ -1,2 +0,0 @@
80 * -Is it a bird?
81 * -Is it a plane?
82 */
83
84 const char *one_sha = "26a125e";
85 const char *another_sha = "735b6a2";
86 git_tree *one, *another;
87 git_diff_list *diff;
88
805c476c
RB
89 g_repo = cl_git_sandbox_init("status");
90
eb3d71a5 91 one = resolve_commit_oid_to_tree(g_repo, one_sha);
92 another = resolve_commit_oid_to_tree(g_repo, another_sha);
93
5735bf5e 94 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL));
eb3d71a5 95
793c4385 96 cl_git_pass(git_diff_print_patch(diff, check_removal_cb, NULL));
eb3d71a5 97
98 git_diff_list_free(diff);
99
100 git_tree_free(another);
101 git_tree_free(one);
102}
93cf7bb8
RB
103
104void test_diff_patch__to_string(void)
105{
106 const char *one_sha = "26a125e";
107 const char *another_sha = "735b6a2";
108 git_tree *one, *another;
109 git_diff_list *diff;
110 git_diff_patch *patch;
111 char *text;
112 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";
113
805c476c
RB
114 g_repo = cl_git_sandbox_init("status");
115
93cf7bb8
RB
116 one = resolve_commit_oid_to_tree(g_repo, one_sha);
117 another = resolve_commit_oid_to_tree(g_repo, another_sha);
118
5735bf5e 119 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL));
93cf7bb8 120
a8122b5d 121 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
93cf7bb8
RB
122
123 cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
124
125 cl_git_pass(git_diff_patch_to_str(&text, patch));
126
127 cl_assert_equal_s(expected, text);
128
129 git__free(text);
130 git_diff_patch_free(patch);
131 git_diff_list_free(diff);
132 git_tree_free(another);
133 git_tree_free(one);
134}
805c476c
RB
135
136void test_diff_patch__hunks_have_correct_line_numbers(void)
137{
138 git_tree *head;
139 git_diff_list *diff;
140 git_diff_patch *patch;
141 const git_diff_delta *delta;
142 const git_diff_range *range;
143 const char *hdr, *text;
144 size_t hdrlen, hunklen, textlen;
145 char origin;
146 int oldno, newno;
147 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";
148
149 g_repo = cl_git_sandbox_init("renames");
150
151 cl_git_rewritefile("renames/songofseven.txt", new_content);
152
153 cl_git_pass(git_repository_head_tree(&head, g_repo));
154
155 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, head, NULL));
156
157 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
158
159 cl_git_pass(git_diff_get_patch(&patch, &delta, diff, 0));
160
161 cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status);
162 cl_assert_equal_i(2, (int)git_diff_patch_num_hunks(patch));
163
164 /* check hunk 0 */
165
166 cl_git_pass(
167 git_diff_patch_get_hunk(&range, &hdr, &hdrlen, &hunklen, patch, 0));
168
169 cl_assert_equal_i(18, (int)hunklen);
170
171 cl_assert_equal_i(6, (int)range->old_start);
172 cl_assert_equal_i(15, (int)range->old_lines);
173 cl_assert_equal_i(6, (int)range->new_start);
174 cl_assert_equal_i(9, (int)range->new_lines);
175
176 cl_assert_equal_i(18, (int)git_diff_patch_num_lines_in_hunk(patch, 0));
177
178 cl_git_pass(git_diff_patch_get_line_in_hunk(
179 &origin, &text, &textlen, &oldno, &newno, patch, 0, 0));
180 cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)origin);
181 cl_assert(strncmp("Ivory their outposts were—the guardrooms of them gilded,\n", text, textlen) == 0);
182 cl_assert_equal_i(6, oldno);
183 cl_assert_equal_i(6, newno);
184
185 cl_git_pass(git_diff_patch_get_line_in_hunk(
186 &origin, &text, &textlen, &oldno, &newno, patch, 0, 3));
187 cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin);
188 cl_assert(strncmp("All the world went softly when it walked before my Cities—\n", text, textlen) == 0);
189 cl_assert_equal_i(9, oldno);
190 cl_assert_equal_i(-1, newno);
191
192 cl_git_pass(git_diff_patch_get_line_in_hunk(
193 &origin, &text, &textlen, &oldno, &newno, patch, 0, 12));
194 cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin);
195 cl_assert(strncmp("This is some new text;\n", text, textlen) == 0);
196 cl_assert_equal_i(-1, oldno);
197 cl_assert_equal_i(9, newno);
198
199 /* check hunk 1 */
200
201 cl_git_pass(
202 git_diff_patch_get_hunk(&range, &hdr, &hdrlen, &hunklen, patch, 1));
203
204 cl_assert_equal_i(18, (int)hunklen);
205
206 cl_assert_equal_i(31, (int)range->old_start);
207 cl_assert_equal_i(15, (int)range->old_lines);
208 cl_assert_equal_i(25, (int)range->new_start);
209 cl_assert_equal_i(9, (int)range->new_lines);
210
211 cl_assert_equal_i(18, (int)git_diff_patch_num_lines_in_hunk(patch, 1));
212
213 cl_git_pass(git_diff_patch_get_line_in_hunk(
214 &origin, &text, &textlen, &oldno, &newno, patch, 1, 0));
215 cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)origin);
216 cl_assert(strncmp("My rulers and their treasure and their unborn populations,\n", text, textlen) == 0);
217 cl_assert_equal_i(31, oldno);
218 cl_assert_equal_i(25, newno);
219
220 cl_git_pass(git_diff_patch_get_line_in_hunk(
221 &origin, &text, &textlen, &oldno, &newno, patch, 1, 3));
222 cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)origin);
223 cl_assert(strncmp("The Daughters of the Palace whom they cherished in my Cities,\n", text, textlen) == 0);
224 cl_assert_equal_i(34, oldno);
225 cl_assert_equal_i(-1, newno);
226
227 cl_git_pass(git_diff_patch_get_line_in_hunk(
228 &origin, &text, &textlen, &oldno, &newno, patch, 1, 12));
229 cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)origin);
230 cl_assert(strncmp("Another replacement;\n", text, textlen) == 0);
231 cl_assert_equal_i(-1, oldno);
232 cl_assert_equal_i(28, newno);
233
234 git_diff_patch_free(patch);
235 git_diff_list_free(diff);
236 git_tree_free(head);
237}
f1e2735c
RB
238
239static void check_single_patch_stats(
240 git_repository *repo, size_t hunks, size_t adds, size_t dels)
241{
242 git_diff_list *diff;
243 git_diff_patch *patch;
244 const git_diff_delta *delta;
245 size_t actual_adds, actual_dels;
246
247 cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL));
248
249 cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
250
251 cl_git_pass(git_diff_get_patch(&patch, &delta, diff, 0));
252 cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status);
253
3ad05221 254 cl_assert_equal_sz(hunks, git_diff_patch_num_hunks(patch));
f1e2735c
RB
255
256 cl_git_pass(
257 git_diff_patch_line_stats(NULL, &actual_adds, &actual_dels, patch));
258
3ad05221 259 cl_assert_equal_sz(adds, actual_adds);
260 cl_assert_equal_sz(dels, actual_dels);
f1e2735c
RB
261
262 git_diff_patch_free(patch);
263 git_diff_list_free(diff);
264}
265
266void test_diff_patch__line_counts_with_eofnl(void)
267{
268 git_buf content = GIT_BUF_INIT;
269 const char *end;
270 git_index *index;
271
272 g_repo = cl_git_sandbox_init("renames");
273
274 cl_git_pass(git_futils_readbuffer(&content, "renames/songofseven.txt"));
275
276 /* remove first line */
277
278 end = git_buf_cstr(&content) + git_buf_find(&content, '\n') + 1;
279 git_buf_consume(&content, end);
280 cl_git_rewritefile("renames/songofseven.txt", content.ptr);
281
282 check_single_patch_stats(g_repo, 1, 0, 1);
283
284 /* remove trailing whitespace */
285
286 git_buf_rtrim(&content);
287 cl_git_rewritefile("renames/songofseven.txt", content.ptr);
288
289 check_single_patch_stats(g_repo, 2, 1, 2);
290
291 /* add trailing whitespace */
292
293 cl_git_pass(git_repository_index(&index, g_repo));
294 cl_git_pass(git_index_add_bypath(index, "songofseven.txt"));
295 cl_git_pass(git_index_write(index));
296 git_index_free(index);
297
298 cl_git_pass(git_buf_putc(&content, '\n'));
299 cl_git_rewritefile("renames/songofseven.txt", content.ptr);
300
301 check_single_patch_stats(g_repo, 1, 1, 1);
3bf68be4
RB
302
303 git_buf_free(&content);
f1e2735c 304}