reflog.c 9.81 KB
Newer Older
Ben Straub committed
1 2
#include "clar_libgit2.h"

3
#include "fileops.h"
Ben Straub committed
4 5 6 7 8 9
#include "git2/reflog.h"
#include "reflog.h"


static const char *new_ref = "refs/heads/test-reflog";
static const char *current_master_tip = "a65fedf39aefe402d3bb6e24df4d4f5fe4547750";
10
#define commit_msg "commit: bla bla"
Ben Straub committed
11 12 13 14 15

static git_repository *g_repo;


// helpers
16
static void assert_signature(const git_signature *expected, const git_signature *actual)
Ben Straub committed
17
{
18
	cl_assert(actual);
Vicent Martí committed
19 20
	cl_assert_equal_s(expected->name, actual->name);
	cl_assert_equal_s(expected->email, actual->email);
21 22
	cl_assert(expected->when.offset == actual->when.offset);
	cl_assert(expected->when.time == actual->when.time);
Ben Straub committed
23 24 25 26
}


// Fixture setup and teardown
27
void test_refs_reflog_reflog__initialize(void)
Ben Straub committed
28
{
29
   g_repo = cl_git_sandbox_init("testrepo.git");
Ben Straub committed
30 31
}

32
void test_refs_reflog_reflog__cleanup(void)
Ben Straub committed
33 34 35 36
{
   cl_git_sandbox_cleanup();
}

37
static void assert_appends(const git_signature *committer, const git_oid *oid)
Ben Straub committed
38
{
39
	git_repository *repo2;
40
	git_reference *lookedup_ref;
Ben Straub committed
41
	git_reflog *reflog;
42
	const git_reflog_entry *entry;
Ben Straub committed
43 44

	/* Reopen a new instance of the repository */
45
	cl_git_pass(git_repository_open(&repo2, "testrepo.git"));
Ben Straub committed
46

47
	/* Lookup the previously created branch */
Ben Straub committed
48 49 50
	cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref));

	/* Read and parse the reflog for this branch */
51
	cl_git_pass(git_reflog_read(&reflog, repo2, new_ref));
52 53 54 55 56
	cl_assert_equal_i(3, (int)git_reflog_entrycount(reflog));

	/* The first one was the creation of the branch */
	entry = git_reflog_entry_byindex(reflog, 2);
	cl_assert(git_oid_streq(&entry->oid_old, GIT_OID_HEX_ZERO) == 0);
Ben Straub committed
57

58
	entry = git_reflog_entry_byindex(reflog, 1);
59
	assert_signature(committer, entry->committer);
60
	cl_assert(git_oid_cmp(oid, &entry->oid_old) == 0);
61
	cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0);
Ben Straub committed
62 63
	cl_assert(entry->msg == NULL);

64
	entry = git_reflog_entry_byindex(reflog, 0);
65
	assert_signature(committer, entry->committer);
66
	cl_assert(git_oid_cmp(oid, &entry->oid_cur) == 0);
Vicent Martí committed
67
	cl_assert_equal_s(commit_msg, entry->msg);
Ben Straub committed
68 69 70 71 72 73 74

	git_reflog_free(reflog);
	git_repository_free(repo2);

	git_reference_free(lookedup_ref);
}

75 76 77 78 79 80 81 82 83 84
void test_refs_reflog_reflog__append_then_read(void)
{
	/* write a reflog for a given reference and ensure it can be read back */
	git_reference *ref;
	git_oid oid;
	git_signature *committer;
	git_reflog *reflog;

	/* Create a new branch pointing at the HEAD */
	git_oid_fromstr(&oid, current_master_tip);
85
	cl_git_pass(git_reference_create(&ref, g_repo, new_ref, &oid, 0, NULL));
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	git_reference_free(ref);

	cl_git_pass(git_signature_now(&committer, "foo", "foo@bar"));

	cl_git_pass(git_reflog_read(&reflog, g_repo, new_ref));

	cl_git_fail(git_reflog_append(reflog, &oid, committer, "no inner\nnewline"));
	cl_git_pass(git_reflog_append(reflog, &oid, committer, NULL));
	cl_git_pass(git_reflog_append(reflog, &oid, committer, commit_msg "\n"));
	cl_git_pass(git_reflog_write(reflog));
	git_reflog_free(reflog);

	assert_appends(committer, &oid);

	git_signature_free(committer);
}

103
void test_refs_reflog_reflog__renaming_the_reference_moves_the_reflog(void)
104
{
105
	git_reference *master, *new_master;
106 107 108 109 110 111 112 113 114 115 116
	git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT;

	git_buf_joinpath(&master_log_path, git_repository_path(g_repo), GIT_REFLOG_DIR);
	git_buf_puts(&moved_log_path, git_buf_cstr(&master_log_path));
	git_buf_joinpath(&master_log_path, git_buf_cstr(&master_log_path), "refs/heads/master");
	git_buf_joinpath(&moved_log_path, git_buf_cstr(&moved_log_path), "refs/moved");

	cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&master_log_path)));
	cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&moved_log_path)));

	cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
117
	cl_git_pass(git_reference_rename(&new_master, master, "refs/moved", 0, NULL));
118
	git_reference_free(master);
119 120 121 122

	cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&master_log_path)));
	cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&moved_log_path)));

123
	git_reference_free(new_master);
124 125 126
	git_buf_free(&moved_log_path);
	git_buf_free(&master_log_path);
}
127

128 129
static void assert_has_reflog(bool expected_result, const char *name)
{
130
	cl_assert_equal_i(expected_result, git_reference_has_log(g_repo, name));
131 132
}

133
void test_refs_reflog_reflog__reference_has_reflog(void)
134 135 136 137 138
{
	assert_has_reflog(true, "HEAD");
	assert_has_reflog(true, "refs/heads/master");
	assert_has_reflog(false, "refs/heads/subtrees");
}
139 140 141 142

void test_refs_reflog_reflog__reading_the_reflog_from_a_reference_with_no_log_returns_an_empty_one(void)
{
	git_reflog *reflog;
143
	const char *refname = "refs/heads/subtrees";
144 145
	git_buf subtrees_log_path = GIT_BUF_INIT;

146
	git_buf_join_n(&subtrees_log_path, '/', 3, git_repository_path(g_repo), GIT_REFLOG_DIR, refname);
147 148
	cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&subtrees_log_path)));

149
	cl_git_pass(git_reflog_read(&reflog, g_repo, refname));
150

151
	cl_assert_equal_i(0, (int)git_reflog_entrycount(reflog));
152 153 154 155

	git_reflog_free(reflog);
	git_buf_free(&subtrees_log_path);
}
156 157 158

void test_refs_reflog_reflog__cannot_write_a_moved_reflog(void)
{
159
	git_reference *master, *new_master;
160 161 162 163
	git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT;
	git_reflog *reflog;

	cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master"));
164
	cl_git_pass(git_reflog_read(&reflog, g_repo, "refs/heads/master"));
165 166

	cl_git_pass(git_reflog_write(reflog));
167

168
	cl_git_pass(git_reference_rename(&new_master, master, "refs/moved", 0, NULL));
169
	git_reference_free(master);
170 171 172 173

	cl_git_fail(git_reflog_write(reflog));

	git_reflog_free(reflog);
174
	git_reference_free(new_master);
175 176 177
	git_buf_free(&moved_log_path);
	git_buf_free(&master_log_path);
}
178 179 180 181

void test_refs_reflog_reflog__renaming_with_an_invalid_name_returns_EINVALIDSPEC(void)
{
	cl_assert_equal_i(GIT_EINVALIDSPEC,
182
			  git_reflog_rename(g_repo, "refs/heads/master", "refs/heads/Inv@{id"));
183
}
184 185 186 187 188 189 190 191

void test_refs_reflog_reflog__write_only_std_locations(void)
{
	git_reference *ref;
	git_oid id;

	git_oid_fromstr(&id, current_master_tip);

192
	cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/foo", &id, 1, NULL));
193
	git_reference_free(ref);
194
	cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1, NULL));
195
	git_reference_free(ref);
196
	cl_git_pass(git_reference_create(&ref, g_repo, "refs/notes/foo", &id, 1, NULL));
197 198 199 200 201 202 203 204 205 206 207 208 209 210
	git_reference_free(ref);

	assert_has_reflog(true, "refs/heads/foo");
	assert_has_reflog(false, "refs/tags/foo");
	assert_has_reflog(true, "refs/notes/foo");

}

void test_refs_reflog_reflog__write_when_explicitly_active(void)
{
	git_reference *ref;
	git_oid id;

	git_oid_fromstr(&id, current_master_tip);
211
	git_reference_ensure_log(g_repo, "refs/tags/foo");
212

213
	cl_git_pass(git_reference_create(&ref, g_repo, "refs/tags/foo", &id, 1, NULL));
214 215 216
	git_reference_free(ref);
	assert_has_reflog(true, "refs/tags/foo");
}
217 218 219 220 221 222 223 224 225 226 227 228 229 230

void test_refs_reflog_reflog__append_to_HEAD_when_changing_current_branch(void)
{
	size_t nlogs, nlogs_after;
	git_reference *ref;
	git_reflog *log;
	git_oid id;

	cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
	nlogs = git_reflog_entrycount(log);
	git_reflog_free(log);

	/* Move it back */
	git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
231
	cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/master", &id, 1, NULL));
232 233 234 235 236 237 238 239
	git_reference_free(ref);

	cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
	nlogs_after = git_reflog_entrycount(log);
	git_reflog_free(log);

	cl_assert_equal_i(nlogs_after, nlogs + 1);
}
240 241 242 243 244 245 246 247 248 249 250 251 252

void test_refs_reflog_reflog__do_not_append_when_no_update(void)
{
	size_t nlogs, nlogs_after;
	git_reference *ref, *ref2;
	git_reflog *log;

	cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
	nlogs = git_reflog_entrycount(log);
	git_reflog_free(log);

	cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master"));
	cl_git_pass(git_reference_create(&ref2, g_repo, "refs/heads/master",
253
					 git_reference_target(ref), 1, NULL));
254 255 256 257 258 259 260 261 262 263

	git_reference_free(ref);
	git_reference_free(ref2);

	cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
	nlogs_after = git_reflog_entrycount(log);
	git_reflog_free(log);

	cl_assert_equal_i(nlogs_after, nlogs);
}
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282

static void assert_no_reflog_update(void)
{
	size_t nlogs, nlogs_after;
	size_t nlogs_master, nlogs_master_after;
	git_reference *ref;
	git_reflog *log;
	git_oid id;

	cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
	nlogs = git_reflog_entrycount(log);
	git_reflog_free(log);

	cl_git_pass(git_reflog_read(&log, g_repo, "refs/heads/master"));
	nlogs_master = git_reflog_entrycount(log);
	git_reflog_free(log);

	/* Move it back */
	git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
283
	cl_git_pass(git_reference_create(&ref, g_repo, "refs/heads/master", &id, 1, NULL));
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
	git_reference_free(ref);

	cl_git_pass(git_reflog_read(&log, g_repo, "HEAD"));
	nlogs_after = git_reflog_entrycount(log);
	git_reflog_free(log);

	cl_assert_equal_i(nlogs_after, nlogs);

	cl_git_pass(git_reflog_read(&log, g_repo, "refs/heads/master"));
	nlogs_master_after = git_reflog_entrycount(log);
	git_reflog_free(log);

	cl_assert_equal_i(nlogs_after, nlogs);
	cl_assert_equal_i(nlogs_master_after, nlogs_master);

}

void test_refs_reflog_reflog__logallrefupdates_bare_set_false(void)
{
	git_config *config;

	cl_git_pass(git_repository_config(&config, g_repo));
	cl_git_pass(git_config_set_bool(config, "core.logallrefupdates", false));
	git_config_free(config);

	assert_no_reflog_update();
}

void test_refs_reflog_reflog__logallrefupdates_bare_unset(void)
{
	git_config *config;

	cl_git_pass(git_repository_config(&config, g_repo));
	cl_git_pass(git_config_delete_entry(config, "core.logallrefupdates"));
	git_config_free(config);

	assert_no_reflog_update();
}

void test_refs_reflog_reflog__logallrefupdates_nonbare_set_false(void)
{
	git_config *config;

	cl_git_sandbox_cleanup();
	g_repo = cl_git_sandbox_init("testrepo");


	cl_git_pass(git_repository_config(&config, g_repo));
	cl_git_pass(git_config_set_bool(config, "core.logallrefupdates", false));
	git_config_free(config);

	assert_no_reflog_update();
}