]>
Commit | Line | Data |
---|---|---|
731df570 | 1 | #include "clar_libgit2.h" |
2 | #include "refs.h" | |
43a04135 | 3 | #include "path.h" |
731df570 | 4 | |
5 | static git_repository *repo; | |
cfbe4be3 | 6 | static git_commit *target; |
b308c11e | 7 | static git_reference *branch; |
731df570 | 8 | |
9 | void test_refs_branches_create__initialize(void) | |
10 | { | |
99dfa470 | 11 | repo = cl_git_sandbox_init("testrepo.git"); |
b308c11e | 12 | branch = NULL; |
99dfa470 | 13 | target = NULL; |
731df570 | 14 | } |
15 | ||
16 | void test_refs_branches_create__cleanup(void) | |
17 | { | |
b308c11e | 18 | git_reference_free(branch); |
9094d30b | 19 | branch = NULL; |
b308c11e | 20 | |
cb7ac81c | 21 | git_commit_free(target); |
9094d30b SC |
22 | target = NULL; |
23 | ||
99dfa470 | 24 | cl_git_sandbox_cleanup(); |
9094d30b | 25 | repo = NULL; |
731df570 | 26 | } |
27 | ||
cfbe4be3 | 28 | static void retrieve_target_from_oid(git_commit **out, git_repository *repo, const char *sha) |
731df570 | 29 | { |
0d847a31 | 30 | git_object *obj; |
731df570 | 31 | |
0d847a31 BS |
32 | cl_git_pass(git_revparse_single(&obj, repo, sha)); |
33 | cl_git_pass(git_commit_lookup(out, repo, git_object_id(obj))); | |
34 | git_object_free(obj); | |
731df570 | 35 | } |
36 | ||
cfbe4be3 | 37 | static void retrieve_known_commit(git_commit **commit, git_repository *repo) |
731df570 | 38 | { |
0d847a31 | 39 | retrieve_target_from_oid(commit, repo, "e90810b8df3"); |
731df570 | 40 | } |
41 | ||
42 | #define NEW_BRANCH_NAME "new-branch-on-the-block" | |
43 | ||
44 | void test_refs_branches_create__can_create_a_local_branch(void) | |
45 | { | |
46 | retrieve_known_commit(&target, repo); | |
47 | ||
6bfb990d | 48 | cl_git_pass(git_branch_create(&branch, repo, NEW_BRANCH_NAME, target, 0)); |
cfbe4be3 | 49 | cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target))); |
731df570 | 50 | } |
51 | ||
52 | void test_refs_branches_create__can_not_create_a_branch_if_its_name_collide_with_an_existing_one(void) | |
53 | { | |
54 | retrieve_known_commit(&target, repo); | |
55 | ||
6bfb990d | 56 | cl_assert_equal_i(GIT_EEXISTS, git_branch_create(&branch, repo, "br2", target, 0)); |
731df570 | 57 | } |
58 | ||
59 | void test_refs_branches_create__can_force_create_over_an_existing_branch(void) | |
60 | { | |
61 | retrieve_known_commit(&target, repo); | |
62 | ||
6bfb990d | 63 | cl_git_pass(git_branch_create(&branch, repo, "br2", target, 1)); |
cfbe4be3 | 64 | cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target))); |
b308c11e | 65 | cl_assert_equal_s("refs/heads/br2", git_reference_name(branch)); |
731df570 | 66 | } |
62173038 | 67 | |
f9793884 | 68 | void test_refs_branches_create__cannot_force_create_over_current_branch_in_nonbare_repo(void) |
1d08b72e L |
69 | { |
70 | const git_oid *oid; | |
71 | git_reference *branch2; | |
f9793884 JF |
72 | |
73 | /* Default repo for these tests is a bare repo, but this test requires a non-bare one */ | |
74 | cl_git_sandbox_cleanup(); | |
75 | repo = cl_git_sandbox_init("testrepo"); | |
1d08b72e L |
76 | retrieve_known_commit(&target, repo); |
77 | ||
78 | cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL)); | |
79 | cl_assert_equal_s("refs/heads/master", git_reference_name(branch2)); | |
80 | cl_assert_equal_i(true, git_branch_is_head(branch2)); | |
81 | oid = git_reference_target(branch2); | |
82 | ||
6bfb990d | 83 | cl_git_fail_with(-1, git_branch_create(&branch, repo, "master", target, 1)); |
1d08b72e L |
84 | branch = NULL; |
85 | cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); | |
86 | cl_assert_equal_s("refs/heads/master", git_reference_name(branch)); | |
87 | cl_git_pass(git_oid_cmp(git_reference_target(branch), oid)); | |
88 | git_reference_free(branch2); | |
89 | } | |
90 | ||
f9793884 JF |
91 | void test_refs_branches_create__can_force_create_over_current_branch_in_bare_repo(void) |
92 | { | |
93 | const git_oid *oid; | |
94 | git_reference *branch2; | |
95 | retrieve_known_commit(&target, repo); | |
96 | ||
97 | cl_git_pass(git_branch_lookup(&branch2, repo, "master", GIT_BRANCH_LOCAL)); | |
98 | cl_assert_equal_s("refs/heads/master", git_reference_name(branch2)); | |
99 | cl_assert_equal_i(true, git_branch_is_head(branch2)); | |
100 | oid = git_commit_id(target); | |
101 | ||
102 | cl_git_pass(git_branch_create(&branch, repo, "master", target, 1)); | |
103 | git_reference_free(branch); | |
104 | branch = NULL; | |
105 | cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL)); | |
106 | cl_assert_equal_s("refs/heads/master", git_reference_name(branch)); | |
107 | cl_git_pass(git_oid_cmp(git_reference_target(branch), oid)); | |
108 | git_reference_free(branch2); | |
109 | } | |
110 | ||
62173038 | 111 | void test_refs_branches_create__creating_a_branch_with_an_invalid_name_returns_EINVALIDSPEC(void) |
112 | { | |
113 | retrieve_known_commit(&target, repo); | |
114 | ||
115 | cl_assert_equal_i(GIT_EINVALIDSPEC, | |
6bfb990d | 116 | git_branch_create(&branch, repo, "inv@{id", target, 0)); |
59bb1126 BS |
117 | } |
118 | ||
43a04135 RB |
119 | static void assert_branch_matches_name( |
120 | const char *expected, const char *lookup_as) | |
121 | { | |
122 | git_reference *ref; | |
e579e0f7 | 123 | git_str b = GIT_STR_INIT; |
43a04135 RB |
124 | |
125 | cl_git_pass(git_branch_lookup(&ref, repo, lookup_as, GIT_BRANCH_LOCAL)); | |
126 | ||
e579e0f7 MB |
127 | cl_git_pass(git_str_sets(&b, "refs/heads/")); |
128 | cl_git_pass(git_str_puts(&b, expected)); | |
43a04135 RB |
129 | cl_assert_equal_s(b.ptr, git_reference_name(ref)); |
130 | ||
131 | cl_git_pass( | |
132 | git_oid_cmp(git_reference_target(ref), git_commit_id(target))); | |
133 | ||
134 | git_reference_free(ref); | |
e579e0f7 | 135 | git_str_dispose(&b); |
43a04135 RB |
136 | } |
137 | ||
138 | void test_refs_branches_create__can_create_branch_with_unicode(void) | |
139 | { | |
140 | const char *nfc = "\xC3\x85\x73\x74\x72\xC3\xB6\x6D"; | |
141 | const char *nfd = "\x41\xCC\x8A\x73\x74\x72\x6F\xCC\x88\x6D"; | |
142 | const char *emoji = "\xF0\x9F\x8D\xB7"; | |
143 | const char *names[] = { nfc, nfd, emoji }; | |
144 | const char *alt[] = { nfd, nfc, NULL }; | |
145 | const char *expected[] = { nfc, nfd, emoji }; | |
146 | unsigned int i; | |
8a2ef218 | 147 | bool fs_decompose_unicode = |
e579e0f7 | 148 | git_fs_path_does_decompose_unicode(git_repository_path(repo)); |
43a04135 RB |
149 | |
150 | retrieve_known_commit(&target, repo); | |
151 | ||
152 | if (cl_repo_get_bool(repo, "core.precomposeunicode")) | |
153 | expected[1] = nfc; | |
43a04135 | 154 | /* test decomp. because not all Mac filesystems decompose unicode */ |
8a2ef218 | 155 | else if (fs_decompose_unicode) |
43a04135 | 156 | expected[0] = nfd; |
43a04135 RB |
157 | |
158 | for (i = 0; i < ARRAY_SIZE(names); ++i) { | |
9d6c3d28 | 159 | const char *name; |
43a04135 | 160 | cl_git_pass(git_branch_create( |
6bfb990d | 161 | &branch, repo, names[i], target, 0)); |
43a04135 RB |
162 | cl_git_pass(git_oid_cmp( |
163 | git_reference_target(branch), git_commit_id(target))); | |
164 | ||
9d6c3d28 AS |
165 | cl_git_pass(git_branch_name(&name, branch)); |
166 | cl_assert_equal_s(expected[i], name); | |
43a04135 | 167 | assert_branch_matches_name(expected[i], names[i]); |
8a2ef218 | 168 | if (fs_decompose_unicode && alt[i]) |
43a04135 RB |
169 | assert_branch_matches_name(expected[i], alt[i]); |
170 | ||
171 | cl_git_pass(git_branch_delete(branch)); | |
172 | git_reference_free(branch); | |
173 | branch = NULL; | |
174 | } | |
175 | } | |
1589a93a JH |
176 | |
177 | /** | |
178 | * Verify that we can create a branch with a name that matches the | |
179 | * namespace of a previously delete branch. | |
180 | * | |
181 | * git branch level_one/level_two | |
182 | * git branch -D level_one/level_two | |
183 | * git branch level_one | |
184 | * | |
185 | * We expect the delete to have deleted the files: | |
186 | * ".git/refs/heads/level_one/level_two" | |
187 | * ".git/logs/refs/heads/level_one/level_two" | |
188 | * It may or may not have deleted the (now empty) | |
189 | * containing directories. To match git.git behavior, | |
190 | * the second create needs to implicilty delete the | |
191 | * directories and create the new files. | |
192 | * "refs/heads/level_one" | |
193 | * "logs/refs/heads/level_one" | |
194 | * | |
195 | * We should not fail to create the branch or its | |
196 | * reflog because of an obsolete namespace container | |
197 | * directory. | |
198 | */ | |
199 | void test_refs_branches_create__name_vs_namespace(void) | |
200 | { | |
201 | const char * name; | |
202 | struct item { | |
203 | const char *first; | |
204 | const char *second; | |
205 | }; | |
206 | static const struct item item[] = { | |
207 | { "level_one/level_two", "level_one" }, | |
208 | { "a/b/c/d/e", "a/b/c/d" }, | |
209 | { "ss/tt/uu/vv/ww", "ss" }, | |
210 | /* And one test case that is deeper. */ | |
211 | { "xx1/xx2/xx3/xx4", "xx1/xx2/xx3/xx4/xx5/xx6" }, | |
212 | { NULL, NULL }, | |
213 | }; | |
214 | const struct item *p; | |
215 | ||
216 | retrieve_known_commit(&target, repo); | |
217 | ||
218 | for (p=item; p->first; p++) { | |
6bfb990d | 219 | cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0)); |
1589a93a JH |
220 | cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target))); |
221 | cl_git_pass(git_branch_name(&name, branch)); | |
222 | cl_assert_equal_s(name, p->first); | |
223 | ||
224 | cl_git_pass(git_branch_delete(branch)); | |
225 | git_reference_free(branch); | |
226 | branch = NULL; | |
227 | ||
6bfb990d | 228 | cl_git_pass(git_branch_create(&branch, repo, p->second, target, 0)); |
1589a93a JH |
229 | git_reference_free(branch); |
230 | branch = NULL; | |
231 | } | |
232 | } | |
233 | ||
234 | /** | |
235 | * We still need to fail if part of the namespace is | |
236 | * still in use. | |
237 | */ | |
238 | void test_refs_branches_create__name_vs_namespace_fail(void) | |
239 | { | |
240 | const char * name; | |
241 | struct item { | |
242 | const char *first; | |
243 | const char *first_alternate; | |
244 | const char *second; | |
245 | }; | |
246 | static const struct item item[] = { | |
247 | { "level_one/level_two", "level_one/alternate", "level_one" }, | |
248 | { "a/b/c/d/e", "a/b/c/d/alternate", "a/b/c/d" }, | |
249 | { "ss/tt/uu/vv/ww", "ss/alternate", "ss" }, | |
250 | { NULL, NULL, NULL }, | |
251 | }; | |
252 | const struct item *p; | |
253 | ||
254 | retrieve_known_commit(&target, repo); | |
255 | ||
256 | for (p=item; p->first; p++) { | |
6bfb990d | 257 | cl_git_pass(git_branch_create(&branch, repo, p->first, target, 0)); |
1589a93a JH |
258 | cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target))); |
259 | cl_git_pass(git_branch_name(&name, branch)); | |
260 | cl_assert_equal_s(name, p->first); | |
261 | ||
262 | cl_git_pass(git_branch_delete(branch)); | |
263 | git_reference_free(branch); | |
264 | branch = NULL; | |
265 | ||
6bfb990d | 266 | cl_git_pass(git_branch_create(&branch, repo, p->first_alternate, target, 0)); |
1589a93a JH |
267 | cl_git_pass(git_oid_cmp(git_reference_target(branch), git_commit_id(target))); |
268 | cl_git_pass(git_branch_name(&name, branch)); | |
269 | cl_assert_equal_s(name, p->first_alternate); | |
270 | ||
271 | /* we do not delete the alternate. */ | |
272 | git_reference_free(branch); | |
273 | branch = NULL; | |
274 | ||
6bfb990d | 275 | cl_git_fail(git_branch_create(&branch, repo, p->second, target, 0)); |
1589a93a JH |
276 | git_reference_free(branch); |
277 | branch = NULL; | |
278 | } | |
279 | } |