status.c 12.1 KB
Newer Older
Russell Belfer committed
1 2 3 4
#include "clar_libgit2.h"
#include "posix.h"
#include "path.h"
#include "submodule_helpers.h"
5
#include "fileops.h"
6
#include "iterator.h"
Russell Belfer committed
7 8 9 10 11

static git_repository *g_repo = NULL;

void test_submodule_status__initialize(void)
{
12
	g_repo = setup_fixture_submod2();
Russell Belfer committed
13 14 15 16 17 18 19 20
}

void test_submodule_status__cleanup(void)
{
}

void test_submodule_status__unchanged(void)
{
21 22 23
	unsigned int status = get_submodule_status(g_repo, "sm_unchanged");
	unsigned int expected =
		GIT_SUBMODULE_STATUS_IN_HEAD |
24 25 26 27
		GIT_SUBMODULE_STATUS_IN_INDEX |
		GIT_SUBMODULE_STATUS_IN_CONFIG |
		GIT_SUBMODULE_STATUS_IN_WD;

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
	cl_assert(expected == status);
}

static void rm_submodule(const char *name)
{
	git_buf path = GIT_BUF_INIT;
	cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), name));
	cl_git_pass(git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES));
	git_buf_free(&path);
}

static void add_submodule_to_index(const char *name)
{
	git_submodule *sm;
	cl_git_pass(git_submodule_lookup(&sm, g_repo, name));
	cl_git_pass(git_submodule_add_to_index(sm, true));
	git_submodule_free(sm);
}

static void rm_submodule_from_index(const char *name)
{
	git_index *index;
	size_t pos;

	cl_git_pass(git_repository_index(&index, g_repo));
	cl_assert(!git_index_find(&pos, index, name));
	cl_git_pass(git_index_remove(index, name, 0));
	cl_git_pass(git_index_write(index));
	git_index_free(index);
Russell Belfer committed
58 59
}

60 61 62
/* 4 values of GIT_SUBMODULE_IGNORE to check */

void test_submodule_status__ignore_none(void)
Russell Belfer committed
63
{
64 65
	unsigned int status;

66
	rm_submodule("sm_unchanged");
67

68 69 70
	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
71

72
	status = get_submodule_status(g_repo, "sm_changed_index");
73 74
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);

75
	status = get_submodule_status(g_repo, "sm_changed_head");
76 77
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);

78
	status = get_submodule_status(g_repo, "sm_changed_file");
79 80
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);

81
	status = get_submodule_status(g_repo, "sm_changed_untracked_file");
82 83
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNTRACKED) != 0);

84
	status = get_submodule_status(g_repo, "sm_missing_commits");
85 86
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);

87
	status = get_submodule_status(g_repo, "sm_added_and_uncommited");
88 89 90
	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);

	/* removed sm_unchanged for deleted workdir */
91
	status = get_submodule_status(g_repo, "sm_unchanged");
92 93 94
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);

	/* now mkdir sm_unchanged to test uninitialized */
95
	cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
96
	status = get_submodule_status(g_repo, "sm_unchanged");
97 98 99
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);

	/* update sm_changed_head in index */
100 101
	add_submodule_to_index("sm_changed_head");
	status = get_submodule_status(g_repo, "sm_changed_head");
102 103 104
	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);

	/* remove sm_changed_head from index */
105 106
	rm_submodule_from_index("sm_changed_head");
	status = get_submodule_status(g_repo, "sm_changed_head");
107
	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_DELETED) != 0);
Russell Belfer committed
108 109
}

110 111 112 113 114
void test_submodule_status__ignore_untracked(void)
{
	unsigned int status;
	git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_UNTRACKED;

115
	rm_submodule("sm_unchanged");
116

117 118 119
	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
120

121
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign));
122 123
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) != 0);

124
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
125 126
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);

127
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign));
128 129
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) != 0);

130
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign));
131 132
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

133
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign));
134 135
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);

136
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign));
137 138 139
	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);

	/* removed sm_unchanged for deleted workdir */
140
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
141 142 143
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);

	/* now mkdir sm_unchanged to test uninitialized */
144
	cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
145
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
146 147 148
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);

	/* update sm_changed_head in index */
149
	add_submodule_to_index("sm_changed_head");
150
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
151 152 153 154 155 156 157 158
	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
}

void test_submodule_status__ignore_dirty(void)
{
	unsigned int status;
	git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_DIRTY;

159
	rm_submodule("sm_unchanged");
160

161 162 163
	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
164

165
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign));
166 167
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

168
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
169 170
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);

171
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign));
172 173
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

174
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign));
175 176
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

177
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign));
178 179
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_MODIFIED) != 0);

180
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign));
181 182 183
	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_ADDED) != 0);

	/* removed sm_unchanged for deleted workdir */
184
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
185 186 187
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_DELETED) != 0);

	/* now mkdir sm_unchanged to test uninitialized */
188
	cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
189
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
190 191 192
	cl_assert((status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) != 0);

	/* update sm_changed_head in index */
193
	add_submodule_to_index("sm_changed_head");
194
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
195 196 197 198 199 200 201 202
	cl_assert((status & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) != 0);
}

void test_submodule_status__ignore_all(void)
{
	unsigned int status;
	git_submodule_ignore_t ign = GIT_SUBMODULE_IGNORE_ALL;

203
	rm_submodule("sm_unchanged");
204

205 206 207
	refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
	refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
	refute_submodule_exists(g_repo, "not", GIT_EEXISTS);
208

209
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_index", ign));
210 211
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

212
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
213 214
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

215
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_file", ign));
216 217
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

218
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_untracked_file", ign));
219 220
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

221
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_missing_commits", ign));
222 223
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

224
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_added_and_uncommited", ign));
225 226 227
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

	/* removed sm_unchanged for deleted workdir */
228
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
229 230 231
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

	/* now mkdir sm_unchanged to test uninitialized */
232
	cl_git_pass(git_futils_mkdir_relative("sm_unchanged", "submod2", 0755, 0, NULL));
233
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_unchanged", ign));
234 235 236
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

	/* update sm_changed_head in index */
237
	add_submodule_to_index("sm_changed_head");
238
	cl_git_pass(git_submodule_status(&status, g_repo,"sm_changed_head", ign));
239 240
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));
}
241 242 243 244

typedef struct {
	size_t counter;
	const char **paths;
245
	int *statuses;
246 247 248 249 250 251 252
} submodule_expectations;

static int confirm_submodule_status(
	const char *path, unsigned int status_flags, void *payload)
{
	submodule_expectations *exp = payload;

253
	while (exp->statuses[exp->counter] < 0)
254 255
		exp->counter++;

256
	cl_assert_equal_i(exp->statuses[exp->counter], (int)status_flags);
257 258 259 260 261 262 263 264 265 266
	cl_assert_equal_s(exp->paths[exp->counter++], path);

	GIT_UNUSED(status_flags);

	return 0;
}

void test_submodule_status__iterator(void)
{
	git_iterator *iter;
267
	git_iterator_options iter_opts = GIT_ITERATOR_OPTIONS_INIT;
268 269 270 271 272 273 274
	const git_index_entry *entry;
	size_t i;
	static const char *expected[] = {
		".gitmodules",
		"just_a_dir/",
		"just_a_dir/contents",
		"just_a_file",
275 276 277 278
		"not-submodule/",
		"not-submodule/README.txt",
		"not/",
		"not/README.txt",
279 280 281 282 283 284 285 286 287 288
		"README.txt",
		"sm_added_and_uncommited",
		"sm_changed_file",
		"sm_changed_head",
		"sm_changed_index",
		"sm_changed_untracked_file",
		"sm_missing_commits",
		"sm_unchanged",
		NULL
	};
289 290
	static int expected_flags[] = {
		GIT_STATUS_INDEX_MODIFIED | GIT_STATUS_WT_MODIFIED, /* ".gitmodules" */
291
		-1,					    /* "just_a_dir/" will be skipped */
292 293
		GIT_STATUS_CURRENT,     /* "just_a_dir/contents" */
		GIT_STATUS_CURRENT,	    /* "just_a_file" */
294 295 296 297
		GIT_STATUS_WT_NEW,      /* "not-submodule/" untracked item */
		-1,                     /* "not-submodule/README.txt" */
		GIT_STATUS_WT_NEW,      /* "not/" untracked item */
		-1,                     /* "not/README.txt" */
298 299 300 301 302 303 304 305 306 307 308
		GIT_STATUS_CURRENT,     /* "README.txt */
		GIT_STATUS_INDEX_NEW,   /* "sm_added_and_uncommited" */
		GIT_STATUS_WT_MODIFIED, /* "sm_changed_file" */
		GIT_STATUS_WT_MODIFIED, /* "sm_changed_head" */
		GIT_STATUS_WT_MODIFIED, /* "sm_changed_index" */
		GIT_STATUS_WT_MODIFIED, /* "sm_changed_untracked_file" */
		GIT_STATUS_WT_MODIFIED, /* "sm_missing_commits" */
		GIT_STATUS_CURRENT,     /* "sm_unchanged" */
		0
	};
	submodule_expectations exp = { 0, expected, expected_flags };
309
	git_status_options opts = GIT_STATUS_OPTIONS_INIT;
310
	git_index *index;
311

312 313
	iter_opts.flags = GIT_ITERATOR_IGNORE_CASE | GIT_ITERATOR_INCLUDE_TREES;

314
	cl_git_pass(git_repository_index(&index, g_repo));
315
	cl_git_pass(git_iterator_for_workdir(&iter, g_repo, index, NULL, &iter_opts));
316

317
	for (i = 0; !git_iterator_advance(&entry, iter); ++i)
318 319 320
		cl_assert_equal_s(expected[i], entry->path);

	git_iterator_free(iter);
321
	git_index_free(index);
322

323 324
	opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
		GIT_STATUS_OPT_INCLUDE_UNMODIFIED |
325
		GIT_STATUS_OPT_INCLUDE_IGNORED |
326 327
		GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS |
		GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY;
328

329 330
	cl_git_pass(git_status_foreach_ext(
		g_repo, &opts, confirm_submodule_status, &exp));
331
}
332 333 334 335 336

void test_submodule_status__untracked_dirs_containing_ignored_files(void)
{
	unsigned int status, expected;

337 338
	cl_git_append2file(
		"submod2/.git/modules/sm_unchanged/info/exclude", "\n*.ignored\n");
339

340
	cl_git_pass(
341
		git_futils_mkdir_relative("sm_unchanged/directory", "submod2", 0755, 0, NULL));
342 343 344
	cl_git_mkfile(
		"submod2/sm_unchanged/directory/i_am.ignored",
		"ignore this file, please\n");
345

346
	status = get_submodule_status(g_repo, "sm_unchanged");
347 348 349 350 351 352 353 354
	cl_assert(GIT_SUBMODULE_STATUS_IS_UNMODIFIED(status));

	expected = GIT_SUBMODULE_STATUS_IN_HEAD |
		GIT_SUBMODULE_STATUS_IN_INDEX |
		GIT_SUBMODULE_STATUS_IN_CONFIG |
		GIT_SUBMODULE_STATUS_IN_WD;
	cl_assert(status == expected);
}