1 #include "clar_libgit2.h"
3 #include "repository.h"
4 #include "git2/reflog.h"
6 #include "ref_helpers.h"
8 static const char *current_master_tip
= "099fabac3a9ea935598528c27f866e34089c2eff";
9 static const char *current_head_target
= "refs/heads/master";
11 static git_repository
*g_repo
;
13 void test_refs_create__initialize(void)
15 g_repo
= cl_git_sandbox_init("testrepo");
19 void test_refs_create__cleanup(void)
21 cl_git_sandbox_cleanup();
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));
28 void test_refs_create__symbolic(void)
30 /* create a new symbolic reference */
31 git_reference
*new_reference
, *looked_up_ref
, *resolved_ref
;
32 git_repository
*repo2
;
35 const char *new_head_tracker
= "ANOTHER_HEAD_TRACKER";
37 git_oid_fromstr(&id
, current_master_tip
);
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
));
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
);
49 cl_git_pass(git_reference_resolve(&resolved_ref
, looked_up_ref
));
50 cl_assert(git_reference_type(resolved_ref
) == GIT_REFERENCE_DIRECT
);
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
);
57 /* Similar test with a fresh new repository */
58 cl_git_pass(git_repository_open(&repo2
, "testrepo"));
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
));
64 git_repository_free(repo2
);
66 git_reference_free(new_reference
);
67 git_reference_free(looked_up_ref
);
68 git_reference_free(resolved_ref
);
71 void test_refs_create__symbolic_with_arbitrary_content(void)
73 git_reference
*new_reference
, *looked_up_ref
;
74 git_repository
*repo2
;
77 const char *new_head_tracker
= "ANOTHER_HEAD_TRACKER";
78 const char *arbitrary_target
= "ARBITRARY DATA";
80 git_oid_fromstr(&id
, current_master_tip
);
82 /* Attempt to create symbolic ref with arbitrary data in target
85 cl_git_fail(git_reference_symbolic_create(&new_reference
, g_repo
, new_head_tracker
, arbitrary_target
, 0, NULL
));
87 git_libgit2_opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION
, 0);
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
));
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
);
99 /* Ensure the target is what we expect it to be */
100 cl_assert_equal_s(git_reference_symbolic_target(new_reference
), arbitrary_target
);
102 /* Similar test with a fresh new repository object */
103 cl_git_pass(git_repository_open(&repo2
, "testrepo"));
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
);
111 /* Ensure the target is what we expect it to be */
112 cl_assert_equal_s(git_reference_symbolic_target(new_reference
), arbitrary_target
);
114 git_repository_free(repo2
);
115 git_reference_free(new_reference
);
116 git_reference_free(looked_up_ref
);
119 void test_refs_create__deep_symbolic(void)
121 /* create a deep symbolic reference */
122 git_reference
*new_reference
, *looked_up_ref
, *resolved_ref
;
125 const char *new_head_tracker
= "deep/rooted/tracker";
127 git_oid_fromstr(&id
, current_master_tip
);
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
));
134 git_reference_free(new_reference
);
135 git_reference_free(looked_up_ref
);
136 git_reference_free(resolved_ref
);
139 void test_refs_create__oid(void)
141 /* create a new OID reference */
142 git_reference
*new_reference
, *looked_up_ref
;
143 git_repository
*repo2
;
146 const char *new_head
= "refs/heads/new-head";
148 git_oid_fromstr(&id
, current_master_tip
);
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
));
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
);
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
);
163 /* Similar test with a fresh new repository */
164 cl_git_pass(git_repository_open(&repo2
, "testrepo"));
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
));
169 git_repository_free(repo2
);
171 git_reference_free(new_reference
);
172 git_reference_free(looked_up_ref
);
175 /* Can by default create a reference that targets at an unknown id */
176 void test_refs_create__oid_unknown_succeeds_without_strict(void)
178 git_reference
*new_reference
, *looked_up_ref
;
181 const char *new_head
= "refs/heads/new-head";
183 git_oid_fromstr(&id
, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644");
185 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION
, 0));
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
);
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
);
196 /* Strict object enforcement enforces valid object id */
197 void test_refs_create__oid_unknown_fails_by_default(void)
199 git_reference
*new_reference
, *looked_up_ref
;
202 const char *new_head
= "refs/heads/new-head";
204 git_oid_fromstr(&id
, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644");
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
));
209 /* Ensure the reference can't be looked-up... */
210 cl_git_fail(git_reference_lookup(&looked_up_ref
, g_repo
, new_head
));
213 void test_refs_create__propagate_eexists(void)
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
));
223 void test_refs_create__existing_dir_propagates_edirectory(void)
225 git_reference
*new_reference
, *fail_reference
;
227 const char *dir_head
= "refs/heads/new-dir/new-head",
228 *fail_head
= "refs/heads/new-dir";
230 git_oid_fromstr(&id
, current_master_tip
);
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
));
237 git_reference_free(new_reference
);
240 static void test_invalid_name(const char *name
)
242 git_reference
*new_reference
;
245 git_oid_fromstr(&id
, current_master_tip
);
247 cl_assert_equal_i(GIT_EINVALIDSPEC
, git_reference_create(
248 &new_reference
, g_repo
, name
, &id
, 0, NULL
));
250 cl_assert_equal_i(GIT_EINVALIDSPEC
, git_reference_symbolic_create(
251 &new_reference
, g_repo
, name
, current_head_target
, 0, NULL
));
254 void test_refs_create__creating_a_reference_with_an_invalid_name_returns_EINVALIDSPEC(void)
256 test_invalid_name("refs/heads/inv@{id");
257 test_invalid_name("refs/heads/back\\slash");
259 test_invalid_name("refs/heads/foo ");
260 test_invalid_name("refs/heads/foo /bar");
261 test_invalid_name("refs/heads/com1:bar/foo");
263 test_invalid_name("refs/heads/e:");
264 test_invalid_name("refs/heads/c:/foo");
266 test_invalid_name("refs/heads/foo.");
269 static void test_win32_name(const char *name
)
271 git_reference
*new_reference
= NULL
;
275 git_oid_fromstr(&id
, current_master_tip
);
277 ret
= git_reference_create(&new_reference
, g_repo
, name
, &id
, 0, NULL
);
280 cl_assert_equal_i(GIT_EINVALIDSPEC
, ret
);
285 git_reference_free(new_reference
);
288 void test_refs_create__creating_a_loose_ref_with_invalid_windows_name(void)
290 test_win32_name("refs/heads/foo./bar");
292 test_win32_name("refs/heads/aux");
293 test_win32_name("refs/heads/aux.foo/bar");
295 test_win32_name("refs/heads/com1");
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.
304 static int expected_fsyncs_create
= 2, expected_fsyncs_compress
= 1;
306 static int expected_fsyncs_create
= 4, expected_fsyncs_compress
= 2;
309 static void count_fsyncs(size_t *create_count
, size_t *compress_count
)
311 git_reference
*ref
= NULL
;
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
);
321 *create_count
= p_fsync__cnt
;
324 cl_git_pass(git_repository_refdb(&refdb
, g_repo
));
325 cl_git_pass(git_refdb_compress(refdb
));
326 git_refdb_free(refdb
);
328 *compress_count
= p_fsync__cnt
;
332 void test_refs_create__does_not_fsync_by_default(void)
334 size_t create_count
, compress_count
;
335 count_fsyncs(&create_count
, &compress_count
);
337 cl_assert_equal_i(0, create_count
);
338 cl_assert_equal_i(0, compress_count
);
341 void test_refs_create__fsyncs_when_global_opt_set(void)
343 size_t create_count
, compress_count
;
345 cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_FSYNC_GITDIR
, 1));
346 count_fsyncs(&create_count
, &compress_count
);
348 cl_assert_equal_i(expected_fsyncs_create
, create_count
);
349 cl_assert_equal_i(expected_fsyncs_compress
, compress_count
);
352 void test_refs_create__fsyncs_when_repo_config_set(void)
354 size_t create_count
, compress_count
;
356 cl_repo_set_bool(g_repo
, "core.fsyncObjectFiles", true);
358 count_fsyncs(&create_count
, &compress_count
);
360 cl_assert_equal_i(expected_fsyncs_create
, create_count
);
361 cl_assert_equal_i(expected_fsyncs_compress
, compress_count
);