]> git.proxmox.com Git - libgit2.git/blob - tests/refs/create.c
01eb62a52264b40b7025090d2a05fa10118cc6ea
[libgit2.git] / tests / refs / create.c
1 #include "clar_libgit2.h"
2
3 #include "repository.h"
4 #include "git2/reflog.h"
5 #include "reflog.h"
6 #include "ref_helpers.h"
7
8 static const char *current_master_tip = "099fabac3a9ea935598528c27f866e34089c2eff";
9 static const char *current_head_target = "refs/heads/master";
10
11 static git_repository *g_repo;
12
13 void test_refs_create__initialize(void)
14 {
15 g_repo = cl_git_sandbox_init("testrepo");
16 p_fsync__cnt = 0;
17 }
18
19 void test_refs_create__cleanup(void)
20 {
21 cl_git_sandbox_cleanup();
22
23 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 1));
24 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, 1));
25 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 0));
26 }
27
28 void test_refs_create__symbolic(void)
29 {
30 /* create a new symbolic reference */
31 git_reference *new_reference, *looked_up_ref, *resolved_ref;
32 git_repository *repo2;
33 git_oid id;
34
35 const char *new_head_tracker = "ANOTHER_HEAD_TRACKER";
36
37 git_oid_fromstr(&id, current_master_tip);
38
39 /* Create and write the new symbolic reference */
40 cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL));
41
42 /* Ensure the reference can be looked-up... */
43 cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head_tracker));
44 cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC);
45 cl_assert(reference_is_packed(looked_up_ref) == 0);
46 cl_assert_equal_s(looked_up_ref->name, new_head_tracker);
47
48 /* ...peeled.. */
49 cl_git_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
50 cl_assert(git_reference_type(resolved_ref) == GIT_REFERENCE_DIRECT);
51
52 /* ...and that it points to the current master tip */
53 cl_assert_equal_oid(&id, git_reference_target(resolved_ref));
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));
62 cl_assert_equal_oid(&id, git_reference_target(resolved_ref));
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
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));
94 cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC);
95 cl_assert(reference_is_packed(looked_up_ref) == 0);
96 cl_assert_equal_s(looked_up_ref->name, new_head_tracker);
97 git_reference_free(looked_up_ref);
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));
107 cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_SYMBOLIC);
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);
117 }
118
119 void test_refs_create__deep_symbolic(void)
120 {
121 /* create a deep symbolic reference */
122 git_reference *new_reference, *looked_up_ref, *resolved_ref;
123 git_oid id;
124
125 const char *new_head_tracker = "deep/rooted/tracker";
126
127 git_oid_fromstr(&id, current_master_tip);
128
129 cl_git_pass(git_reference_symbolic_create(&new_reference, g_repo, new_head_tracker, current_head_target, 0, NULL));
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));
132 cl_assert_equal_oid(&id, git_reference_target(resolved_ref));
133
134 git_reference_free(new_reference);
135 git_reference_free(looked_up_ref);
136 git_reference_free(resolved_ref);
137 }
138
139 void test_refs_create__oid(void)
140 {
141 /* create a new OID reference */
142 git_reference *new_reference, *looked_up_ref;
143 git_repository *repo2;
144 git_oid id;
145
146 const char *new_head = "refs/heads/new-head";
147
148 git_oid_fromstr(&id, current_master_tip);
149
150 /* Create and write the new object id reference */
151 cl_git_pass(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL));
152
153 /* Ensure the reference can be looked-up... */
154 cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, new_head));
155 cl_assert(git_reference_type(looked_up_ref) & GIT_REFERENCE_DIRECT);
156 cl_assert(reference_is_packed(looked_up_ref) == 0);
157 cl_assert_equal_s(looked_up_ref->name, new_head);
158
159 /* ...and that it points to the current master tip */
160 cl_assert_equal_oid(&id, git_reference_target(looked_up_ref));
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));
167 cl_assert_equal_oid(&id, git_reference_target(looked_up_ref));
168
169 git_repository_free(repo2);
170
171 git_reference_free(new_reference);
172 git_reference_free(looked_up_ref);
173 }
174
175 /* Can by default create a reference that targets at an unknown id */
176 void test_refs_create__oid_unknown_succeeds_without_strict(void)
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
185 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, 0));
186
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));
189 git_reference_free(new_reference);
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 */
197 void test_refs_create__oid_unknown_fails_by_default(void)
198 {
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 */
207 cl_git_fail(git_reference_create(&new_reference, g_repo, new_head, &id, 0, NULL));
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 }
212
213 void test_refs_create__propagate_eexists(void)
214 {
215 git_oid oid;
216
217 /* Make sure it works for oid and for symbolic both */
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));
221 }
222
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
240 static void test_invalid_name(const char *name)
241 {
242 git_reference *new_reference;
243 git_oid id;
244
245 git_oid_fromstr(&id, current_master_tip);
246
247 cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_create(
248 &new_reference, g_repo, name, &id, 0, NULL));
249
250 cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create(
251 &new_reference, g_repo, name, current_head_target, 0, NULL));
252 }
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
277 ret = git_reference_create(&new_reference, g_repo, name, &id, 0, NULL);
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 }
297
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)
310 {
311 git_reference *ref = NULL;
312 git_refdb *refdb;
313 git_oid id;
314
315 p_fsync__cnt = 0;
316
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);
320
321 *create_count = p_fsync__cnt;
322 p_fsync__cnt = 0;
323
324 cl_git_pass(git_repository_refdb(&refdb, g_repo));
325 cl_git_pass(git_refdb_compress(refdb));
326 git_refdb_free(refdb);
327
328 *compress_count = p_fsync__cnt;
329 p_fsync__cnt = 0;
330 }
331
332 void test_refs_create__does_not_fsync_by_default(void)
333 {
334 size_t create_count, compress_count;
335 count_fsyncs(&create_count, &compress_count);
336
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;
344
345 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR, 1));
346 count_fsyncs(&create_count, &compress_count);
347
348 cl_assert_equal_i(expected_fsyncs_create, create_count);
349 cl_assert_equal_i(expected_fsyncs_compress, compress_count);
350 }
351
352 void test_refs_create__fsyncs_when_repo_config_set(void)
353 {
354 size_t create_count, compress_count;
355
356 cl_repo_set_bool(g_repo, "core.fsyncObjectFiles", true);
357
358 count_fsyncs(&create_count, &compress_count);
359
360 cl_assert_equal_i(expected_fsyncs_create, create_count);
361 cl_assert_equal_i(expected_fsyncs_compress, compress_count);
362 }