rename.c 13.6 KB
Newer Older
Ben Straub committed
1 2
#include "clar_libgit2.h"

3
#include "fileops.h"
Ben Straub committed
4 5
#include "git2/reflog.h"
#include "reflog.h"
6
#include "refs.h"
7
#include "ref_helpers.h"
Ben Straub committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

static const char *loose_tag_ref_name = "refs/tags/e90810b";
static const char *packed_head_name = "refs/heads/packed";
static const char *packed_test_head_name = "refs/heads/packed-test";
static const char *ref_one_name = "refs/heads/one/branch";
static const char *ref_one_name_new = "refs/heads/two/branch";
static const char *ref_two_name = "refs/heads/two";
static const char *ref_master_name = "refs/heads/master";
static const char *ref_two_name_new = "refs/heads/two/two";

static git_repository *g_repo;



void test_refs_rename__initialize(void)
{
24
	g_repo = cl_git_sandbox_init("testrepo");
Ben Straub committed
25 26 27 28
}

void test_refs_rename__cleanup(void)
{
29
	cl_git_sandbox_cleanup();
Ben Straub committed
30 31 32 33 34 35
}



void test_refs_rename__loose(void)
{
36
	// rename a loose reference
37
	git_reference *looked_up_ref, *new_ref, *another_looked_up_ref;
Ben Straub committed
38 39 40 41
	git_buf temp_path = GIT_BUF_INIT;
	const char *new_name = "refs/tags/Nemo/knows/refs.kung-fu";

	/* Ensure the ref doesn't exist on the file system */
42
	cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), new_name));
Vicent Martí committed
43
	cl_assert(!git_path_exists(temp_path.ptr));
Ben Straub committed
44 45 46 47 48

	/* Retrieval of the reference to rename */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, loose_tag_ref_name));

	/* ... which is indeed loose */
49
	cl_assert(reference_is_packed(looked_up_ref) == 0);
Ben Straub committed
50 51

	/* Now that the reference is renamed... */
52
	cl_git_pass(git_reference_rename(&new_ref, looked_up_ref, new_name, 0, NULL, NULL));
53 54
	cl_assert_equal_s(new_ref->name, new_name);
	git_reference_free(looked_up_ref);
Ben Straub committed
55 56 57 58 59 60

	/* ...It can't be looked-up with the old name... */
	cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, loose_tag_ref_name));

	/* ...but the new name works ok... */
	cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, new_name));
61
	cl_assert_equal_s(new_ref->name, new_name);
Ben Straub committed
62

63 64 65
	/* .. the new ref is loose... */
	cl_assert(reference_is_packed(another_looked_up_ref) == 0);
	cl_assert(reference_is_packed(new_ref) == 0);
Ben Straub committed
66 67

	/* ...and the ref can be found in the file system */
68
	cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), new_name));
Vicent Martí committed
69
	cl_assert(git_path_exists(temp_path.ptr));
Ben Straub committed
70

71
	git_reference_free(new_ref);
Ben Straub committed
72 73 74 75 76 77
	git_reference_free(another_looked_up_ref);
	git_buf_free(&temp_path);
}

void test_refs_rename__packed(void)
{
78
	// rename a packed reference (should make it loose)
79
	git_reference *looked_up_ref, *new_ref, *another_looked_up_ref;
Ben Straub committed
80 81 82 83
	git_buf temp_path = GIT_BUF_INIT;
	const char *brand_new_name = "refs/heads/brand_new_name";

	/* Ensure the ref doesn't exist on the file system */
84
	cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_head_name));
Vicent Martí committed
85
	cl_assert(!git_path_exists(temp_path.ptr));
Ben Straub committed
86 87 88 89 90

	/* The reference can however be looked-up... */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));

	/* .. and it's packed */
91
	cl_assert(reference_is_packed(looked_up_ref) != 0);
Ben Straub committed
92 93

	/* Now that the reference is renamed... */
94
	cl_git_pass(git_reference_rename(&new_ref, looked_up_ref, brand_new_name, 0, NULL, NULL));
95 96
	cl_assert_equal_s(new_ref->name, brand_new_name);
	git_reference_free(looked_up_ref);
Ben Straub committed
97 98 99 100 101 102

	/* ...It can't be looked-up with the old name... */
	cl_git_fail(git_reference_lookup(&another_looked_up_ref, g_repo, packed_head_name));

	/* ...but the new name works ok... */
	cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, brand_new_name));
Vicent Martí committed
103
	cl_assert_equal_s(another_looked_up_ref->name, brand_new_name);
Ben Straub committed
104 105

	/* .. the ref is no longer packed... */
106 107
	cl_assert(reference_is_packed(another_looked_up_ref) == 0);
	cl_assert(reference_is_packed(new_ref) == 0);
Ben Straub committed
108 109

	/* ...and the ref now happily lives in the file system */
110
	cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), brand_new_name));
Vicent Martí committed
111
	cl_assert(git_path_exists(temp_path.ptr));
Ben Straub committed
112

113
	git_reference_free(new_ref);
Ben Straub committed
114 115 116 117 118 119
	git_reference_free(another_looked_up_ref);
	git_buf_free(&temp_path);
}

void test_refs_rename__packed_doesnt_pack_others(void)
{
120
	// renaming a packed reference does not pack another reference which happens to be in both loose and pack state
121
	git_reference *looked_up_ref, *another_looked_up_ref, *renamed_ref;
Ben Straub committed
122 123 124 125
	git_buf temp_path = GIT_BUF_INIT;
	const char *brand_new_name = "refs/heads/brand_new_name";

	/* Ensure the other reference exists on the file system */
126
	cl_git_pass(git_buf_joinpath(&temp_path, git_repository_path(g_repo), packed_test_head_name));
Vicent Martí committed
127
	cl_assert(git_path_exists(temp_path.ptr));
Ben Straub committed
128 129 130 131 132

	/* Lookup the other reference */
	cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name));

	/* Ensure it's loose */
133
	cl_assert(reference_is_packed(another_looked_up_ref) == 0);
Ben Straub committed
134 135 136 137 138 139
	git_reference_free(another_looked_up_ref);

	/* Lookup the reference to rename */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));

	/* Ensure it's packed */
140
	cl_assert(reference_is_packed(looked_up_ref) != 0);
Ben Straub committed
141 142

	/* Now that the reference is renamed... */
143
	cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, brand_new_name, 0, NULL, NULL));
144
	git_reference_free(looked_up_ref);
Ben Straub committed
145 146 147 148 149

	/* Lookup the other reference */
	cl_git_pass(git_reference_lookup(&another_looked_up_ref, g_repo, packed_test_head_name));

	/* Ensure it's loose */
150
	cl_assert(reference_is_packed(another_looked_up_ref) == 0);
Ben Straub committed
151 152

	/* Ensure the other ref still exists on the file system */
Vicent Martí committed
153
	cl_assert(git_path_exists(temp_path.ptr));
Ben Straub committed
154

155
	git_reference_free(renamed_ref);
Ben Straub committed
156 157 158 159 160 161
	git_reference_free(another_looked_up_ref);
	git_buf_free(&temp_path);
}

void test_refs_rename__name_collision(void)
{
162
	// can not rename a reference with the name of an existing reference
163
	git_reference *looked_up_ref, *renamed_ref;
Ben Straub committed
164 165 166 167 168

	/* An existing reference... */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));

	/* Can not be renamed to the name of another existing reference. */
169
	cl_git_fail(git_reference_rename(&renamed_ref, looked_up_ref, packed_test_head_name, 0, NULL, NULL));
Ben Straub committed
170 171 172 173
	git_reference_free(looked_up_ref);

	/* Failure to rename it hasn't corrupted its state */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
Vicent Martí committed
174
	cl_assert_equal_s(looked_up_ref->name, packed_head_name);
Ben Straub committed
175 176 177 178 179 180

	git_reference_free(looked_up_ref);
}

void test_refs_rename__invalid_name(void)
{
181
	// can not rename a reference with an invalid name
182
	git_reference *looked_up_ref, *renamed_ref;
Ben Straub committed
183 184 185 186 187

	/* An existing oid reference... */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));

	/* Can not be renamed with an invalid name. */
188 189
	cl_assert_equal_i(
		GIT_EINVALIDSPEC,
190
		git_reference_rename(&renamed_ref, looked_up_ref, "Hello! I'm a very invalid name.", 0, NULL, NULL));
191 192 193 194

	/* Can not be renamed outside of the refs hierarchy
	 * unless it's ALL_CAPS_AND_UNDERSCORES.
	 */
195
	cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_rename(&renamed_ref, looked_up_ref, "i-will-sudo-you", 0, NULL, NULL));
Ben Straub committed
196 197 198 199

	/* Failure to rename it hasn't corrupted its state */
	git_reference_free(looked_up_ref);
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));
Vicent Martí committed
200
	cl_assert_equal_s(looked_up_ref->name, packed_test_head_name);
Ben Straub committed
201 202 203 204 205 206

	git_reference_free(looked_up_ref);
}

void test_refs_rename__force_loose_packed(void)
{
207
	// can force-rename a packed reference with the name of an existing loose and packed reference
208
	git_reference *looked_up_ref, *renamed_ref;
Ben Straub committed
209 210 211 212
	git_oid oid;

	/* An existing reference... */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
213
	git_oid_cpy(&oid, git_reference_target(looked_up_ref));
Ben Straub committed
214 215

	/* Can be force-renamed to the name of another existing reference. */
216
	cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, packed_test_head_name, 1, NULL, NULL));
Ben Straub committed
217
	git_reference_free(looked_up_ref);
218
	git_reference_free(renamed_ref);
Ben Straub committed
219 220 221

	/* Check we actually renamed it */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, packed_test_head_name));
Vicent Martí committed
222
	cl_assert_equal_s(looked_up_ref->name, packed_test_head_name);
223
	cl_assert(!git_oid_cmp(&oid, git_reference_target(looked_up_ref)));
Ben Straub committed
224 225 226 227 228 229 230 231
	git_reference_free(looked_up_ref);

	/* And that the previous one doesn't exist any longer */
	cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, packed_head_name));
}

void test_refs_rename__force_loose(void)
{
232
	// can force-rename a loose reference with the name of an existing loose reference
233
	git_reference *looked_up_ref, *renamed_ref;
Ben Straub committed
234 235 236 237
	git_oid oid;

	/* An existing reference... */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/br2"));
238
	git_oid_cpy(&oid, git_reference_target(looked_up_ref));
Ben Straub committed
239 240

	/* Can be force-renamed to the name of another existing reference. */
241
	cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, "refs/heads/test", 1, NULL, NULL));
Ben Straub committed
242
	git_reference_free(looked_up_ref);
243
	git_reference_free(renamed_ref);
Ben Straub committed
244 245 246

	/* Check we actually renamed it */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/test"));
Vicent Martí committed
247
	cl_assert_equal_s(looked_up_ref->name,  "refs/heads/test");
248
	cl_assert(!git_oid_cmp(&oid, git_reference_target(looked_up_ref)));
Ben Straub committed
249 250 251 252 253 254 255 256 257 258 259
	git_reference_free(looked_up_ref);

	/* And that the previous one doesn't exist any longer */
	cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, "refs/heads/br2"));

	git_reference_free(looked_up_ref);
}


void test_refs_rename__overwrite(void)
{
260
	// can not overwrite name of existing reference
Ben Straub committed
261
	git_reference *ref, *ref_one, *ref_one_new, *ref_two;
262
	git_refdb *refdb;
Ben Straub committed
263 264 265 266 267
	git_oid id;

	cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
	cl_assert(git_reference_type(ref) & GIT_REF_OID);

268
	git_oid_cpy(&id, git_reference_target(ref));
Ben Straub committed
269 270

	/* Create loose references */
271 272
	cl_git_pass(git_reference_create(&ref_one, g_repo, ref_one_name, &id, 0, NULL, NULL));
	cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name, &id, 0, NULL, NULL));
Ben Straub committed
273 274

	/* Pack everything */
275 276
	cl_git_pass(git_repository_refdb(&refdb, g_repo));
	cl_git_pass(git_refdb_compress(refdb));
Ben Straub committed
277 278

	/* Attempt to create illegal reference */
279
	cl_git_fail(git_reference_create(&ref_one_new, g_repo, ref_one_name_new, &id, 0, NULL, NULL));
Ben Straub committed
280 281 282 283 284 285 286 287

	/* Illegal reference couldn't be created so this is supposed to fail */
	cl_git_fail(git_reference_lookup(&ref_one_new, g_repo, ref_one_name_new));

	git_reference_free(ref);
	git_reference_free(ref_one);
	git_reference_free(ref_one_new);
	git_reference_free(ref_two);
288
	git_refdb_free(refdb);
Ben Straub committed
289 290 291 292 293
}


void test_refs_rename__prefix(void)
{
294
	// can be renamed to a new name prefixed with the old name
295
	git_reference *ref, *ref_two, *looked_up_ref, *renamed_ref;
Ben Straub committed
296 297 298 299 300
	git_oid id;

	cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
	cl_assert(git_reference_type(ref) & GIT_REF_OID);

301
	git_oid_cpy(&id, git_reference_target(ref));
Ben Straub committed
302 303

	/* Create loose references */
304
	cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name, &id, 0, NULL, NULL));
Ben Straub committed
305 306 307 308 309

	/* An existing reference... */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name));

	/* Can be rename to a new name starting with the old name. */
310
	cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, ref_two_name_new, 0, NULL, NULL));
Ben Straub committed
311
	git_reference_free(looked_up_ref);
312
	git_reference_free(renamed_ref);
Ben Straub committed
313 314 315

	/* Check we actually renamed it */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new));
Vicent Martí committed
316
	cl_assert_equal_s(looked_up_ref->name, ref_two_name_new);
Ben Straub committed
317 318 319 320 321 322 323 324 325 326
	git_reference_free(looked_up_ref);
	cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name));

	git_reference_free(ref);
	git_reference_free(ref_two);
	git_reference_free(looked_up_ref);
}

void test_refs_rename__move_up(void)
{
327
	// can move a reference to a upper reference hierarchy
328
	git_reference *ref, *ref_two, *looked_up_ref, *renamed_ref;
329
	git_oid id;
Ben Straub committed
330

331 332
	cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
	cl_assert(git_reference_type(ref) & GIT_REF_OID);
Ben Straub committed
333

334
	git_oid_cpy(&id, git_reference_target(ref));
Ben Straub committed
335

336
	/* Create loose references */
337
	cl_git_pass(git_reference_create(&ref_two, g_repo, ref_two_name_new, &id, 0, NULL, NULL));
338
	git_reference_free(ref_two);
Ben Straub committed
339

340 341
	/* An existing reference... */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new));
Ben Straub committed
342

343
	/* Can be renamed upward the reference tree. */
344
	cl_git_pass(git_reference_rename(&renamed_ref, looked_up_ref, ref_two_name, 0, NULL, NULL));
345
	git_reference_free(looked_up_ref);
346
	git_reference_free(renamed_ref);
Ben Straub committed
347

348 349 350 351
	/* Check we actually renamed it */
	cl_git_pass(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name));
	cl_assert_equal_s(looked_up_ref->name, ref_two_name);
	git_reference_free(looked_up_ref);
352

353 354 355
	cl_git_fail(git_reference_lookup(&looked_up_ref, g_repo, ref_two_name_new));
	git_reference_free(ref);
	git_reference_free(looked_up_ref);
Ben Straub committed
356
}
357 358 359

void test_refs_rename__propagate_eexists(void)
{
360
	git_reference *ref, *new_ref;
361 362 363

	cl_git_pass(git_reference_lookup(&ref, g_repo, packed_head_name));

364
	cl_assert_equal_i(GIT_EEXISTS, git_reference_rename(&new_ref, ref, packed_test_head_name, 0, NULL, NULL));
365 366 367

	git_reference_free(ref);
}
368 369 370 371 372 373

void test_refs_rename__writes_to_reflog(void)
{
	git_reference *ref, *new_ref;
	git_reflog *log;
	const git_reflog_entry *entry;
374 375 376
	git_signature *sig;

	cl_git_pass(git_signature_now(&sig, "me", "foo@example.com"));
377 378 379

	cl_git_pass(git_reference_lookup(&ref, g_repo, ref_master_name));
	cl_git_pass(git_reference_rename(&new_ref, ref, ref_one_name_new, false,
380
				sig, "message"));
381 382 383
	cl_git_pass(git_reflog_read(&log, g_repo, git_reference_name(new_ref)));
	entry = git_reflog_entry_byindex(log, 0);
	cl_assert_equal_s("message", git_reflog_entry_message(entry));
384
	cl_assert_equal_s("foo@example.com", git_reflog_entry_committer(entry)->email);
385 386 387 388

	git_reflog_free(log);
	git_reference_free(ref);
	git_reference_free(new_ref);
389
	git_signature_free(sig);
390
}