]> git.proxmox.com Git - libgit2.git/blame - tests/checkout/crlf.c
git_buf_text_lf_to_crlf: allow mixed line endings
[libgit2.git] / tests / checkout / crlf.c
CommitLineData
6e959708
ET
1#include "clar_libgit2.h"
2#include "checkout_helpers.h"
0cf77103 3#include "../filter/crlf.h"
3d92b9ab 4#include "fileops.h"
6e959708
ET
5
6#include "git2/checkout.h"
7#include "repository.h"
c4e6ab5f 8#include "index.h"
37f9e409 9#include "posix.h"
6e959708 10
6e959708
ET
11static git_repository *g_repo;
12
3d92b9ab
ET
13static const char *systype;
14static git_buf expected_fixture = GIT_BUF_INIT;
15
6e959708
ET
16void test_checkout_crlf__initialize(void)
17{
6e959708 18 g_repo = cl_git_sandbox_init("crlf");
3d92b9ab
ET
19
20 if (GIT_EOL_NATIVE == GIT_EOL_CRLF)
21 systype = "windows";
22 else
23 systype = "posix";
6e959708
ET
24}
25
26void test_checkout_crlf__cleanup(void)
27{
28 cl_git_sandbox_cleanup();
3d92b9ab
ET
29
30 if (expected_fixture.size) {
31 cl_fixture_cleanup(expected_fixture.ptr);
32 git_buf_free(&expected_fixture);
33 }
34}
35
36struct compare_data
37{
38 const char *dirname;
39 const char *autocrlf;
40 const char *attrs;
41};
42
43static int compare_file(void *payload, git_buf *actual_path)
44{
45 git_buf expected_path = GIT_BUF_INIT;
46 git_buf actual_contents = GIT_BUF_INIT;
47 git_buf expected_contents = GIT_BUF_INIT;
48 struct compare_data *cd = payload;
49 bool failed = true;
50
51 if (strcmp(git_path_basename(actual_path->ptr), ".git") == 0 ||
52 strcmp(git_path_basename(actual_path->ptr), ".gitattributes") == 0) {
53 failed = false;
54 goto done;
55 }
56
57 cl_git_pass(git_buf_joinpath(&expected_path, cd->dirname,
58 git_path_basename(actual_path->ptr)));
59
60 if (!git_path_isfile(expected_path.ptr) ||
61 !git_path_isfile(actual_path->ptr))
62 goto done;
63
64 if (git_futils_readbuffer(&actual_contents, actual_path->ptr) < 0 ||
65 git_futils_readbuffer(&expected_contents, expected_path.ptr) < 0)
66 goto done;
67
68 if (actual_contents.size != expected_contents.size)
69 goto done;
70
71 if (memcmp(actual_contents.ptr, expected_contents.ptr, expected_contents.size) != 0)
72 goto done;
73
74 failed = false;
75
76done:
77 if (failed) {
78 git_buf details = GIT_BUF_INIT;
79 git_buf_printf(&details, "filename=%s, system=%s, autocrlf=%s, attrs={%s}",
80 git_path_basename(actual_path->ptr), systype, cd->autocrlf, cd->attrs);
81 clar__fail(__FILE__, __LINE__,
82 "checked out contents did not match expected", details.ptr, 0);
83 git_buf_free(&details);
84 }
85
86 git_buf_free(&expected_contents);
87 git_buf_free(&actual_contents);
88 git_buf_free(&expected_path);
89
90 return 0;
91}
92
93static void test_checkout(const char *autocrlf, const char *attrs)
94{
95 git_buf attrbuf = GIT_BUF_INIT;
96 git_buf expected_dirname = GIT_BUF_INIT;
97 git_buf sandboxname = GIT_BUF_INIT;
98 git_buf reponame = GIT_BUF_INIT;
99 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
100 struct compare_data compare_data = { NULL, autocrlf, attrs };
101 const char *c;
102
103 git_buf_puts(&reponame, "crlf");
104
105 git_buf_puts(&sandboxname, "autocrlf_");
106 git_buf_puts(&sandboxname, autocrlf);
107
108 if (*attrs) {
109 git_buf_puts(&sandboxname, ",");
110
111 for (c = attrs; *c; c++) {
112 if (*c == ' ')
113 git_buf_putc(&sandboxname, ',');
114 else if (*c == '=')
115 git_buf_putc(&sandboxname, '_');
116 else
117 git_buf_putc(&sandboxname, *c);
118 }
119
120 git_buf_printf(&attrbuf, "* %s\n", attrs);
121 cl_git_mkfile("crlf/.gitattributes", attrbuf.ptr);
122 }
123
124 cl_repo_set_string(g_repo, "core.autocrlf", autocrlf);
125
126 git_buf_joinpath(&expected_dirname, systype, sandboxname.ptr);
127 git_buf_joinpath(&expected_fixture, "crlf_data", expected_dirname.ptr);
128 cl_fixture_sandbox(expected_fixture.ptr);
129
130 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
131 git_checkout_head(g_repo, &opts);
132
133 compare_data.dirname = sandboxname.ptr;
134 cl_git_pass(git_path_direach(&reponame, 0, compare_file, &compare_data));
135
136 cl_fixture_cleanup(expected_fixture.ptr);
137 git_buf_free(&expected_fixture);
138
139 git_buf_free(&attrbuf);
140 git_buf_free(&expected_fixture);
141 git_buf_free(&expected_dirname);
142 git_buf_free(&sandboxname);
143 git_buf_free(&reponame);
144}
145
146static void empty_workdir(const char *name)
147{
148 git_vector contents = GIT_VECTOR_INIT;
149 size_t i;
150 const char *fn;
151
152 git_path_dirload(&contents, name, 0, 0);
153 git_vector_foreach(&contents, i, fn) {
154 if (strncasecmp(git_path_basename(fn), ".git", 4) == 0)
155 continue;
156 p_unlink(fn);
157 }
158 git_vector_free_deep(&contents);
159}
160
161void test_checkout_crlf__matches_core_git(void)
162{
163 const char *autocrlf[] = { "true", "false", "input", NULL };
164 const char *attrs[] = { "", "-crlf", "-text", "eol=crlf", "eol=lf",
165 "text", "text eol=crlf", "text eol=lf",
166 "text=auto", "text=auto eol=crlf", "text=auto eol=lf",
167 NULL };
168 const char **a, **b;
169
170 for (a = autocrlf; *a; a++) {
171 for (b = attrs; *b; b++) {
172 empty_workdir("crlf");
173 test_checkout(*a, *b);
174 }
175 }
6e959708
ET
176}
177
6affd71f
BS
178void test_checkout_crlf__detect_crlf_autocrlf_false(void)
179{
180 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 181 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
6affd71f
BS
182
183 cl_repo_set_bool(g_repo, "core.autocrlf", false);
184
185 git_checkout_head(g_repo, &opts);
186
187 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
188 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
189}
190
6e959708
ET
191void test_checkout_crlf__autocrlf_false_index_size_is_unfiltered_size(void)
192{
193 git_index *index;
194 const git_index_entry *entry;
6affd71f 195 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 196 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
6e959708 197
1323c6d1 198 cl_repo_set_bool(g_repo, "core.autocrlf", false);
6e959708 199
6e959708 200 git_repository_index(&index, g_repo);
c4e6ab5f
CMN
201 tick_index(index);
202
203 git_checkout_head(g_repo, &opts);
6e959708
ET
204
205 cl_assert((entry = git_index_get_bypath(index, "all-lf", 0)) != NULL);
206 cl_assert(entry->file_size == strlen(ALL_LF_TEXT_RAW));
207
b8acb775
SS
208 cl_assert((entry = git_index_get_bypath(index, "all-crlf", 0)) != NULL);
209 cl_assert(entry->file_size == strlen(ALL_CRLF_TEXT_RAW));
210
6e959708
ET
211 git_index_free(index);
212}
213
214void test_checkout_crlf__detect_crlf_autocrlf_true(void)
215{
6affd71f 216 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 217 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
6e959708 218
1323c6d1 219 cl_repo_set_bool(g_repo, "core.autocrlf", true);
6e959708
ET
220
221 git_checkout_head(g_repo, &opts);
222
050ab995
RB
223 if (GIT_EOL_NATIVE == GIT_EOL_LF)
224 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
225 else
226 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_AS_CRLF);
227
228 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
6e959708
ET
229}
230
b4c6a9da
L
231void test_checkout_crlf__detect_crlf_autocrlf_true_utf8(void)
232{
233 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 234 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
b4c6a9da
L
235
236 cl_repo_set_bool(g_repo, "core.autocrlf", true);
237
bd5e59ee 238 git_repository_set_head(g_repo, "refs/heads/master");
b4c6a9da
L
239 git_checkout_head(g_repo, &opts);
240
241 if (GIT_EOL_NATIVE == GIT_EOL_LF)
242 {
bd5e59ee
ET
243 check_file_contents("./crlf/few-utf8-chars-lf", FEW_UTF8_LF_RAW);
244 check_file_contents("./crlf/many-utf8-chars-lf", MANY_UTF8_LF_RAW);
b4c6a9da
L
245 }
246 else
247 {
bd5e59ee
ET
248 check_file_contents("./crlf/few-utf8-chars-lf", FEW_UTF8_CRLF_RAW);
249 check_file_contents("./crlf/many-utf8-chars-lf", MANY_UTF8_CRLF_RAW);
b4c6a9da
L
250 }
251
bd5e59ee
ET
252 check_file_contents("./crlf/few-utf8-chars-crlf", FEW_UTF8_CRLF_RAW);
253 check_file_contents("./crlf/many-utf8-chars-crlf", MANY_UTF8_CRLF_RAW);
b4c6a9da
L
254}
255
6e959708
ET
256void test_checkout_crlf__autocrlf_true_index_size_is_filtered_size(void)
257{
258 git_index *index;
259 const git_index_entry *entry;
6affd71f 260 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 261 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
6e959708 262
1323c6d1 263 cl_repo_set_bool(g_repo, "core.autocrlf", true);
6e959708 264
6e959708 265 git_repository_index(&index, g_repo);
c4e6ab5f
CMN
266 tick_index(index);
267
268 git_checkout_head(g_repo, &opts);
6e959708
ET
269
270 cl_assert((entry = git_index_get_bypath(index, "all-lf", 0)) != NULL);
050ab995
RB
271
272 if (GIT_EOL_NATIVE == GIT_EOL_LF)
273 cl_assert_equal_sz(strlen(ALL_LF_TEXT_RAW), entry->file_size);
274 else
275 cl_assert_equal_sz(strlen(ALL_LF_TEXT_AS_CRLF), entry->file_size);
6e959708 276
b8acb775 277 cl_assert((entry = git_index_get_bypath(index, "all-crlf", 0)) != NULL);
050ab995 278 cl_assert_equal_sz(strlen(ALL_CRLF_TEXT_RAW), entry->file_size);
b8acb775 279
6e959708
ET
280 git_index_free(index);
281}
37f9e409
RB
282
283void test_checkout_crlf__with_ident(void)
284{
285 git_index *index;
286 git_blob *blob;
6affd71f 287 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 288 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
37f9e409
RB
289
290 cl_git_mkfile("crlf/.gitattributes",
291 "*.txt text\n*.bin binary\n"
292 "*.crlf text eol=crlf\n"
293 "*.lf text eol=lf\n"
294 "*.ident text ident\n"
295 "*.identcrlf ident text eol=crlf\n"
296 "*.identlf ident text eol=lf\n");
297
298 cl_repo_set_bool(g_repo, "core.autocrlf", true);
299
300 /* add files with $Id$ */
301
302 cl_git_mkfile("crlf/lf.ident", ALL_LF_TEXT_RAW "\n$Id: initial content$\n");
303 cl_git_mkfile("crlf/crlf.ident", ALL_CRLF_TEXT_RAW "\r\n$Id$\r\n\r\n");
eab3746b
RB
304 cl_git_mkfile("crlf/more1.identlf", "$Id$\n" MORE_LF_TEXT_RAW);
305 cl_git_mkfile("crlf/more2.identcrlf", "\r\n$Id: \f$\r\n" MORE_CRLF_TEXT_RAW);
37f9e409
RB
306
307 cl_git_pass(git_repository_index(&index, g_repo));
308 cl_git_pass(git_index_add_bypath(index, "lf.ident"));
309 cl_git_pass(git_index_add_bypath(index, "crlf.ident"));
eab3746b
RB
310 cl_git_pass(git_index_add_bypath(index, "more1.identlf"));
311 cl_git_pass(git_index_add_bypath(index, "more2.identcrlf"));
37f9e409
RB
312 cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "Some ident files\n");
313
314 git_checkout_head(g_repo, &opts);
315
eab3746b 316 /* check that blobs have $Id$ */
37f9e409
RB
317
318 cl_git_pass(git_blob_lookup(&blob, g_repo,
d541170c 319 & git_index_get_bypath(index, "lf.ident", 0)->id));
37f9e409
RB
320 cl_assert_equal_s(
321 ALL_LF_TEXT_RAW "\n$Id$\n", git_blob_rawcontent(blob));
eab3746b 322 git_blob_free(blob);
37f9e409 323
eab3746b 324 cl_git_pass(git_blob_lookup(&blob, g_repo,
d541170c 325 & git_index_get_bypath(index, "more2.identcrlf", 0)->id));
eab3746b
RB
326 cl_assert_equal_s(
327 "\n$Id$\n" MORE_CRLF_TEXT_AS_LF, git_blob_rawcontent(blob));
37f9e409
RB
328 git_blob_free(blob);
329
330 /* check that filesystem is initially untouched - matching core Git */
331
332 cl_assert_equal_file(
333 ALL_LF_TEXT_RAW "\n$Id: initial content$\n", 0, "crlf/lf.ident");
334
335 /* check that forced checkout rewrites correctly */
336
337 p_unlink("crlf/lf.ident");
eab3746b
RB
338 p_unlink("crlf/crlf.ident");
339 p_unlink("crlf/more1.identlf");
340 p_unlink("crlf/more2.identcrlf");
37f9e409
RB
341
342 git_checkout_head(g_repo, &opts);
343
eab3746b 344 if (GIT_EOL_NATIVE == GIT_EOL_LF) {
37f9e409
RB
345 cl_assert_equal_file(
346 ALL_LF_TEXT_RAW
1ecbcd8e 347 "\n$Id: fcf6d4d9c212dc66563b1171b1cd99953c756467 $\n",
37f9e409 348 0, "crlf/lf.ident");
eab3746b
RB
349 cl_assert_equal_file(
350 ALL_CRLF_TEXT_AS_LF
1ecbcd8e 351 "\n$Id: f2c66ad9b2b5a734d9bf00d5000cc10a62b8a857 $\n\n",
eab3746b
RB
352 0, "crlf/crlf.ident");
353 } else {
37f9e409
RB
354 cl_assert_equal_file(
355 ALL_LF_TEXT_AS_CRLF
1ecbcd8e 356 "\r\n$Id: fcf6d4d9c212dc66563b1171b1cd99953c756467 $\r\n",
37f9e409 357 0, "crlf/lf.ident");
eab3746b
RB
358 cl_assert_equal_file(
359 ALL_CRLF_TEXT_RAW
1ecbcd8e 360 "\r\n$Id: f2c66ad9b2b5a734d9bf00d5000cc10a62b8a857 $\r\n\r\n",
eab3746b
RB
361 0, "crlf/crlf.ident");
362 }
363
364 cl_assert_equal_file(
1ecbcd8e 365 "$Id: f7830382dac1f1583422be5530fdfbd26289431b $\n"
eab3746b
RB
366 MORE_LF_TEXT_AS_LF, 0, "crlf/more1.identlf");
367
368 cl_assert_equal_file(
1ecbcd8e 369 "\r\n$Id: 74677a68413012ce8d7e7cfc3f12603df3a3eac4 $\r\n"
eab3746b 370 MORE_CRLF_TEXT_AS_CRLF, 0, "crlf/more2.identcrlf");
37f9e409
RB
371
372 git_index_free(index);
373}
f77127da
ET
374
375void test_checkout_crlf__autocrlf_false_no_attrs(void)
376{
6affd71f 377 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 378 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
f77127da
ET
379
380 cl_repo_set_bool(g_repo, "core.autocrlf", false);
381
382 git_checkout_head(g_repo, &opts);
383
384 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
385 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
386}
387
388void test_checkout_crlf__autocrlf_true_no_attrs(void)
389{
6affd71f 390 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 391 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
f77127da
ET
392
393 cl_repo_set_bool(g_repo, "core.autocrlf", true);
394
395 git_checkout_head(g_repo, &opts);
396
397 if (GIT_EOL_NATIVE == GIT_EOL_CRLF) {
398 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_AS_CRLF);
399 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_AS_CRLF);
400 } else {
401 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
402 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
403 }
404}
405
406void test_checkout_crlf__autocrlf_input_no_attrs(void)
407{
6affd71f 408 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 409 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
f77127da
ET
410
411 cl_repo_set_string(g_repo, "core.autocrlf", "input");
412
413 git_checkout_head(g_repo, &opts);
414
415 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
416 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
417}
418
419void test_checkout_crlf__autocrlf_false_text_auto_attr(void)
420{
6affd71f 421 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 422 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
f77127da
ET
423
424 cl_git_mkfile("./crlf/.gitattributes", "* text=auto\n");
425
426 cl_repo_set_bool(g_repo, "core.autocrlf", false);
427
428 git_checkout_head(g_repo, &opts);
429
d412165f
ET
430 if (GIT_EOL_NATIVE == GIT_EOL_CRLF) {
431 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_AS_CRLF);
432 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_AS_CRLF);
433 } else {
434 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
435 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
436 }
f77127da
ET
437}
438
439void test_checkout_crlf__autocrlf_true_text_auto_attr(void)
440{
6affd71f 441 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 442 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
f77127da
ET
443
444 cl_git_mkfile("./crlf/.gitattributes", "* text=auto\n");
445
446 cl_repo_set_bool(g_repo, "core.autocrlf", true);
447
448 git_checkout_head(g_repo, &opts);
449
450 if (GIT_EOL_NATIVE == GIT_EOL_CRLF) {
451 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_AS_CRLF);
452 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_AS_CRLF);
453 } else {
454 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
455 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
456 }
457}
458
459void test_checkout_crlf__autocrlf_input_text_auto_attr(void)
460{
6affd71f 461 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
96b82b11 462 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
f77127da
ET
463
464 cl_git_mkfile("./crlf/.gitattributes", "* text=auto\n");
465
466 cl_repo_set_string(g_repo, "core.autocrlf", "input");
467
468 git_checkout_head(g_repo, &opts);
469
470 check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW);
471 check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW);
472}
7c2b9e06
JG
473
474void test_checkout_crlf__can_write_empty_file(void)
475{
476 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
477 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
478
479 cl_repo_set_bool(g_repo, "core.autocrlf", true);
480
481 git_repository_set_head(g_repo, "refs/heads/empty-files");
482 git_checkout_head(g_repo, &opts);
483
484 check_file_contents("./crlf/test1.txt", "");
485
486 if (GIT_EOL_NATIVE == GIT_EOL_LF)
487 check_file_contents("./crlf/test2.txt", "test2.txt's content\n");
488 else
489 check_file_contents("./crlf/test2.txt", "test2.txt's content\r\n");
490
491 check_file_contents("./crlf/test3.txt", "");
492}