]>
Commit | Line | Data |
---|---|---|
00a48934 BS |
1 | #include "clar_libgit2.h" |
2 | ||
3 | #include "repository.h" | |
4 | #include "git2/reflog.h" | |
5 | #include "reflog.h" | |
d00d5464 | 6 | #include "ref_helpers.h" |
00a48934 | 7 | |
3e026f1b | 8 | static const char *current_master_tip = "099fabac3a9ea935598528c27f866e34089c2eff"; |
00a48934 BS |
9 | static const char *current_head_target = "refs/heads/master"; |
10 | ||
11 | static git_repository *g_repo; | |
12 | ||
471bb8b1 | 13 | void test_refs_create__initialize(void) |
00a48934 | 14 | { |
b84e58f4 | 15 | g_repo = cl_git_sandbox_init("testrepo"); |
af3dcb0e | 16 | p_fsync__cnt = 0; |
00a48934 BS |
17 | } |
18 | ||
471bb8b1 | 19 | void test_refs_create__cleanup(void) |
00a48934 | 20 | { |
b84e58f4 | 21 | cl_git_sandbox_cleanup(); |
98c34149 | 22 | |
d22a8b95 | 23 | cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1)); |
d2b3a21f | 24 | cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 1)); |
6c23704d | 25 | cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0)); |
00a48934 BS |
26 | } |
27 | ||
471bb8b1 | 28 | void test_refs_create__symbolic(void) |
00a48934 | 29 | { |
b84e58f4 | 30 | /* create a new symbolic reference */ |
00a48934 BS |
31 | git_reference *new_reference, *looked_up_ref, *resolved_ref; |
32 | git_repository *repo2; | |
33 | git_oid id; | |
00a48934 | 34 | |
77e06d7e | 35 | const char *new_head_tracker = "ANOTHER_HEAD_TRACKER"; |
00a48934 BS |
36 | |
37 | git_oid_fromstr(&id, current_master_tip); | |
38 | ||
00a48934 | 39 | /* Create and write the new symbolic reference */ |
659cf202 | 40 | cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL)); |
00a48934 BS |
41 | |
42 | /* Ensure the reference can be looked-up... */ | |
43 | cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); | |
ac3d33df | 44 | cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC); |
d00d5464 | 45 | cl_assert(reference_is_packed(looked_up_ref) == 0); |
946a6dc4 | 46 | cl_assert_equal_s(looked_up_ref->name, new_head_tracker); |
00a48934 BS |
47 | |
48 | /* ...peeled.. */ | |
49 | cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); | |
ac3d33df | 50 | cl_assert(git_reference_type(resolved_ref) == GIT_REFERENCE_DIRECT); |
00a48934 BS |
51 | |
52 | /* ...and that it points to the current master tip */ | |
0cee70eb | 53 | cl_assert_equal_oid(&id, git_reference_target(resolved_ref)); |
00a48934 BS |
54 | git_reference_free(looked_up_ref); |
55 | git_reference_free(resolved_ref); | |
56 | ||
57 | /* Similar test with a fresh new repository */ | |
58 | cl_git_pass(git_repository_open(&repo2, "testrepo")); | |
59 | ||
60 | cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker)); | |
61 | cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); | |
0cee70eb | 62 | cl_assert_equal_oid(&id, git_reference_target(resolved_ref)); |
00a48934 BS |
63 | |
64 | git_repository_free(repo2); | |
65 | ||
66 | git_reference_free(new_reference); | |
67 | git_reference_free(looked_up_ref); | |
68 | git_reference_free(resolved_ref); | |
69 | } | |
70 | ||
d2b3a21f RI |
71 | void test_refs_create__symbolic_with_arbitrary_content(void) |
72 | { | |
73 | git_reference *new_reference, *looked_up_ref; | |
74 | git_repository *repo2; | |
75 | git_oid id; | |
76 | ||
77 | const char *new_head_tracker = "ANOTHER_HEAD_TRACKER"; | |
78 | const char *arbitrary_target = "ARBITRARY DATA"; | |
79 | ||
80 | git_oid_fromstr(&id, current_master_tip); | |
81 | ||
82 | /* Attempt to create symbolic ref with arbitrary data in target | |
83 | * fails by default | |
84 | */ | |
85 | cl_git_fail(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL)); | |
86 | ||
87 | git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 0); | |
88 | ||
89 | /* With strict target validation disabled, ref creation succeeds */ | |
90 | cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, arbitrary_target, 0, NULL)); | |
91 | ||
92 | /* Ensure the reference can be looked-up... */ | |
93 | cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); | |
ac3d33df | 94 | cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC); |
d2b3a21f RI |
95 | cl_assert(reference_is_packed(looked_up_ref) == 0); |
96 | cl_assert_equal_s(looked_up_ref->name, new_head_tracker); | |
5aa1f12a | 97 | git_reference_free(looked_up_ref); |
d2b3a21f RI |
98 | |
99 | /* Ensure the target is what we expect it to be */ | |
100 | cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target); | |
101 | ||
102 | /* Similar test with a fresh new repository object */ | |
103 | cl_git_pass(git_repository_open(&repo2, "testrepo")); | |
104 | ||
105 | /* Ensure the reference can be looked-up... */ | |
106 | cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker)); | |
ac3d33df | 107 | cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC); |
d2b3a21f RI |
108 | cl_assert(reference_is_packed(looked_up_ref) == 0); |
109 | cl_assert_equal_s(looked_up_ref->name, new_head_tracker); | |
110 | ||
111 | /* Ensure the target is what we expect it to be */ | |
112 | cl_assert_equal_s(git_reference_symbolic_target(new_reference), arbitrary_target); | |
113 | ||
114 | git_repository_free(repo2); | |
115 | git_reference_free(new_reference); | |
116 | git_reference_free(looked_up_ref); | |
d2b3a21f RI |
117 | } |
118 | ||
471bb8b1 | 119 | void test_refs_create__deep_symbolic(void) |
00a48934 | 120 | { |
b84e58f4 | 121 | /* create a deep symbolic reference */ |
00a48934 BS |
122 | git_reference *new_reference, *looked_up_ref, *resolved_ref; |
123 | git_oid id; | |
00a48934 BS |
124 | |
125 | const char *new_head_tracker = "deep/rooted/tracker"; | |
126 | ||
127 | git_oid_fromstr(&id, current_master_tip); | |
128 | ||
659cf202 | 129 | cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL)); |
00a48934 BS |
130 | cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker)); |
131 | cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); | |
0cee70eb | 132 | cl_assert_equal_oid(&id, git_reference_target(resolved_ref)); |
00a48934 BS |
133 | |
134 | git_reference_free(new_reference); | |
135 | git_reference_free(looked_up_ref); | |
136 | git_reference_free(resolved_ref); | |
00a48934 BS |
137 | } |
138 | ||
471bb8b1 | 139 | void test_refs_create__oid(void) |
00a48934 | 140 | { |
b84e58f4 | 141 | /* create a new OID reference */ |
00a48934 BS |
142 | git_reference *new_reference, *looked_up_ref; |
143 | git_repository *repo2; | |
144 | git_oid id; | |
00a48934 BS |
145 | |
146 | const char *new_head = "refs/heads/new-head"; | |
147 | ||
148 | git_oid_fromstr(&id, current_master_tip); | |
149 | ||
00a48934 | 150 | /* Create and write the new object id reference */ |
659cf202 | 151 | cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL)); |
00a48934 BS |
152 | |
153 | /* Ensure the reference can be looked-up... */ | |
154 | cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head)); | |
ac3d33df | 155 | cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_DIRECT); |
d00d5464 | 156 | cl_assert(reference_is_packed(looked_up_ref) == 0); |
946a6dc4 | 157 | cl_assert_equal_s(looked_up_ref->name, new_head); |
00a48934 BS |
158 | |
159 | /* ...and that it points to the current master tip */ | |
0cee70eb | 160 | cl_assert_equal_oid(&id, git_reference_target(looked_up_ref)); |
00a48934 BS |
161 | git_reference_free(looked_up_ref); |
162 | ||
163 | /* Similar test with a fresh new repository */ | |
164 | cl_git_pass(git_repository_open(&repo2, "testrepo")); | |
165 | ||
166 | cl_git_pass(git_reference_lookup(&looked_up_ref, repo2, new_head)); | |
0cee70eb | 167 | cl_assert_equal_oid(&id, git_reference_target(looked_up_ref)); |
00a48934 BS |
168 | |
169 | git_repository_free(repo2); | |
170 | ||
171 | git_reference_free(new_reference); | |
172 | git_reference_free(looked_up_ref); | |
00a48934 BS |
173 | } |
174 | ||
98c34149 | 175 | /* Can by default create a reference that targets at an unknown id */ |
d22a8b95 | 176 | void test_refs_create__oid_unknown_succeeds_without_strict(void) |
98c34149 ET |
177 | { |
178 | git_reference *new_reference, *looked_up_ref; | |
179 | git_oid id; | |
180 | ||
181 | const char *new_head = "refs/heads/new-head"; | |
182 | ||
183 | git_oid_fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644"); | |
184 | ||
d22a8b95 ET |
185 | cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0)); |
186 | ||
98c34149 ET |
187 | /* Create and write the new object id reference */ |
188 | cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL)); | |
9b3fc895 | 189 | git_reference_free(new_reference); |
98c34149 ET |
190 | |
191 | /* Ensure the reference can't be looked-up... */ | |
192 | cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head)); | |
193 | git_reference_free(looked_up_ref); | |
194 | } | |
195 | ||
196 | /* Strict object enforcement enforces valid object id */ | |
d22a8b95 | 197 | void test_refs_create__oid_unknown_fails_by_default(void) |
00a48934 | 198 | { |
00a48934 BS |
199 | git_reference *new_reference, *looked_up_ref; |
200 | git_oid id; | |
201 | ||
202 | const char *new_head = "refs/heads/new-head"; | |
203 | ||
204 | git_oid_fromstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644"); | |
205 | ||
206 | /* Create and write the new object id reference */ | |
659cf202 | 207 | cl_git_fail(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL)); |
00a48934 BS |
208 | |
209 | /* Ensure the reference can't be looked-up... */ | |
210 | cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, new_head)); | |
211 | } | |
c1281493 CMN |
212 | |
213 | void test_refs_create__propagate_eexists(void) | |
214 | { | |
c1281493 | 215 | git_oid oid; |
c1281493 CMN |
216 | |
217 | /* Make sure it works for oid and for symbolic both */ | |
22a2d3d5 UG |
218 | cl_git_pass(git_oid_fromstr(&oid, current_master_tip)); |
219 | cl_git_fail_with(GIT_EEXISTS, git_reference_create(NULL, g_repo, current_head_target, &oid, false, NULL)); | |
220 | cl_git_fail_with(GIT_EEXISTS, git_reference_symbolic_create(NULL, g_repo, "HEAD", current_head_target, false, NULL)); | |
c1281493 | 221 | } |
80d9d1df | 222 | |
b46c7ee5 ET |
223 | void test_refs_create__existing_dir_propagates_edirectory(void) |
224 | { | |
225 | git_reference *new_reference, *fail_reference; | |
226 | git_oid id; | |
227 | const char *dir_head = "refs/heads/new-dir/new-head", | |
228 | *fail_head = "refs/heads/new-dir"; | |
229 | ||
230 | git_oid_fromstr(&id, current_master_tip); | |
231 | ||
232 | /* Create and write the new object id reference */ | |
233 | cl_git_pass(git_reference_create(&new_reference, g_repo, dir_head, &id, 1, NULL)); | |
234 | cl_git_fail_with(GIT_EDIRECTORY, | |
235 | git_reference_create(&fail_reference, g_repo, fail_head, &id, false, NULL)); | |
236 | ||
237 | git_reference_free(new_reference); | |
238 | } | |
239 | ||
ee5da720 | 240 | static void test_invalid_name(const char *name) |
80d9d1df | 241 | { |
242 | git_reference *new_reference; | |
243 | git_oid id; | |
244 | ||
80d9d1df | 245 | git_oid_fromstr(&id, current_master_tip); |
246 | ||
247 | cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_create( | |
659cf202 | 248 | &new_reference, g_repo, name, &id, 0, NULL)); |
80d9d1df | 249 | |
250 | cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create( | |
659cf202 | 251 | &new_reference, g_repo, name, current_head_target, 0, NULL)); |
80d9d1df | 252 | } |
ee5da720 ET |
253 | |
254 | void test_refs_create__creating_a_reference_with_an_invalid_name_returns_EINVALIDSPEC(void) | |
255 | { | |
256 | test_invalid_name("refs/heads/inv@{id"); | |
257 | test_invalid_name("refs/heads/back\\slash"); | |
258 | ||
259 | test_invalid_name("refs/heads/foo "); | |
260 | test_invalid_name("refs/heads/foo /bar"); | |
261 | test_invalid_name("refs/heads/com1:bar/foo"); | |
262 | ||
263 | test_invalid_name("refs/heads/e:"); | |
264 | test_invalid_name("refs/heads/c:/foo"); | |
265 | ||
266 | test_invalid_name("refs/heads/foo."); | |
267 | } | |
268 | ||
269 | static void test_win32_name(const char *name) | |
270 | { | |
271 | git_reference *new_reference = NULL; | |
272 | git_oid id; | |
273 | int ret; | |
274 | ||
275 | git_oid_fromstr(&id, current_master_tip); | |
276 | ||
659cf202 | 277 | ret = git_reference_create(&new_reference, g_repo, name, &id, 0, NULL); |
ee5da720 ET |
278 | |
279 | #ifdef GIT_WIN32 | |
280 | cl_assert_equal_i(GIT_EINVALIDSPEC, ret); | |
281 | #else | |
282 | cl_git_pass(ret); | |
283 | #endif | |
284 | ||
285 | git_reference_free(new_reference); | |
286 | } | |
287 | ||
288 | void test_refs_create__creating_a_loose_ref_with_invalid_windows_name(void) | |
289 | { | |
290 | test_win32_name("refs/heads/foo./bar"); | |
291 | ||
292 | test_win32_name("refs/heads/aux"); | |
293 | test_win32_name("refs/heads/aux.foo/bar"); | |
294 | ||
295 | test_win32_name("refs/heads/com1"); | |
296 | } | |
af3dcb0e | 297 | |
1c04a96b ET |
298 | /* Creating a loose ref involves fsync'ing the reference, the |
299 | * reflog and (on non-Windows) the containing directories. | |
300 | * Creating a packed ref involves fsync'ing the packed ref file | |
301 | * and (on non-Windows) the containing directory. | |
302 | */ | |
303 | #ifdef GIT_WIN32 | |
304 | static int expected_fsyncs_create = 2, expected_fsyncs_compress = 1; | |
305 | #else | |
306 | static int expected_fsyncs_create = 4, expected_fsyncs_compress = 2; | |
307 | #endif | |
308 | ||
309 | static void count_fsyncs(size_t *create_count, size_t *compress_count) | |
af3dcb0e ET |
310 | { |
311 | git_reference *ref = NULL; | |
eb56ed81 | 312 | git_refdb *refdb; |
af3dcb0e ET |
313 | git_oid id; |
314 | ||
1c04a96b ET |
315 | p_fsync__cnt = 0; |
316 | ||
af3dcb0e ET |
317 | git_oid_fromstr(&id, current_master_tip); |
318 | cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/fsync_test", &id, 0, "log message")); | |
319 | git_reference_free(ref); | |
eb56ed81 | 320 | |
1c04a96b ET |
321 | *create_count = p_fsync__cnt; |
322 | p_fsync__cnt = 0; | |
323 | ||
eb56ed81 ET |
324 | cl_git_pass(git_repository_refdb(&refdb, g_repo)); |
325 | cl_git_pass(git_refdb_compress(refdb)); | |
326 | git_refdb_free(refdb); | |
327 | ||
1c04a96b ET |
328 | *compress_count = p_fsync__cnt; |
329 | p_fsync__cnt = 0; | |
af3dcb0e ET |
330 | } |
331 | ||
1c04a96b | 332 | void test_refs_create__does_not_fsync_by_default(void) |
af3dcb0e | 333 | { |
1c04a96b ET |
334 | size_t create_count, compress_count; |
335 | count_fsyncs(&create_count, &compress_count); | |
af3dcb0e | 336 | |
1c04a96b ET |
337 | cl_assert_equal_i(0, create_count); |
338 | cl_assert_equal_i(0, compress_count); | |
339 | } | |
340 | ||
341 | void test_refs_create__fsyncs_when_global_opt_set(void) | |
342 | { | |
343 | size_t create_count, compress_count; | |
3ac05d11 | 344 | |
6c23704d | 345 | cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1)); |
1c04a96b | 346 | count_fsyncs(&create_count, &compress_count); |
af3dcb0e | 347 | |
1c04a96b ET |
348 | cl_assert_equal_i(expected_fsyncs_create, create_count); |
349 | cl_assert_equal_i(expected_fsyncs_compress, compress_count); | |
350 | } | |
eb56ed81 | 351 | |
1c04a96b ET |
352 | void test_refs_create__fsyncs_when_repo_config_set(void) |
353 | { | |
354 | size_t create_count, compress_count; | |
eb56ed81 | 355 | |
1c04a96b ET |
356 | cl_repo_set_bool(g_repo, "core.fsyncObjectFiles", true); |
357 | ||
358 | count_fsyncs(&create_count, &compress_count); | |
eb56ed81 | 359 | |
1c04a96b ET |
360 | cl_assert_equal_i(expected_fsyncs_create, create_count); |
361 | cl_assert_equal_i(expected_fsyncs_compress, compress_count); | |
af3dcb0e | 362 | } |