]> git.proxmox.com Git - libgit2.git/blob - tests/attr/repo.c
abd2381541d87f47deb2eabffdf101f0f8ebdc56
[libgit2.git] / tests / attr / repo.c
1 #include "clar_libgit2.h"
2 #include "futils.h"
3 #include "git2/attr.h"
4 #include "attr.h"
5 #include "sysdir.h"
6
7 #include "attr_expect.h"
8 #include "git2/sys/repository.h"
9
10 static git_repository *g_repo = NULL;
11
12 void test_attr_repo__initialize(void)
13 {
14 g_repo = cl_git_sandbox_init("attr");
15 }
16
17 void test_attr_repo__cleanup(void)
18 {
19 cl_git_sandbox_cleanup();
20 g_repo = NULL;
21 cl_sandbox_set_search_path_defaults();
22 }
23
24 static struct attr_expected get_one_test_cases[] = {
25 { "root_test1", "repoattr", EXPECT_TRUE, NULL },
26 { "root_test1", "rootattr", EXPECT_TRUE, NULL },
27 { "root_test1", "missingattr", EXPECT_UNDEFINED, NULL },
28 { "root_test1", "subattr", EXPECT_UNDEFINED, NULL },
29 { "root_test1", "negattr", EXPECT_UNDEFINED, NULL },
30 { "root_test2", "repoattr", EXPECT_TRUE, NULL },
31 { "root_test2", "rootattr", EXPECT_FALSE, NULL },
32 { "root_test2", "missingattr", EXPECT_UNDEFINED, NULL },
33 { "root_test2", "multiattr", EXPECT_FALSE, NULL },
34 { "root_test3", "repoattr", EXPECT_TRUE, NULL },
35 { "root_test3", "rootattr", EXPECT_UNDEFINED, NULL },
36 { "root_test3", "multiattr", EXPECT_STRING, "3" },
37 { "root_test3", "multi2", EXPECT_UNDEFINED, NULL },
38 { "sub/subdir_test1", "repoattr", EXPECT_TRUE, NULL },
39 { "sub/subdir_test1", "rootattr", EXPECT_TRUE, NULL },
40 { "sub/subdir_test1", "missingattr", EXPECT_UNDEFINED, NULL },
41 { "sub/subdir_test1", "subattr", EXPECT_STRING, "yes" },
42 { "sub/subdir_test1", "negattr", EXPECT_FALSE, NULL },
43 { "sub/subdir_test1", "another", EXPECT_UNDEFINED, NULL },
44 { "sub/subdir_test2.txt", "repoattr", EXPECT_TRUE, NULL },
45 { "sub/subdir_test2.txt", "rootattr", EXPECT_TRUE, NULL },
46 { "sub/subdir_test2.txt", "missingattr", EXPECT_UNDEFINED, NULL },
47 { "sub/subdir_test2.txt", "subattr", EXPECT_STRING, "yes" },
48 { "sub/subdir_test2.txt", "negattr", EXPECT_FALSE, NULL },
49 { "sub/subdir_test2.txt", "another", EXPECT_STRING, "zero" },
50 { "sub/subdir_test2.txt", "reposub", EXPECT_TRUE, NULL },
51 { "sub/sub/subdir.txt", "another", EXPECT_STRING, "one" },
52 { "sub/sub/subdir.txt", "reposubsub", EXPECT_TRUE, NULL },
53 { "sub/sub/subdir.txt", "reposub", EXPECT_UNDEFINED, NULL },
54 { "does-not-exist", "foo", EXPECT_STRING, "yes" },
55 { "sub/deep/file", "deepdeep", EXPECT_TRUE, NULL },
56 { "sub/sub/d/no", "test", EXPECT_STRING, "a/b/d/*" },
57 { "sub/sub/d/yes", "test", EXPECT_UNDEFINED, NULL },
58 };
59
60 void test_attr_repo__get_one(void)
61 {
62 int i;
63
64 for (i = 0; i < (int)ARRAY_SIZE(get_one_test_cases); ++i) {
65 struct attr_expected *scan = &get_one_test_cases[i];
66 const char *value;
67
68 cl_git_pass(git_attr_get(&value, g_repo, 0, scan->path, scan->attr));
69 attr_check_expected(
70 scan->expected, scan->expected_str, scan->attr, value);
71 }
72
73 cl_assert(git_attr_cache__is_cached(
74 g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/attributes"));
75 cl_assert(git_attr_cache__is_cached(
76 g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
77 cl_assert(git_attr_cache__is_cached(
78 g_repo, GIT_ATTR_FILE_SOURCE_FILE, "sub/.gitattributes"));
79 }
80
81 void test_attr_repo__get_one_start_deep(void)
82 {
83 int i;
84
85 for (i = (int)ARRAY_SIZE(get_one_test_cases) - 1; i >= 0; --i) {
86 struct attr_expected *scan = &get_one_test_cases[i];
87 const char *value;
88
89 cl_git_pass(git_attr_get(&value, g_repo, 0, scan->path, scan->attr));
90 attr_check_expected(
91 scan->expected, scan->expected_str, scan->attr, value);
92 }
93
94 cl_assert(git_attr_cache__is_cached(
95 g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".git/info/attributes"));
96 cl_assert(git_attr_cache__is_cached(
97 g_repo, GIT_ATTR_FILE_SOURCE_FILE, ".gitattributes"));
98 cl_assert(git_attr_cache__is_cached(
99 g_repo, GIT_ATTR_FILE_SOURCE_FILE, "sub/.gitattributes"));
100 }
101
102 void test_attr_repo__get_many(void)
103 {
104 const char *names[4] = { "repoattr", "rootattr", "missingattr", "subattr" };
105 const char *values[4];
106
107 cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test1", 4, names));
108
109 cl_assert(GIT_ATTR_IS_TRUE(values[0]));
110 cl_assert(GIT_ATTR_IS_TRUE(values[1]));
111 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
112 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
113
114 cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test2", 4, names));
115
116 cl_assert(GIT_ATTR_IS_TRUE(values[0]));
117 cl_assert(GIT_ATTR_IS_FALSE(values[1]));
118 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
119 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
120
121 cl_git_pass(git_attr_get_many(values, g_repo, 0, "sub/subdir_test1", 4, names));
122
123 cl_assert(GIT_ATTR_IS_TRUE(values[0]));
124 cl_assert(GIT_ATTR_IS_TRUE(values[1]));
125 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
126 cl_assert_equal_s("yes", values[3]);
127 }
128
129 void test_attr_repo__get_many_in_place(void)
130 {
131 const char *vals[4] = { "repoattr", "rootattr", "missingattr", "subattr" };
132
133 /* it should be legal to look up values into the same array that has
134 * the attribute names, overwriting each name as the value is found.
135 */
136
137 cl_git_pass(git_attr_get_many(vals, g_repo, 0, "sub/subdir_test1", 4, vals));
138
139 cl_assert(GIT_ATTR_IS_TRUE(vals[0]));
140 cl_assert(GIT_ATTR_IS_TRUE(vals[1]));
141 cl_assert(GIT_ATTR_IS_UNSPECIFIED(vals[2]));
142 cl_assert_equal_s("yes", vals[3]);
143 }
144
145 static int count_attrs(
146 const char *name,
147 const char *value,
148 void *payload)
149 {
150 GIT_UNUSED(name);
151 GIT_UNUSED(value);
152
153 *((int *)payload) += 1;
154
155 return 0;
156 }
157
158 #define CANCEL_VALUE 12345
159
160 static int cancel_iteration(
161 const char *name,
162 const char *value,
163 void *payload)
164 {
165 GIT_UNUSED(name);
166 GIT_UNUSED(value);
167
168 *((int *)payload) -= 1;
169
170 if (*((int *)payload) < 0)
171 return CANCEL_VALUE;
172
173 return 0;
174 }
175
176 void test_attr_repo__foreach(void)
177 {
178 int count;
179
180 count = 0;
181 cl_git_pass(git_attr_foreach(
182 g_repo, 0, "root_test1", &count_attrs, &count));
183 cl_assert(count == 2);
184
185 count = 0;
186 cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test1",
187 &count_attrs, &count));
188 cl_assert(count == 4); /* repoattr, rootattr, subattr, negattr */
189
190 count = 0;
191 cl_git_pass(git_attr_foreach(g_repo, 0, "sub/subdir_test2.txt",
192 &count_attrs, &count));
193 cl_assert(count == 6); /* repoattr, rootattr, subattr, reposub, negattr, another */
194
195 count = 2;
196 cl_assert_equal_i(
197 CANCEL_VALUE, git_attr_foreach(
198 g_repo, 0, "sub/subdir_test1", &cancel_iteration, &count)
199 );
200 }
201
202 void test_attr_repo__manpage_example(void)
203 {
204 const char *value;
205
206 cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "foo"));
207 cl_assert(GIT_ATTR_IS_TRUE(value));
208
209 cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "bar"));
210 cl_assert(GIT_ATTR_IS_UNSPECIFIED(value));
211
212 cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "baz"));
213 cl_assert(GIT_ATTR_IS_FALSE(value));
214
215 cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "merge"));
216 cl_assert_equal_s("filfre", value);
217
218 cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "frotz"));
219 cl_assert(GIT_ATTR_IS_UNSPECIFIED(value));
220 }
221
222 #define CONTENT "I'm going to be dynamically processed\r\n" \
223 "And my line endings...\r\n" \
224 "...are going to be\n" \
225 "normalized!\r\n"
226
227 #define GITATTR "* text=auto\n" \
228 "*.txt text\n" \
229 "*.data binary\n"
230
231 static void add_to_workdir(const char *filename, const char *content)
232 {
233 git_str buf = GIT_STR_INIT;
234
235 cl_git_pass(git_str_joinpath(&buf, "attr", filename));
236 cl_git_rewritefile(git_str_cstr(&buf), content);
237
238 git_str_dispose(&buf);
239 }
240
241 static void assert_proper_normalization(git_index *index, const char *filename, const char *expected_sha)
242 {
243 size_t index_pos;
244 const git_index_entry *entry;
245
246 add_to_workdir(filename, CONTENT);
247 cl_git_pass(git_index_add_bypath(index, filename));
248
249 cl_assert(!git_index_find(&index_pos, index, filename));
250
251 entry = git_index_get_byindex(index, index_pos);
252 cl_assert_equal_i(0, git_oid_streq(&entry->id, expected_sha));
253 }
254
255 void test_attr_repo__staging_properly_normalizes_line_endings_according_to_gitattributes_directives(void)
256 {
257 git_index* index;
258
259 cl_git_pass(git_repository_index(&index, g_repo));
260
261 add_to_workdir(".gitattributes", GITATTR);
262
263 assert_proper_normalization(index, "text.txt", "22c74203bace3c2e950278c7ab08da0fca9f4e9b");
264 assert_proper_normalization(index, "huh.dunno", "22c74203bace3c2e950278c7ab08da0fca9f4e9b");
265 assert_proper_normalization(index, "binary.data", "66eeff1fcbacf589e6d70aa70edd3fce5be2b37c");
266
267 git_index_free(index);
268 }
269
270 void test_attr_repo__bare_repo_with_index(void)
271 {
272 const char *names[4] = { "test1", "test2", "test3", "test4" };
273 const char *values[4];
274 git_index *index;
275
276 cl_git_pass(git_repository_index(&index, g_repo));
277
278 cl_git_mkfile(
279 "attr/.gitattributes",
280 "*.txt test1 test2=foobar -test3\n"
281 "trial.txt -test1 test2=barfoo !test3 test4\n");
282 cl_git_pass(git_index_add_bypath(index, ".gitattributes"));
283 git_index_free(index);
284
285 cl_must_pass(p_unlink("attr/.gitattributes"));
286 cl_assert(!git_fs_path_exists("attr/.gitattributes"));
287
288 cl_git_pass(git_repository_set_bare(g_repo));
289
290 cl_git_pass(git_attr_get_many(values, g_repo, 0, "file.txt", 4, names));
291
292 cl_assert(GIT_ATTR_IS_TRUE(values[0]));
293 cl_assert_equal_s("foobar", values[1]);
294 cl_assert(GIT_ATTR_IS_FALSE(values[2]));
295 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
296
297 cl_git_pass(git_attr_get_many(values, g_repo, 0, "trial.txt", 4, names));
298
299 cl_assert(GIT_ATTR_IS_FALSE(values[0]));
300 cl_assert_equal_s("barfoo", values[1]);
301 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[2]));
302 cl_assert(GIT_ATTR_IS_TRUE(values[3]));
303
304 cl_git_pass(git_attr_get_many(values, g_repo, 0, "sub/sub/subdir.txt", 4, names));
305
306 cl_assert(GIT_ATTR_IS_TRUE(values[0]));
307 cl_assert_equal_s("foobar", values[1]);
308 cl_assert(GIT_ATTR_IS_FALSE(values[2]));
309 cl_assert(GIT_ATTR_IS_UNSPECIFIED(values[3]));
310 }
311
312 void test_attr_repo__sysdir(void)
313 {
314 git_str sysdir = GIT_STR_INIT;
315 const char *value;
316
317 cl_git_pass(p_mkdir("system", 0777));
318 cl_git_rewritefile("system/gitattributes", "file merge=foo");
319 cl_git_pass(git_str_joinpath(&sysdir, clar_sandbox_path(), "system"));
320 cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, sysdir.ptr));
321 g_repo = cl_git_sandbox_reopen();
322
323 cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "merge"));
324 cl_assert_equal_s(value, "foo");
325
326 cl_git_pass(p_unlink("system/gitattributes"));
327 cl_git_pass(p_rmdir("system"));
328 git_str_dispose(&sysdir);
329 }
330
331 void test_attr_repo__sysdir_with_session(void)
332 {
333 const char *values[2], *attrs[2] = { "foo", "bar" };
334 git_str sysdir = GIT_STR_INIT;
335 git_attr_session session;
336
337 cl_git_pass(p_mkdir("system", 0777));
338 cl_git_rewritefile("system/gitattributes", "file foo=1 bar=2");
339 cl_git_pass(git_str_joinpath(&sysdir, clar_sandbox_path(), "system"));
340 cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, sysdir.ptr));
341 g_repo = cl_git_sandbox_reopen();
342
343 cl_git_pass(git_attr_session__init(&session, g_repo));
344 cl_git_pass(git_attr_get_many_with_session(values, g_repo, &session, NULL, "file", ARRAY_SIZE(attrs), attrs));
345
346 cl_assert_equal_s(values[0], "1");
347 cl_assert_equal_s(values[1], "2");
348
349 cl_git_pass(p_unlink("system/gitattributes"));
350 cl_git_pass(p_rmdir("system"));
351 git_str_dispose(&sysdir);
352 git_attr_session__free(&session);
353 }
354
355 void test_attr_repo__rewrite(void)
356 {
357 const char *value;
358
359 cl_git_rewritefile("attr/.gitattributes", "file.txt foo=first\n");
360 cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
361 cl_assert_equal_s(value, "first");
362
363 cl_git_rewritefile("attr/.gitattributes", "file.txt foo=second\n");
364 cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
365 cl_assert_equal_s(value, "second");
366
367 cl_git_rewritefile("attr/.gitattributes", "file.txt other=value\n");
368 cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
369 cl_assert_equal_p(value, NULL);
370 }
371
372 void test_attr_repo__rewrite_sysdir(void)
373 {
374 git_str sysdir = GIT_STR_INIT;
375 const char *value;
376
377 cl_git_pass(p_mkdir("system", 0777));
378 cl_git_pass(git_str_joinpath(&sysdir, clar_sandbox_path(), "system"));
379 cl_git_pass(git_sysdir_set(GIT_SYSDIR_SYSTEM, sysdir.ptr));
380 g_repo = cl_git_sandbox_reopen();
381
382 cl_git_rewritefile("system/gitattributes", "file foo=first");
383 cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "foo"));
384 cl_assert_equal_s(value, "first");
385
386 cl_git_rewritefile("system/gitattributes", "file foo=second");
387 cl_git_pass(git_attr_get(&value, g_repo, 0, "file", "foo"));
388 cl_assert_equal_s(value, "second");
389
390 git_str_dispose(&sysdir);
391 }
392
393 void test_attr_repo__unlink(void)
394 {
395 const char *value;
396
397 cl_git_rewritefile("attr/.gitattributes", "file.txt foo=value1\n");
398 cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
399 cl_assert_equal_s(value, "value1");
400
401 cl_git_pass(p_unlink("attr/.gitattributes"));
402
403 cl_git_pass(git_attr_get(&value, g_repo, 0, "file.txt", "foo"));
404 cl_assert_equal_p(value, NULL);
405 }