1 #include "clar_libgit2.h"
6 #include "attr_expect.h"
7 #include "git2/sys/repository.h"
9 static git_repository
*g_repo
= NULL
;
11 void test_attr_repo__initialize(void)
13 g_repo
= cl_git_sandbox_init("attr");
16 void test_attr_repo__cleanup(void)
18 cl_git_sandbox_cleanup();
22 static struct attr_expected get_one_test_cases
[] = {
23 { "root_test1", "repoattr", EXPECT_TRUE
, NULL
},
24 { "root_test1", "rootattr", EXPECT_TRUE
, NULL
},
25 { "root_test1", "missingattr", EXPECT_UNDEFINED
, NULL
},
26 { "root_test1", "subattr", EXPECT_UNDEFINED
, NULL
},
27 { "root_test1", "negattr", EXPECT_UNDEFINED
, NULL
},
28 { "root_test2", "repoattr", EXPECT_TRUE
, NULL
},
29 { "root_test2", "rootattr", EXPECT_FALSE
, NULL
},
30 { "root_test2", "missingattr", EXPECT_UNDEFINED
, NULL
},
31 { "root_test2", "multiattr", EXPECT_FALSE
, NULL
},
32 { "root_test3", "repoattr", EXPECT_TRUE
, NULL
},
33 { "root_test3", "rootattr", EXPECT_UNDEFINED
, NULL
},
34 { "root_test3", "multiattr", EXPECT_STRING
, "3" },
35 { "root_test3", "multi2", EXPECT_UNDEFINED
, NULL
},
36 { "sub/subdir_test1", "repoattr", EXPECT_TRUE
, NULL
},
37 { "sub/subdir_test1", "rootattr", EXPECT_TRUE
, NULL
},
38 { "sub/subdir_test1", "missingattr", EXPECT_UNDEFINED
, NULL
},
39 { "sub/subdir_test1", "subattr", EXPECT_STRING
, "yes" },
40 { "sub/subdir_test1", "negattr", EXPECT_FALSE
, NULL
},
41 { "sub/subdir_test1", "another", EXPECT_UNDEFINED
, NULL
},
42 { "sub/subdir_test2.txt", "repoattr", EXPECT_TRUE
, NULL
},
43 { "sub/subdir_test2.txt", "rootattr", EXPECT_TRUE
, NULL
},
44 { "sub/subdir_test2.txt", "missingattr", EXPECT_UNDEFINED
, NULL
},
45 { "sub/subdir_test2.txt", "subattr", EXPECT_STRING
, "yes" },
46 { "sub/subdir_test2.txt", "negattr", EXPECT_FALSE
, NULL
},
47 { "sub/subdir_test2.txt", "another", EXPECT_STRING
, "zero" },
48 { "sub/subdir_test2.txt", "reposub", EXPECT_TRUE
, NULL
},
49 { "sub/sub/subdir.txt", "another", EXPECT_STRING
, "one" },
50 { "sub/sub/subdir.txt", "reposubsub", EXPECT_TRUE
, NULL
},
51 { "sub/sub/subdir.txt", "reposub", EXPECT_UNDEFINED
, NULL
},
52 { "does-not-exist", "foo", EXPECT_STRING
, "yes" },
53 { "sub/deep/file", "deepdeep", EXPECT_TRUE
, NULL
},
54 { "sub/sub/d/no", "test", EXPECT_STRING
, "a/b/d/*" },
55 { "sub/sub/d/yes", "test", EXPECT_UNDEFINED
, NULL
},
58 void test_attr_repo__get_one(void)
62 for (i
= 0; i
< (int)ARRAY_SIZE(get_one_test_cases
); ++i
) {
63 struct attr_expected
*scan
= &get_one_test_cases
[i
];
66 cl_git_pass(git_attr_get(&value
, g_repo
, 0, scan
->path
, scan
->attr
));
68 scan
->expected
, scan
->expected_str
, scan
->attr
, value
);
71 cl_assert(git_attr_cache__is_cached(
72 g_repo
, GIT_ATTR_FILE__FROM_FILE
, ".git/info/attributes"));
73 cl_assert(git_attr_cache__is_cached(
74 g_repo
, GIT_ATTR_FILE__FROM_FILE
, ".gitattributes"));
75 cl_assert(git_attr_cache__is_cached(
76 g_repo
, GIT_ATTR_FILE__FROM_FILE
, "sub/.gitattributes"));
79 void test_attr_repo__get_one_start_deep(void)
83 for (i
= (int)ARRAY_SIZE(get_one_test_cases
) - 1; i
>= 0; --i
) {
84 struct attr_expected
*scan
= &get_one_test_cases
[i
];
87 cl_git_pass(git_attr_get(&value
, g_repo
, 0, scan
->path
, scan
->attr
));
89 scan
->expected
, scan
->expected_str
, scan
->attr
, value
);
92 cl_assert(git_attr_cache__is_cached(
93 g_repo
, GIT_ATTR_FILE__FROM_FILE
, ".git/info/attributes"));
94 cl_assert(git_attr_cache__is_cached(
95 g_repo
, GIT_ATTR_FILE__FROM_FILE
, ".gitattributes"));
96 cl_assert(git_attr_cache__is_cached(
97 g_repo
, GIT_ATTR_FILE__FROM_FILE
, "sub/.gitattributes"));
100 void test_attr_repo__get_many(void)
102 const char *names
[4] = { "repoattr", "rootattr", "missingattr", "subattr" };
103 const char *values
[4];
105 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "root_test1", 4, names
));
107 cl_assert(GIT_ATTR_TRUE(values
[0]));
108 cl_assert(GIT_ATTR_TRUE(values
[1]));
109 cl_assert(GIT_ATTR_UNSPECIFIED(values
[2]));
110 cl_assert(GIT_ATTR_UNSPECIFIED(values
[3]));
112 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "root_test2", 4, names
));
114 cl_assert(GIT_ATTR_TRUE(values
[0]));
115 cl_assert(GIT_ATTR_FALSE(values
[1]));
116 cl_assert(GIT_ATTR_UNSPECIFIED(values
[2]));
117 cl_assert(GIT_ATTR_UNSPECIFIED(values
[3]));
119 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "sub/subdir_test1", 4, names
));
121 cl_assert(GIT_ATTR_TRUE(values
[0]));
122 cl_assert(GIT_ATTR_TRUE(values
[1]));
123 cl_assert(GIT_ATTR_UNSPECIFIED(values
[2]));
124 cl_assert_equal_s("yes", values
[3]);
127 void test_attr_repo__get_many_in_place(void)
129 const char *vals
[4] = { "repoattr", "rootattr", "missingattr", "subattr" };
131 /* it should be legal to look up values into the same array that has
132 * the attribute names, overwriting each name as the value is found.
135 cl_git_pass(git_attr_get_many(vals
, g_repo
, 0, "sub/subdir_test1", 4, vals
));
137 cl_assert(GIT_ATTR_TRUE(vals
[0]));
138 cl_assert(GIT_ATTR_TRUE(vals
[1]));
139 cl_assert(GIT_ATTR_UNSPECIFIED(vals
[2]));
140 cl_assert_equal_s("yes", vals
[3]);
143 static int count_attrs(
151 *((int *)payload
) += 1;
156 #define CANCEL_VALUE 12345
158 static int cancel_iteration(
166 *((int *)payload
) -= 1;
168 if (*((int *)payload
) < 0)
174 void test_attr_repo__foreach(void)
179 cl_git_pass(git_attr_foreach(
180 g_repo
, 0, "root_test1", &count_attrs
, &count
));
181 cl_assert(count
== 2);
184 cl_git_pass(git_attr_foreach(g_repo
, 0, "sub/subdir_test1",
185 &count_attrs
, &count
));
186 cl_assert(count
== 4); /* repoattr, rootattr, subattr, negattr */
189 cl_git_pass(git_attr_foreach(g_repo
, 0, "sub/subdir_test2.txt",
190 &count_attrs
, &count
));
191 cl_assert(count
== 6); /* repoattr, rootattr, subattr, reposub, negattr, another */
195 CANCEL_VALUE
, git_attr_foreach(
196 g_repo
, 0, "sub/subdir_test1", &cancel_iteration
, &count
)
200 void test_attr_repo__manpage_example(void)
204 cl_git_pass(git_attr_get(&value
, g_repo
, 0, "sub/abc", "foo"));
205 cl_assert(GIT_ATTR_TRUE(value
));
207 cl_git_pass(git_attr_get(&value
, g_repo
, 0, "sub/abc", "bar"));
208 cl_assert(GIT_ATTR_UNSPECIFIED(value
));
210 cl_git_pass(git_attr_get(&value
, g_repo
, 0, "sub/abc", "baz"));
211 cl_assert(GIT_ATTR_FALSE(value
));
213 cl_git_pass(git_attr_get(&value
, g_repo
, 0, "sub/abc", "merge"));
214 cl_assert_equal_s("filfre", value
);
216 cl_git_pass(git_attr_get(&value
, g_repo
, 0, "sub/abc", "frotz"));
217 cl_assert(GIT_ATTR_UNSPECIFIED(value
));
220 void test_attr_repo__macros(void)
222 const char *names
[5] = { "rootattr", "binary", "diff", "crlf", "frotz" };
223 const char *names2
[5] = { "mymacro", "positive", "negative", "rootattr", "another" };
224 const char *names3
[3] = { "macro2", "multi2", "multi3" };
225 const char *values
[5];
227 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "binfile", 5, names
));
229 cl_assert(GIT_ATTR_TRUE(values
[0]));
230 cl_assert(GIT_ATTR_TRUE(values
[1]));
231 cl_assert(GIT_ATTR_FALSE(values
[2]));
232 cl_assert(GIT_ATTR_FALSE(values
[3]));
233 cl_assert(GIT_ATTR_UNSPECIFIED(values
[4]));
235 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "macro_test", 5, names2
));
237 cl_assert(GIT_ATTR_TRUE(values
[0]));
238 cl_assert(GIT_ATTR_TRUE(values
[1]));
239 cl_assert(GIT_ATTR_FALSE(values
[2]));
240 cl_assert(GIT_ATTR_UNSPECIFIED(values
[3]));
241 cl_assert_equal_s("77", values
[4]);
243 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "macro_test", 3, names3
));
245 cl_assert(GIT_ATTR_TRUE(values
[0]));
246 cl_assert(GIT_ATTR_FALSE(values
[1]));
247 cl_assert_equal_s("answer", values
[2]);
250 void test_attr_repo__bad_macros(void)
252 const char *names
[6] = { "rootattr", "positive", "negative",
253 "firstmacro", "secondmacro", "thirdmacro" };
254 const char *values
[6];
256 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "macro_bad", 6, names
));
258 /* these three just confirm that the "mymacro" rule ran */
259 cl_assert(GIT_ATTR_UNSPECIFIED(values
[0]));
260 cl_assert(GIT_ATTR_TRUE(values
[1]));
261 cl_assert(GIT_ATTR_FALSE(values
[2]));
264 * # let's try some malicious macro defs
265 * [attr]firstmacro -thirdmacro -secondmacro
266 * [attr]secondmacro firstmacro -firstmacro
267 * [attr]thirdmacro secondmacro=hahaha -firstmacro
268 * macro_bad firstmacro secondmacro thirdmacro
270 * firstmacro assignment list ends up with:
271 * -thirdmacro -secondmacro
272 * secondmacro assignment list expands "firstmacro" and ends up with:
273 * -thirdmacro -secondmacro -firstmacro
274 * thirdmacro assignment don't expand so list ends up with:
275 * secondmacro="hahaha"
277 * macro_bad assignment list ends up with:
278 * -thirdmacro -secondmacro firstmacro &&
279 * -thirdmacro -secondmacro -firstmacro secondmacro &&
280 * secondmacro="hahaha" thirdmacro
282 * so summary results should be:
283 * -firstmacro secondmacro="hahaha" thirdmacro
285 cl_assert(GIT_ATTR_FALSE(values
[3]));
286 cl_assert_equal_s("hahaha", values
[4]);
287 cl_assert(GIT_ATTR_TRUE(values
[5]));
290 #define CONTENT "I'm going to be dynamically processed\r\n" \
291 "And my line endings...\r\n" \
292 "...are going to be\n" \
295 #define GITATTR "* text=auto\n" \
299 static void add_to_workdir(const char *filename
, const char *content
)
301 git_buf buf
= GIT_BUF_INIT
;
303 cl_git_pass(git_buf_joinpath(&buf
, "attr", filename
));
304 cl_git_rewritefile(git_buf_cstr(&buf
), content
);
309 static void assert_proper_normalization(git_index
*index
, const char *filename
, const char *expected_sha
)
312 const git_index_entry
*entry
;
314 add_to_workdir(filename
, CONTENT
);
315 cl_git_pass(git_index_add_bypath(index
, filename
));
317 cl_assert(!git_index_find(&index_pos
, index
, filename
));
319 entry
= git_index_get_byindex(index
, index_pos
);
320 cl_assert_equal_i(0, git_oid_streq(&entry
->id
, expected_sha
));
323 void test_attr_repo__staging_properly_normalizes_line_endings_according_to_gitattributes_directives(void)
327 cl_git_pass(git_repository_index(&index
, g_repo
));
329 add_to_workdir(".gitattributes", GITATTR
);
331 assert_proper_normalization(index
, "text.txt", "22c74203bace3c2e950278c7ab08da0fca9f4e9b");
332 assert_proper_normalization(index
, "huh.dunno", "22c74203bace3c2e950278c7ab08da0fca9f4e9b");
333 assert_proper_normalization(index
, "binary.data", "66eeff1fcbacf589e6d70aa70edd3fce5be2b37c");
335 git_index_free(index
);
338 void test_attr_repo__bare_repo_with_index(void)
340 const char *names
[4] = { "test1", "test2", "test3", "test4" };
341 const char *values
[4];
344 cl_git_pass(git_repository_index(&index
, g_repo
));
347 "attr/.gitattributes",
348 "*.txt test1 test2=foobar -test3\n"
349 "trial.txt -test1 test2=barfoo !test3 test4\n");
350 cl_git_pass(git_index_add_bypath(index
, ".gitattributes"));
351 git_index_free(index
);
353 cl_must_pass(p_unlink("attr/.gitattributes"));
354 cl_assert(!git_path_exists("attr/.gitattributes"));
356 cl_git_pass(git_repository_set_bare(g_repo
));
358 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "file.txt", 4, names
));
360 cl_assert(GIT_ATTR_TRUE(values
[0]));
361 cl_assert_equal_s("foobar", values
[1]);
362 cl_assert(GIT_ATTR_FALSE(values
[2]));
363 cl_assert(GIT_ATTR_UNSPECIFIED(values
[3]));
365 cl_git_pass(git_attr_get_many(values
, g_repo
, 0, "trial.txt", 4, names
));
367 cl_assert(GIT_ATTR_FALSE(values
[0]));
368 cl_assert_equal_s("barfoo", values
[1]);
369 cl_assert(GIT_ATTR_UNSPECIFIED(values
[2]));
370 cl_assert(GIT_ATTR_TRUE(values
[3]));