apply.c 14.1 KB
Newer Older
1
#include "clar_libgit2.h"
2
#include "futils.h"
3 4 5 6 7 8 9 10 11 12
#include "stash_helpers.h"

static git_signature *signature;
static git_repository *repo;
static git_index *repo_index;

void test_stash_apply__initialize(void)
{
	git_oid oid;

13
	repo = cl_git_sandbox_init_new("stash");
14
	cl_git_pass(git_repository_index(&repo_index, repo));
15
	cl_git_pass(git_signature_new(&signature, "nulltoken", "emeric.fermas@gmail.com", 1323847743, 60)); /* Wed Dec 14 08:29:03 2011 +0100 */
16 17 18 19

	cl_git_mkfile("stash/what", "hello\n");
	cl_git_mkfile("stash/how", "small\n");
	cl_git_mkfile("stash/who", "world\n");
20
	cl_git_mkfile("stash/where", "meh\n");
21 22 23 24 25 26 27 28 29 30

	cl_git_pass(git_index_add_bypath(repo_index, "what"));
	cl_git_pass(git_index_add_bypath(repo_index, "how"));
	cl_git_pass(git_index_add_bypath(repo_index, "who"));

	cl_repo_commit_from_index(NULL, repo, signature, 0, "Initial commit");

	cl_git_rewritefile("stash/what", "goodbye\n");
	cl_git_rewritefile("stash/who", "funky world\n");
	cl_git_mkfile("stash/when", "tomorrow\n");
31
	cl_git_mkfile("stash/why", "would anybody use stash?\n");
32
	cl_git_mkfile("stash/where", "????\n");
33 34

	cl_git_pass(git_index_add_bypath(repo_index, "who"));
35
	cl_git_pass(git_index_add_bypath(repo_index, "why"));
36
	cl_git_pass(git_index_add_bypath(repo_index, "where"));
37
	cl_git_pass(git_index_write(repo_index));
38 39

	cl_git_rewritefile("stash/where", "....\n");
40 41 42 43 44 45

	/* Pre-stash state */
	assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
46
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
47
	assert_status(repo, "where", GIT_STATUS_INDEX_NEW|GIT_STATUS_WT_MODIFIED);
48 49 50 51 52 53 54 55

	cl_git_pass(git_stash_save(&oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));

	/* Post-stash state */
	assert_status(repo, "what", GIT_STATUS_CURRENT);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_CURRENT);
	assert_status(repo, "when", GIT_ENOTFOUND);
56
	assert_status(repo, "why", GIT_ENOTFOUND);
57
	assert_status(repo, "where", GIT_ENOTFOUND);
58 59 60 61 62 63 64 65 66 67
}

void test_stash_apply__cleanup(void)
{
	git_signature_free(signature);
	signature = NULL;

	git_index_free(repo_index);
	repo_index = NULL;

68
	cl_git_sandbox_cleanup();
69 70 71 72
}

void test_stash_apply__with_default(void)
{
73
	git_str where = GIT_STR_INIT;
74

75
	cl_git_pass(git_stash_apply(repo, 0, NULL));
76 77 78 79 80 81

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
82 83 84 85 86 87
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
	assert_status(repo, "where", GIT_STATUS_INDEX_NEW);

	cl_git_pass(git_futils_readbuffer(&where, "stash/where"));
	cl_assert_equal_s("....\n", where.ptr);

88
	git_str_dispose(&where);
89 90 91 92 93 94 95 96 97 98
}

void test_stash_apply__with_existing_file(void)
{
	cl_git_mkfile("stash/where", "oops!\n");
	cl_git_fail(git_stash_apply(repo, 0, NULL));
}

void test_stash_apply__merges_new_file(void)
{
99
	const git_index_entry *ancestor, *our, *their;
100 101 102 103 104 105 106 107 108 109 110 111 112

	cl_git_mkfile("stash/where", "committed before stash\n");
	cl_git_pass(git_index_add_bypath(repo_index, "where"));
	cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit");

	cl_git_pass(git_stash_apply(repo, 0, NULL));

	cl_assert_equal_i(1, git_index_has_conflicts(repo_index));
	assert_status(repo, "what", GIT_STATUS_INDEX_MODIFIED);
	cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "where")); /* unmerged */
	assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
113 114 115 116
}

void test_stash_apply__with_reinstate_index(void)
{
117
	git_str where = GIT_STR_INIT;
118 119 120 121 122
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;

	opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX;

	cl_git_pass(git_stash_apply(repo, 0, &opts));
123 124 125 126 127 128

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
129
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
130 131 132 133 134
	assert_status(repo, "where", GIT_STATUS_INDEX_NEW | GIT_STATUS_WT_MODIFIED);

	cl_git_pass(git_futils_readbuffer(&where, "stash/where"));
	cl_assert_equal_s("....\n", where.ptr);

135
	git_str_dispose(&where);
136 137 138 139 140 141 142 143 144 145 146
}

void test_stash_apply__conflict_index_with_default(void)
{
	const git_index_entry *ancestor;
	const git_index_entry *our;
	const git_index_entry *their;

	cl_git_rewritefile("stash/who", "nothing\n");
	cl_git_pass(git_index_add_bypath(repo_index, "who"));
	cl_git_pass(git_index_write(repo_index));
147
	cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit");
148

149
	cl_git_pass(git_stash_apply(repo, 0, NULL));
150 151 152 153 154 155

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 1);
	assert_status(repo, "what", GIT_STATUS_INDEX_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "who")); /* unmerged */
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
156
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
157 158 159 160
}

void test_stash_apply__conflict_index_with_reinstate_index(void)
{
161 162 163 164
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;

	opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX;

165 166 167
	cl_git_rewritefile("stash/who", "nothing\n");
	cl_git_pass(git_index_add_bypath(repo_index, "who"));
	cl_git_pass(git_index_write(repo_index));
168
	cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit");
169

170
	cl_git_fail_with(git_stash_apply(repo, 0, &opts), GIT_ECONFLICT);
171 172 173 174

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_CURRENT);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
175
	assert_status(repo, "who", GIT_STATUS_CURRENT);
176
	assert_status(repo, "when", GIT_ENOTFOUND);
177
	assert_status(repo, "why", GIT_ENOTFOUND);
178 179 180 181
}

void test_stash_apply__conflict_untracked_with_default(void)
{
182 183
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;

184 185
	cl_git_mkfile("stash/when", "nothing\n");

186
	cl_git_fail_with(git_stash_apply(repo, 0, &opts), GIT_ECONFLICT);
187 188 189 190 191 192

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_CURRENT);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_CURRENT);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
193
	assert_status(repo, "why", GIT_ENOTFOUND);
194 195 196 197
}

void test_stash_apply__conflict_untracked_with_reinstate_index(void)
{
198 199 200 201
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;

	opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX;

202 203
	cl_git_mkfile("stash/when", "nothing\n");

204
	cl_git_fail_with(git_stash_apply(repo, 0, &opts), GIT_ECONFLICT);
205 206 207 208 209 210

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_CURRENT);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_CURRENT);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
211
	assert_status(repo, "why", GIT_ENOTFOUND);
212 213 214 215 216 217
}

void test_stash_apply__conflict_workdir_with_default(void)
{
	cl_git_rewritefile("stash/what", "ciao\n");

218
	cl_git_fail_with(git_stash_apply(repo, 0, NULL), GIT_ECONFLICT);
219 220 221 222 223 224

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_CURRENT);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
225
	assert_status(repo, "why", GIT_ENOTFOUND);
226 227 228 229
}

void test_stash_apply__conflict_workdir_with_reinstate_index(void)
{
230 231 232 233
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;

	opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX;

234 235
	cl_git_rewritefile("stash/what", "ciao\n");

236
	cl_git_fail_with(git_stash_apply(repo, 0, &opts), GIT_ECONFLICT);
237 238 239 240 241 242

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_CURRENT);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
243
	assert_status(repo, "why", GIT_ENOTFOUND);
244 245 246 247 248 249 250 251 252 253 254 255
}

void test_stash_apply__conflict_commit_with_default(void)
{
	const git_index_entry *ancestor;
	const git_index_entry *our;
	const git_index_entry *their;

	cl_git_rewritefile("stash/what", "ciao\n");
	cl_git_pass(git_index_add_bypath(repo_index, "what"));
	cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit");

256
	cl_git_pass(git_stash_apply(repo, 0, NULL));
257 258 259 260 261 262

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 1);
	cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "what")); /* unmerged */
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
263
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
264 265 266 267
}

void test_stash_apply__conflict_commit_with_reinstate_index(void)
{
268
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;
269 270 271 272
	const git_index_entry *ancestor;
	const git_index_entry *our;
	const git_index_entry *their;

273 274
	opts.flags = GIT_STASH_APPLY_REINSTATE_INDEX;

275 276 277 278
	cl_git_rewritefile("stash/what", "ciao\n");
	cl_git_pass(git_index_add_bypath(repo_index, "what"));
	cl_repo_commit_from_index(NULL, repo, signature, 0, "Other commit");

279
	cl_git_pass(git_stash_apply(repo, 0, &opts));
280 281 282 283 284 285

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 1);
	cl_git_pass(git_index_conflict_get(&ancestor, &our, &their, repo_index, "what")); /* unmerged */
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
286
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
287 288
}

289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
void test_stash_apply__fails_with_uncommitted_changes_in_index(void)
{
	cl_git_rewritefile("stash/who", "nothing\n");
	cl_git_pass(git_index_add_bypath(repo_index, "who"));
	cl_git_pass(git_index_write(repo_index));

	cl_git_fail_with(git_stash_apply(repo, 0, NULL), GIT_EUNCOMMITTED);

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_CURRENT);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_INDEX_MODIFIED);
	assert_status(repo, "when", GIT_ENOTFOUND);
	assert_status(repo, "why", GIT_ENOTFOUND);
}

305 306
void test_stash_apply__pop(void)
{
307
	cl_git_pass(git_stash_pop(repo, 0, NULL));
308

309
	cl_git_fail_with(git_stash_pop(repo, 0, NULL), GIT_ENOTFOUND);
310
}
311 312 313 314 315 316 317 318

struct seen_paths {
	bool what;
	bool how;
	bool who;
	bool when;
};

319
static int checkout_notify(
320 321 322 323 324 325 326 327 328
	git_checkout_notify_t why,
	const char *path,
	const git_diff_file *baseline,
	const git_diff_file *target,
	const git_diff_file *workdir,
	void *payload)
{
	struct seen_paths *seen_paths = (struct seen_paths *)payload;

329 330 331 332 333
	GIT_UNUSED(why);
	GIT_UNUSED(baseline);
	GIT_UNUSED(target);
	GIT_UNUSED(workdir);

334 335 336 337 338 339 340 341 342 343 344 345 346 347
	if (strcmp(path, "what") == 0)
		seen_paths->what = 1;
	else if (strcmp(path, "how") == 0)
		seen_paths->how = 1;
	else if (strcmp(path, "who") == 0)
		seen_paths->who = 1;
	else if (strcmp(path, "when") == 0)
		seen_paths->when = 1;

	return 0;
}

void test_stash_apply__executes_notify_cb(void)
{
348
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;
349 350
	struct seen_paths seen_paths = {0};

351 352 353
	opts.checkout_options.notify_cb = checkout_notify;
	opts.checkout_options.notify_flags = GIT_CHECKOUT_NOTIFY_ALL;
	opts.checkout_options.notify_payload = &seen_paths;
354

355
	cl_git_pass(git_stash_apply(repo, 0, &opts));
356 357 358 359 360 361

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
362 363
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
	assert_status(repo, "where", GIT_STATUS_INDEX_NEW);
364 365 366 367 368 369

	cl_assert_equal_b(true, seen_paths.what);
	cl_assert_equal_b(false, seen_paths.how);
	cl_assert_equal_b(true, seen_paths.who);
	cl_assert_equal_b(true, seen_paths.when);
}
370

371
static int progress_cb(
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
	git_stash_apply_progress_t progress,
	void *payload)
{
	git_stash_apply_progress_t *p = (git_stash_apply_progress_t *)payload;

	cl_assert_equal_i((*p)+1, progress);

	*p = progress;

	return 0;
}

void test_stash_apply__calls_progress_cb(void)
{
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;
	git_stash_apply_progress_t progress = GIT_STASH_APPLY_PROGRESS_NONE;

	opts.progress_cb = progress_cb;
	opts.progress_payload = &progress;

	cl_git_pass(git_stash_apply(repo, 0, &opts));
	cl_assert_equal_i(progress, GIT_STASH_APPLY_PROGRESS_DONE);
}

396
static int aborting_progress_cb(
397 398 399
	git_stash_apply_progress_t progress,
	void *payload)
{
400 401
	GIT_UNUSED(payload);

402 403 404 405 406 407 408 409 410 411 412 413 414 415
	if (progress == GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED)
		return -44;

	return 0;
}

void test_stash_apply__progress_cb_can_abort(void)
{
	git_stash_apply_options opts = GIT_STASH_APPLY_OPTIONS_INIT;

	opts.progress_cb = aborting_progress_cb;

	cl_git_fail_with(-44, git_stash_apply(repo, 0, &opts));
}
416 417 418 419 420 421 422 423 424

void test_stash_apply__uses_reflog_like_indices_1(void)
{
	git_oid oid;

	cl_git_mkfile("stash/untracked", "untracked\n");
	cl_git_pass(git_stash_save(&oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));
	assert_status(repo, "untracked", GIT_ENOTFOUND);

425
	/* stash@{1} is the oldest (first) stash we made */
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
	cl_git_pass(git_stash_apply(repo, 1, NULL));
	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "what", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "how", GIT_STATUS_CURRENT);
	assert_status(repo, "who", GIT_STATUS_WT_MODIFIED);
	assert_status(repo, "when", GIT_STATUS_WT_NEW);
	assert_status(repo, "why", GIT_STATUS_INDEX_NEW);
	assert_status(repo, "where", GIT_STATUS_INDEX_NEW);
}

void test_stash_apply__uses_reflog_like_indices_2(void)
{
	git_oid oid;

	cl_git_mkfile("stash/untracked", "untracked\n");
	cl_git_pass(git_stash_save(&oid, repo, signature, NULL, GIT_STASH_INCLUDE_UNTRACKED));
	assert_status(repo, "untracked", GIT_ENOTFOUND);

444
	/* stash@{0} is the newest stash we made immediately above */
445 446 447 448 449
	cl_git_pass(git_stash_apply(repo, 0, NULL));

	cl_assert_equal_i(git_index_has_conflicts(repo_index), 0);
	assert_status(repo, "untracked", GIT_STATUS_WT_NEW);
}