]> git.proxmox.com Git - libgit2.git/blob - tests/ignore/path.c
5d53c9df93694fc2925515a1dd4950c6909ad610
[libgit2.git] / tests / ignore / path.c
1 #include "clar_libgit2.h"
2 #include "posix.h"
3 #include "path.h"
4 #include "futils.h"
5
6 static git_repository *g_repo = NULL;
7
8 void test_ignore_path__initialize(void)
9 {
10 g_repo = cl_git_sandbox_init("attr");
11 }
12
13 void test_ignore_path__cleanup(void)
14 {
15 cl_git_sandbox_cleanup();
16 g_repo = NULL;
17 }
18
19 static void assert_is_ignored_(
20 bool expected, const char *filepath,
21 const char *file, const char *func, int line)
22 {
23 int is_ignored = 0;
24
25 cl_git_expect(
26 git_ignore_path_is_ignored(&is_ignored, g_repo, filepath), 0, file, func, line);
27
28 clar__assert_equal(
29 file, func, line, "expected != is_ignored", 1, "%d",
30 (int)(expected != 0), (int)(is_ignored != 0));
31 }
32 #define assert_is_ignored(expected, filepath) \
33 assert_is_ignored_(expected, filepath, __FILE__, __func__, __LINE__)
34
35 void test_ignore_path__honor_temporary_rules(void)
36 {
37 cl_git_rewritefile("attr/.gitignore", "/NewFolder\n/NewFolder/NewFolder");
38
39 assert_is_ignored(false, "File.txt");
40 assert_is_ignored(true, "NewFolder");
41 assert_is_ignored(true, "NewFolder/NewFolder");
42 assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
43 }
44
45 void test_ignore_path__allow_root(void)
46 {
47 cl_git_rewritefile("attr/.gitignore", "/");
48
49 assert_is_ignored(false, "File.txt");
50 assert_is_ignored(false, "NewFolder");
51 assert_is_ignored(false, "NewFolder/NewFolder");
52 assert_is_ignored(false, "NewFolder/NewFolder/File.txt");
53 }
54
55 void test_ignore_path__ignore_space(void)
56 {
57 cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder \n/NewFolder/NewFolder");
58
59 assert_is_ignored(false, "File.txt");
60 assert_is_ignored(true, "NewFolder");
61 assert_is_ignored(true, "NewFolder/NewFolder");
62 assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
63 }
64
65 void test_ignore_path__intermittent_space(void)
66 {
67 cl_git_rewritefile("attr/.gitignore", "foo bar\n");
68
69 assert_is_ignored(false, "foo");
70 assert_is_ignored(false, "bar");
71 assert_is_ignored(true, "foo bar");
72 }
73
74 void test_ignore_path__trailing_space(void)
75 {
76 cl_git_rewritefile(
77 "attr/.gitignore",
78 "foo \n"
79 "bar \n"
80 );
81
82 assert_is_ignored(true, "foo");
83 assert_is_ignored(false, "foo ");
84 assert_is_ignored(true, "bar");
85 assert_is_ignored(false, "bar ");
86 assert_is_ignored(false, "bar ");
87 }
88
89 void test_ignore_path__escaped_trailing_spaces(void)
90 {
91 cl_git_rewritefile(
92 "attr/.gitignore",
93 "foo\\ \n"
94 "bar\\ \\ \n"
95 "baz \\ \n"
96 "qux\\ \n"
97 );
98
99 assert_is_ignored(false, "foo");
100 assert_is_ignored(true, "foo ");
101 assert_is_ignored(false, "bar");
102 assert_is_ignored(false, "bar ");
103 assert_is_ignored(true, "bar ");
104 assert_is_ignored(true, "baz ");
105 assert_is_ignored(false, "baz ");
106 assert_is_ignored(true, "qux ");
107 assert_is_ignored(false, "qux");
108 assert_is_ignored(false, "qux ");
109 }
110
111 void test_ignore_path__ignore_dir(void)
112 {
113 cl_git_rewritefile("attr/.gitignore", "dir/\n");
114
115 assert_is_ignored(true, "dir");
116 assert_is_ignored(true, "dir/file");
117 }
118
119 void test_ignore_path__ignore_dir_with_trailing_space(void)
120 {
121 cl_git_rewritefile("attr/.gitignore", "dir/ \n");
122
123 assert_is_ignored(true, "dir");
124 assert_is_ignored(true, "dir/file");
125 }
126
127 void test_ignore_path__ignore_root(void)
128 {
129 cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder");
130
131 assert_is_ignored(false, "File.txt");
132 assert_is_ignored(true, "NewFolder");
133 assert_is_ignored(true, "NewFolder/NewFolder");
134 assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
135 }
136
137 void test_ignore_path__full_paths(void)
138 {
139 cl_git_rewritefile("attr/.gitignore", "Folder/*/Contained");
140
141 assert_is_ignored(true, "Folder/Middle/Contained");
142 assert_is_ignored(false, "Folder/Middle/More/More/Contained");
143
144 cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained");
145
146 assert_is_ignored(true, "Folder/Middle/Contained");
147 assert_is_ignored(true, "Folder/Middle/More/More/Contained");
148
149 cl_git_rewritefile("attr/.gitignore", "Folder/**/Contained/*/Child");
150
151 assert_is_ignored(true, "Folder/Middle/Contained/Happy/Child");
152 assert_is_ignored(false, "Folder/Middle/Contained/Not/Happy/Child");
153 assert_is_ignored(true, "Folder/Middle/More/More/Contained/Happy/Child");
154 assert_is_ignored(false, "Folder/Middle/More/More/Contained/Not/Happy/Child");
155 }
156
157 void test_ignore_path__more_starstar_cases(void)
158 {
159 cl_must_pass(p_unlink("attr/.gitignore"));
160 cl_git_mkfile(
161 "attr/dir/.gitignore",
162 "sub/**/*.html\n");
163
164 assert_is_ignored(false, "aaa.html");
165 assert_is_ignored(false, "dir");
166 assert_is_ignored(false, "dir/sub");
167 assert_is_ignored(true, "dir/sub/sub2/aaa.html");
168 assert_is_ignored(true, "dir/sub/aaa.html");
169 assert_is_ignored(false, "dir/aaa.html");
170 assert_is_ignored(false, "sub");
171 assert_is_ignored(false, "sub/aaa.html");
172 assert_is_ignored(false, "sub/sub2/aaa.html");
173 }
174
175 void test_ignore_path__leading_stars(void)
176 {
177 cl_git_rewritefile(
178 "attr/.gitignore",
179 "*/onestar\n"
180 "**/twostars\n"
181 "*/parent1/kid1/*\n"
182 "**/parent2/kid2/*\n");
183
184 assert_is_ignored(true, "dir1/onestar");
185 assert_is_ignored(true, "dir1/onestar/child"); /* in ignored dir */
186 assert_is_ignored(false, "dir1/dir2/onestar");
187
188 assert_is_ignored(true, "dir1/twostars");
189 assert_is_ignored(true, "dir1/twostars/child"); /* in ignored dir */
190 assert_is_ignored(true, "dir1/dir2/twostars");
191 assert_is_ignored(true, "dir1/dir2/twostars/child"); /* in ignored dir */
192 assert_is_ignored(true, "dir1/dir2/dir3/twostars");
193
194 assert_is_ignored(true, "dir1/parent1/kid1/file");
195 assert_is_ignored(true, "dir1/parent1/kid1/file/inside/parent");
196 assert_is_ignored(false, "dir1/dir2/parent1/kid1/file");
197 assert_is_ignored(false, "dir1/parent1/file");
198 assert_is_ignored(false, "dir1/kid1/file");
199
200 assert_is_ignored(true, "dir1/parent2/kid2/file");
201 assert_is_ignored(true, "dir1/parent2/kid2/file/inside/parent");
202 assert_is_ignored(true, "dir1/dir2/parent2/kid2/file");
203 assert_is_ignored(true, "dir1/dir2/dir3/parent2/kid2/file");
204 assert_is_ignored(false, "dir1/parent2/file");
205 assert_is_ignored(false, "dir1/kid2/file");
206 }
207
208 void test_ignore_path__globs_and_path_delimiters(void)
209 {
210 cl_git_rewritefile("attr/.gitignore", "foo/bar/**");
211 assert_is_ignored(true, "foo/bar/baz");
212 assert_is_ignored(true, "foo/bar/baz/quux");
213
214 cl_git_rewritefile("attr/.gitignore", "_*/");
215 assert_is_ignored(true, "sub/_test/a/file");
216 assert_is_ignored(false, "test_folder/file");
217 assert_is_ignored(true, "_test/file");
218 assert_is_ignored(true, "_test/a/file");
219
220 cl_git_rewritefile("attr/.gitignore", "**/_*/");
221 assert_is_ignored(true, "sub/_test/a/file");
222 assert_is_ignored(false, "test_folder/file");
223 assert_is_ignored(true, "_test/file");
224 assert_is_ignored(true, "_test/a/file");
225
226 cl_git_rewritefile("attr/.gitignore", "**/_*/foo/bar/*ux");
227
228 assert_is_ignored(true, "sub/_test/foo/bar/qux/file");
229 assert_is_ignored(true, "_test/foo/bar/qux/file");
230 assert_is_ignored(true, "_test/foo/bar/crux/file");
231 assert_is_ignored(false, "_test/foo/bar/code/file");
232 }
233
234 void test_ignore_path__globs_without_star(void)
235 {
236 cl_git_rewritefile(
237 "attr/.gitignore",
238 "*.foo\n"
239 "**.bar\n"
240 );
241
242 assert_is_ignored(true, ".foo");
243 assert_is_ignored(true, "xyz.foo");
244 assert_is_ignored(true, ".bar");
245 assert_is_ignored(true, "x.bar");
246 assert_is_ignored(true, "xyz.bar");
247
248 assert_is_ignored(true, "test/.foo");
249 assert_is_ignored(true, "test/x.foo");
250 assert_is_ignored(true, "test/xyz.foo");
251 assert_is_ignored(true, "test/.bar");
252 assert_is_ignored(true, "test/x.bar");
253 assert_is_ignored(true, "test/xyz.bar");
254 }
255
256 void test_ignore_path__skip_gitignore_directory(void)
257 {
258 cl_git_rewritefile("attr/.git/info/exclude", "/NewFolder\n/NewFolder/NewFolder");
259 cl_must_pass(p_unlink("attr/.gitignore"));
260 cl_assert(!git_path_exists("attr/.gitignore"));
261 p_mkdir("attr/.gitignore", 0777);
262 cl_git_mkfile("attr/.gitignore/garbage.txt", "new_file\n");
263
264 assert_is_ignored(false, "File.txt");
265 assert_is_ignored(true, "NewFolder");
266 assert_is_ignored(true, "NewFolder/NewFolder");
267 assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
268 }
269
270 void test_ignore_path__subdirectory_gitignore(void)
271 {
272 cl_must_pass(p_unlink("attr/.gitignore"));
273 cl_assert(!git_path_exists("attr/.gitignore"));
274 cl_git_mkfile(
275 "attr/.gitignore",
276 "file1\n");
277 cl_git_mkfile(
278 "attr/dir/.gitignore",
279 "file2/\n");
280
281 assert_is_ignored(true, "file1");
282 assert_is_ignored(true, "dir/file1");
283 assert_is_ignored(true, "dir/file2/actual_file"); /* in ignored dir */
284 assert_is_ignored(false, "dir/file3");
285 }
286
287 void test_ignore_path__expand_tilde_to_homedir(void)
288 {
289 git_config *cfg;
290
291 assert_is_ignored(false, "example.global_with_tilde");
292
293 cl_fake_home();
294
295 /* construct fake home with fake global excludes */
296 cl_git_mkfile("home/globalexclude", "# found me\n*.global_with_tilde\n");
297
298 cl_git_pass(git_repository_config(&cfg, g_repo));
299 cl_git_pass(git_config_set_string(cfg, "core.excludesfile", "~/globalexclude"));
300 git_config_free(cfg);
301
302 git_attr_cache_flush(g_repo); /* must reset to pick up change */
303
304 assert_is_ignored(true, "example.global_with_tilde");
305
306 cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
307
308 cl_fake_home_cleanup(NULL);
309
310 git_attr_cache_flush(g_repo); /* must reset to pick up change */
311
312 assert_is_ignored(false, "example.global_with_tilde");
313 }
314
315 /* Ensure that the .gitignore in the subdirectory only affects
316 * items in the subdirectory. */
317 void test_ignore_path__gitignore_in_subdir(void)
318 {
319 cl_git_rmfile("attr/.gitignore");
320
321 cl_must_pass(p_mkdir("attr/dir1", 0777));
322 cl_must_pass(p_mkdir("attr/dir1/dir2", 0777));
323 cl_must_pass(p_mkdir("attr/dir1/dir2/dir3", 0777));
324
325 cl_git_mkfile("attr/dir1/dir2/dir3/.gitignore", "dir1/\ndir1/subdir/");
326
327 assert_is_ignored(false, "dir1/file");
328 assert_is_ignored(false, "dir1/dir2/file");
329 assert_is_ignored(false, "dir1/dir2/dir3/file");
330 assert_is_ignored(true, "dir1/dir2/dir3/dir1/file");
331 assert_is_ignored(true, "dir1/dir2/dir3/dir1/subdir/foo");
332
333 if (cl_repo_get_bool(g_repo, "core.ignorecase")) {
334 cl_git_mkfile("attr/dir1/dir2/dir3/.gitignore", "DiR1/\nDiR1/subdir/\n");
335
336 assert_is_ignored(false, "dir1/file");
337 assert_is_ignored(false, "dir1/dir2/file");
338 assert_is_ignored(false, "dir1/dir2/dir3/file");
339 assert_is_ignored(true, "dir1/dir2/dir3/dir1/file");
340 assert_is_ignored(true, "dir1/dir2/dir3/dir1/subdir/foo");
341 }
342 }
343
344 /* Ensure that files do not match folder cases */
345 void test_ignore_path__dont_ignore_files_for_folder(void)
346 {
347 cl_git_rmfile("attr/.gitignore");
348
349 cl_git_mkfile("attr/dir/.gitignore", "test/\n");
350
351 /* Create "test" as a file; ensure it is not ignored. */
352 cl_git_mkfile("attr/dir/test", "This is a file.");
353
354 assert_is_ignored(false, "dir/test");
355 if (cl_repo_get_bool(g_repo, "core.ignorecase"))
356 assert_is_ignored(false, "dir/TeSt");
357
358 /* Create "test" as a directory; ensure it is ignored. */
359 cl_git_rmfile("attr/dir/test");
360 cl_must_pass(p_mkdir("attr/dir/test", 0777));
361
362 assert_is_ignored(true, "dir/test");
363 if (cl_repo_get_bool(g_repo, "core.ignorecase"))
364 assert_is_ignored(true, "dir/TeSt");
365
366 /* Remove "test" entirely; ensure it is not ignored.
367 * (As it doesn't exist, it is not a directory.)
368 */
369 cl_must_pass(p_rmdir("attr/dir/test"));
370
371 assert_is_ignored(false, "dir/test");
372 if (cl_repo_get_bool(g_repo, "core.ignorecase"))
373 assert_is_ignored(false, "dir/TeSt");
374 }
375
376 void test_ignore_path__symlink_to_outside(void)
377 {
378 #ifdef GIT_WIN32
379 cl_skip();
380 #endif
381
382 cl_git_rewritefile("attr/.gitignore", "symlink\n");
383 cl_git_mkfile("target", "target");
384 cl_git_pass(p_symlink("../target", "attr/symlink"));
385 assert_is_ignored(true, "symlink");
386 assert_is_ignored(true, "lala/../symlink");
387 }
388
389 void test_ignore_path__test(void)
390 {
391 cl_git_rewritefile("attr/.gitignore",
392 "/*/\n"
393 "!/src\n");
394 assert_is_ignored(false, "src/foo.c");
395 assert_is_ignored(false, "src/foo/foo.c");
396 assert_is_ignored(false, "README.md");
397 assert_is_ignored(true, "dist/foo.o");
398 assert_is_ignored(true, "bin/foo");
399 }
400
401 void test_ignore_path__unignore_dir_succeeds(void)
402 {
403 cl_git_rewritefile("attr/.gitignore",
404 "*.c\n"
405 "!src/*.c\n");
406 assert_is_ignored(false, "src/foo.c");
407 assert_is_ignored(true, "src/foo/foo.c");
408 }
409
410 void test_ignore_path__case_insensitive_unignores_previous_rule(void)
411 {
412 git_config *cfg;
413
414 cl_git_rewritefile("attr/.gitignore",
415 "/case\n"
416 "!/Case/\n");
417
418 cl_git_pass(git_repository_config(&cfg, g_repo));
419 cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", true));
420
421 cl_must_pass(p_mkdir("attr/case", 0755));
422 cl_git_mkfile("attr/case/file", "content");
423
424 assert_is_ignored(false, "case/file");
425 }
426
427 void test_ignore_path__case_sensitive_unignore_does_nothing(void)
428 {
429 git_config *cfg;
430
431 cl_git_rewritefile("attr/.gitignore",
432 "/case\n"
433 "!/Case/\n");
434
435 cl_git_pass(git_repository_config(&cfg, g_repo));
436 cl_git_pass(git_config_set_bool(cfg, "core.ignorecase", false));
437
438 cl_must_pass(p_mkdir("attr/case", 0755));
439 cl_git_mkfile("attr/case/file", "content");
440
441 assert_is_ignored(true, "case/file");
442 }
443
444 void test_ignore_path__ignored_subdirfiles_with_subdir_rule(void)
445 {
446 cl_git_rewritefile(
447 "attr/.gitignore",
448 "dir/*\n"
449 "!dir/sub1/sub2/**\n");
450
451 assert_is_ignored(true, "dir/a.test");
452 assert_is_ignored(true, "dir/sub1/a.test");
453 assert_is_ignored(true, "dir/sub1/sub2");
454 }
455
456 void test_ignore_path__ignored_subdirfiles_with_negations(void)
457 {
458 cl_git_rewritefile(
459 "attr/.gitignore",
460 "dir/*\n"
461 "!dir/a.test\n");
462
463 assert_is_ignored(false, "dir/a.test");
464 assert_is_ignored(true, "dir/b.test");
465 assert_is_ignored(true, "dir/sub1/c.test");
466 }
467
468 void test_ignore_path__negative_directory_rules_only_match_directories(void)
469 {
470 cl_git_rewritefile(
471 "attr/.gitignore",
472 "*\n"
473 "!/**/\n"
474 "!*.keep\n"
475 "!.gitignore\n"
476 );
477
478 assert_is_ignored(true, "src");
479 assert_is_ignored(true, "src/A");
480 assert_is_ignored(false, "src/");
481 assert_is_ignored(false, "src/A.keep");
482 assert_is_ignored(false, ".gitignore");
483 }
484
485 void test_ignore_path__escaped_character(void)
486 {
487 cl_git_rewritefile("attr/.gitignore", "\\c\n");
488 assert_is_ignored(true, "c");
489 assert_is_ignored(false, "\\c");
490 }
491
492 void test_ignore_path__escaped_newline(void)
493 {
494 cl_git_rewritefile(
495 "attr/.gitignore",
496 "\\\nnewline\n"
497 );
498
499 assert_is_ignored(true, "\nnewline");
500 }
501
502 void test_ignore_path__escaped_glob(void)
503 {
504 cl_git_rewritefile("attr/.gitignore", "\\*\n");
505 assert_is_ignored(true, "*");
506 assert_is_ignored(false, "foo");
507 }
508
509 void test_ignore_path__escaped_comments(void)
510 {
511 cl_git_rewritefile(
512 "attr/.gitignore",
513 "#foo\n"
514 "\\#bar\n"
515 "\\##baz\n"
516 "\\#\\\\#qux\n"
517 );
518
519 assert_is_ignored(false, "#foo");
520 assert_is_ignored(true, "#bar");
521 assert_is_ignored(false, "\\#bar");
522 assert_is_ignored(true, "##baz");
523 assert_is_ignored(false, "\\##baz");
524 assert_is_ignored(true, "#\\#qux");
525 assert_is_ignored(false, "##qux");
526 assert_is_ignored(false, "\\##qux");
527 }
528
529 void test_ignore_path__escaped_slash(void)
530 {
531 cl_git_rewritefile(
532 "attr/.gitignore",
533 "\\\\\n"
534 "\\\\preceding\n"
535 "inter\\\\mittent\n"
536 "trailing\\\\\n"
537 );
538
539 #ifndef GIT_WIN32
540 assert_is_ignored(true, "\\");
541 assert_is_ignored(true, "\\preceding");
542 #endif
543 assert_is_ignored(true, "inter\\mittent");
544 assert_is_ignored(true, "trailing\\");
545 }
546
547 void test_ignore_path__escaped_space(void)
548 {
549 cl_git_rewritefile(
550 "attr/.gitignore",
551 "foo\\\\ \n"
552 "bar\\\\\\ \n");
553 assert_is_ignored(true, "foo\\");
554 assert_is_ignored(false, "foo\\ ");
555 assert_is_ignored(false, "foo\\\\ ");
556 assert_is_ignored(false, "foo\\\\");
557 assert_is_ignored(true, "bar\\ ");
558 assert_is_ignored(false, "bar\\\\");
559 assert_is_ignored(false, "bar\\\\ ");
560 assert_is_ignored(false, "bar\\\\\\");
561 assert_is_ignored(false, "bar\\\\\\ ");
562 }
563
564 void test_ignore_path__invalid_pattern(void)
565 {
566 cl_git_rewritefile("attr/.gitignore", "[");
567 assert_is_ignored(false, "[f");
568 assert_is_ignored(false, "f");
569 }
570
571 void test_ignore_path__negative_prefix_rule(void)
572 {
573 cl_git_rewritefile("attr/.gitignore", "ff*\n!f\n");
574 assert_is_ignored(true, "fff");
575 assert_is_ignored(true, "ff");
576 assert_is_ignored(false, "f");
577 }