t00-core.c 12.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2,
 * as published by the Free Software Foundation.
 *
 * In addition to the permissions in the GNU General Public License,
 * the authors give you unlimited permission to link the compiled
 * version of this file into combinations with other programs,
 * and to distribute those combinations without any restriction
 * coming from the use of this file.  (The General Public License
 * restrictions do apply in other respects; for example, they cover
 * modification of the file, and distribution when not linked into
 * a combined executable.)
 *
 * This file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "test_lib.h"

#include "vector.h"
#include "fileops.h"
29
#include "filebuf.h"
30

31
BEGIN_TEST(string0, "compare prefixes")
32 33 34 35 36 37 38 39 40 41
	must_be_true(git__prefixcmp("", "") == 0);
	must_be_true(git__prefixcmp("a", "") == 0);
	must_be_true(git__prefixcmp("", "a") < 0);
	must_be_true(git__prefixcmp("a", "b") < 0);
	must_be_true(git__prefixcmp("b", "a") > 0);
	must_be_true(git__prefixcmp("ab", "a") == 0);
	must_be_true(git__prefixcmp("ab", "ac") < 0);
	must_be_true(git__prefixcmp("ab", "aa") > 0);
END_TEST

42
BEGIN_TEST(string1, "compare suffixes")
43 44 45 46 47 48 49 50 51 52
	must_be_true(git__suffixcmp("", "") == 0);
	must_be_true(git__suffixcmp("a", "") == 0);
	must_be_true(git__suffixcmp("", "a") < 0);
	must_be_true(git__suffixcmp("a", "b") < 0);
	must_be_true(git__suffixcmp("b", "a") > 0);
	must_be_true(git__suffixcmp("ba", "a") == 0);
	must_be_true(git__suffixcmp("zaa", "ac") < 0);
	must_be_true(git__suffixcmp("zaz", "ac") > 0);
END_TEST

53 54 55 56

BEGIN_TEST(vector0, "initial size of 1 would cause writing past array bounds")
  git_vector x;
  int i;
57
  git_vector_init(&x, 1, NULL);
58 59 60 61 62 63 64 65 66
  for (i = 0; i < 10; ++i) {
    git_vector_insert(&x, (void*) 0xabc);
  }
  git_vector_free(&x);
END_TEST

BEGIN_TEST(vector1, "don't read past array bounds on remove()")
  git_vector x;
  // make initial capacity exact for our insertions.
67
  git_vector_init(&x, 3, NULL);
68 69 70 71 72 73 74 75 76 77
  git_vector_insert(&x, (void*) 0xabc);
  git_vector_insert(&x, (void*) 0xdef);
  git_vector_insert(&x, (void*) 0x123);

  git_vector_remove(&x, 0);  // used to read past array bounds.
  git_vector_free(&x);
END_TEST


BEGIN_TEST(path0, "get the dirname of a path")
78 79 80
	char dir[64], *dir2;

#define DIRNAME_TEST(A, B) { \
Vicent Marti committed
81
	must_be_true(git_path_dirname_r(dir, sizeof(dir), A) >= 0); \
82
	must_be_true(strcmp(dir, B) == 0);				\
Vicent Marti committed
83
	must_be_true((dir2 = git_path_dirname(A)) != NULL);	\
84 85 86
	must_be_true(strcmp(dir2, B) == 0);				\
	free(dir2);										\
}
87

88 89 90 91 92 93 94
	DIRNAME_TEST(NULL, ".");
	DIRNAME_TEST("", ".");
	DIRNAME_TEST("a", ".");
	DIRNAME_TEST("/", "/");
	DIRNAME_TEST("/usr", "/");
	DIRNAME_TEST("/usr/", "/");
	DIRNAME_TEST("/usr/lib", "/usr");
95 96
	DIRNAME_TEST("/usr/lib/", "/usr");
	DIRNAME_TEST("/usr/lib//", "/usr");
97
	DIRNAME_TEST("usr/lib", "usr");
98 99
	DIRNAME_TEST("usr/lib/", "usr");
	DIRNAME_TEST("usr/lib//", "usr");
100
	DIRNAME_TEST(".git/", ".");
101

102
#undef DIRNAME_TEST
103 104 105

END_TEST

106
BEGIN_TEST(path1, "get the base name of a path")
107 108 109
	char base[64], *base2;

#define BASENAME_TEST(A, B) { \
Vicent Marti committed
110
	must_be_true(git_path_basename_r(base, sizeof(base), A) >= 0); \
111
	must_be_true(strcmp(base, B) == 0);					\
Vicent Marti committed
112
	must_be_true((base2 = git_path_basename(A)) != NULL);	\
113 114 115
	must_be_true(strcmp(base2, B) == 0);				\
	free(base2);										\
}
116

117 118 119 120 121 122 123
	BASENAME_TEST(NULL, ".");
	BASENAME_TEST("", ".");
	BASENAME_TEST("a", "a");
	BASENAME_TEST("/", "/");
	BASENAME_TEST("/usr", "usr");
	BASENAME_TEST("/usr/", "usr");
	BASENAME_TEST("/usr/lib", "lib");
124
	BASENAME_TEST("/usr/lib//", "lib");
125
	BASENAME_TEST("usr/lib", "lib");
126

127
#undef BASENAME_TEST
128

129
END_TEST
130

131
BEGIN_TEST(path2, "get the latest component in a path")
132
	const char *dir;
133

134
#define TOPDIR_TEST(A, B) { \
Vicent Marti committed
135
	must_be_true((dir = git_path_topdir(A)) != NULL);	\
136 137
	must_be_true(strcmp(dir, B) == 0);				\
}
138

139 140 141 142 143 144 145
	TOPDIR_TEST(".git/", ".git/");
	TOPDIR_TEST("/.git/", ".git/");
	TOPDIR_TEST("usr/local/.git/", ".git/");
	TOPDIR_TEST("./.git/", ".git/");
	TOPDIR_TEST("/usr/.git/", ".git/");
	TOPDIR_TEST("/", "/");
	TOPDIR_TEST("a/", "a/");
146

Vicent Marti committed
147 148 149 150
	must_be_true(git_path_topdir("/usr/.git") == NULL);
	must_be_true(git_path_topdir(".") == NULL);
	must_be_true(git_path_topdir("") == NULL);
	must_be_true(git_path_topdir("a") == NULL);
151

152
#undef TOPDIR_TEST
153 154
END_TEST

155 156
static int ensure_joinpath(const char *path_a, const char *path_b, const char *expected_path)
{
157
	char joined_path[GIT_PATH_MAX];
Vicent Marti committed
158
	git_path_join(joined_path, path_a, path_b);
159
	return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR;
160 161
}

162
BEGIN_TEST(path5, "properly join path components")
163 164 165
	must_pass(ensure_joinpath("", "", ""));
	must_pass(ensure_joinpath("", "a", "a"));
	must_pass(ensure_joinpath("", "/a", "/a"));
166
	must_pass(ensure_joinpath("a", "", "a/"));
167
	must_pass(ensure_joinpath("a", "/", "a/"));
168 169 170 171 172 173 174 175 176
	must_pass(ensure_joinpath("a", "b", "a/b"));
	must_pass(ensure_joinpath("/", "a", "/a"));
	must_pass(ensure_joinpath("/", "", "/"));
	must_pass(ensure_joinpath("/a", "/b", "/a/b"));
	must_pass(ensure_joinpath("/a", "/b/", "/a/b/"));
	must_pass(ensure_joinpath("/a/", "b/", "/a/b/"));
	must_pass(ensure_joinpath("/a/", "/b/", "/a/b/"));
END_TEST

177 178 179
static int ensure_joinpath_n(const char *path_a, const char *path_b, const char *path_c, const char *path_d, const char *expected_path)
{
	char joined_path[GIT_PATH_MAX];
Vicent Marti committed
180
	git_path_join_n(joined_path, 4, path_a, path_b, path_c, path_d);
181 182 183
	return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR;
}

184
BEGIN_TEST(path6, "properly join path components for more than one path")
185 186 187 188 189 190 191 192
	must_pass(ensure_joinpath_n("", "", "", "", ""));
	must_pass(ensure_joinpath_n("", "a", "", "", "a/"));
	must_pass(ensure_joinpath_n("a", "", "", "", "a/"));
	must_pass(ensure_joinpath_n("", "", "", "a", "a"));
	must_pass(ensure_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/"));
	must_pass(ensure_joinpath_n("a", "b", "", "/c/d", "a/b/c/d"));
END_TEST

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
typedef struct name_data {
	int  count;  /* return count */
	char *name;  /* filename     */
} name_data;

typedef struct walk_data {
	char *sub;        /* sub-directory name */
	name_data *names; /* name state data    */
} walk_data;


static char path_buffer[GIT_PATH_MAX];
static char *top_dir = "dir-walk";
static walk_data *state_loc;

static int error(const char *fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
	fprintf(stderr, "\n");
	return -1;
}

static int setup(walk_data *d)
{
	name_data *n;

Vicent Marti committed
223
	if (p_mkdir(top_dir, 0755) < 0)
224 225
		return error("can't mkdir(\"%s\")", top_dir);

Vicent Marti committed
226
	if (p_chdir(top_dir) < 0)
227 228 229
		return error("can't chdir(\"%s\")", top_dir);

	if (strcmp(d->sub, ".") != 0)
Vicent Marti committed
230
		if (p_mkdir(d->sub, 0755) < 0)
231 232 233 234 235 236
			return error("can't mkdir(\"%s\")", d->sub);

	strcpy(path_buffer, d->sub);
	state_loc = d;

	for (n = d->names; n->name; n++) {
Vicent Marti committed
237
		git_file fd = p_creat(n->name, 0600);
238 239
		if (fd < 0)
			return GIT_ERROR;
Vicent Marti committed
240
		p_close(fd);
241 242 243 244 245 246 247 248 249 250 251
		n->count = 0;
	}

	return 0;
}

static int knockdown(walk_data *d)
{
	name_data *n;

	for (n = d->names; n->name; n++) {
Vicent Marti committed
252
		if (p_unlink(n->name) < 0)
253 254 255 256
			return error("can't unlink(\"%s\")", n->name);
	}

	if (strcmp(d->sub, ".") != 0)
Vicent Marti committed
257
		if (p_rmdir(d->sub) < 0)
258 259
			return error("can't rmdir(\"%s\")", d->sub);

Vicent Marti committed
260
	if (p_chdir("..") < 0)
261 262
		return error("can't chdir(\"..\")");

Vicent Marti committed
263
	if (p_rmdir(top_dir) < 0)
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 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
		return error("can't rmdir(\"%s\")", top_dir);

	return 0;
}

static int check_counts(walk_data *d)
{
	int ret = 0;
	name_data *n;

	for (n = d->names; n->name; n++) {
		if (n->count != 1)
			ret = error("count (%d, %s)", n->count, n->name);
	}
	return ret;
}

static int one_entry(void *state, char *path)
{
	walk_data *d = (walk_data *) state;
	name_data *n;

	if (state != state_loc)
		return GIT_ERROR;

	if (path != path_buffer)
		return GIT_ERROR;

	for (n = d->names; n->name; n++) {
		if (!strcmp(n->name, path)) {
			n->count++;
			return 0;
		}
	}

	return GIT_ERROR;
}


static name_data dot_names[] = {
	{ 0, "./a" },
	{ 0, "./asdf" },
	{ 0, "./pack-foo.pack" },
	{ 0, NULL }
};
static walk_data dot = {
	".",
	dot_names
};

314
BEGIN_TEST(dirent0, "make sure that the '.' folder is not traversed")
315 316 317

	must_pass(setup(&dot));

Vicent Marti committed
318
	must_pass(git_futils_direach(path_buffer,
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
			       sizeof(path_buffer),
			       one_entry,
			       &dot));

	must_pass(check_counts(&dot));

	must_pass(knockdown(&dot));
END_TEST

static name_data sub_names[] = {
	{ 0, "sub/a" },
	{ 0, "sub/asdf" },
	{ 0, "sub/pack-foo.pack" },
	{ 0, NULL }
};
static walk_data sub = {
	"sub",
	sub_names
};

339
BEGIN_TEST(dirent1, "traverse a subfolder")
340 341 342

	must_pass(setup(&sub));

Vicent Marti committed
343
	must_pass(git_futils_direach(path_buffer,
344 345 346 347 348 349 350 351 352 353 354 355 356 357
			       sizeof(path_buffer),
			       one_entry,
			       &sub));

	must_pass(check_counts(&sub));

	must_pass(knockdown(&sub));
END_TEST

static walk_data sub_slash = {
	"sub/",
	sub_names
};

358
BEGIN_TEST(dirent2, "traverse a slash-terminated subfolder")
359 360 361

	must_pass(setup(&sub_slash));

Vicent Marti committed
362
	must_pass(git_futils_direach(path_buffer,
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
			       sizeof(path_buffer),
			       one_entry,
			       &sub_slash));

	must_pass(check_counts(&sub_slash));

	must_pass(knockdown(&sub_slash));
END_TEST

static name_data empty_names[] = {
	{ 0, NULL }
};
static walk_data empty = {
	"empty",
	empty_names
};

static int dont_call_me(void *GIT_UNUSED(state), char *GIT_UNUSED(path))
{
	GIT_UNUSED_ARG(state)
	GIT_UNUSED_ARG(path)
	return GIT_ERROR;
}

387
BEGIN_TEST(dirent3, "make sure that empty folders are not traversed")
388 389 390

	must_pass(setup(&empty));

Vicent Marti committed
391
	must_pass(git_futils_direach(path_buffer,
392 393 394 395 396 397 398
			       sizeof(path_buffer),
			       one_entry,
			       &empty));

	must_pass(check_counts(&empty));

	/* make sure callback not called */
Vicent Marti committed
399
	must_pass(git_futils_direach(path_buffer,
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
			       sizeof(path_buffer),
			       dont_call_me,
			       &empty));

	must_pass(knockdown(&empty));
END_TEST

static name_data odd_names[] = {
	{ 0, "odd/.a" },
	{ 0, "odd/..c" },
	/* the following don't work on cygwin/win32 */
	/* { 0, "odd/.b." }, */
	/* { 0, "odd/..d.." },  */
	{ 0, NULL }
};
static walk_data odd = {
	"odd",
	odd_names
};

420
BEGIN_TEST(dirent4, "make sure that strange looking filenames ('..c') are traversed")
421 422 423

	must_pass(setup(&odd));

Vicent Marti committed
424
	must_pass(git_futils_direach(path_buffer,
425 426 427 428 429 430 431 432 433
			       sizeof(path_buffer),
			       one_entry,
			       &odd));

	must_pass(check_counts(&odd));

	must_pass(knockdown(&odd));
END_TEST

434 435
BEGIN_TEST(filebuf0, "make sure git_filebuf_open doesn't delete an existing lock")
	git_filebuf file;
436
	int fd;
437 438
	char test[] = "test", testlock[] = "test.lock";

Vicent Marti committed
439
	fd = p_creat(testlock, 0744);
440
	must_pass(fd);
Vicent Marti committed
441
	must_pass(p_close(fd));
442
	must_fail(git_filebuf_open(&file, test, 0));
Vicent Marti committed
443 444
	must_pass(git_futils_exists(testlock));
	must_pass(p_unlink(testlock));
445
END_TEST
446

447 448 449 450 451
BEGIN_TEST(filebuf1, "make sure GIT_FILEBUF_APPEND works as expected")
	git_filebuf file;
	int fd;
	char test[] = "test";

Vicent Marti committed
452
	fd = p_creat(test, 0644);
453
	must_pass(fd);
Vicent Marti committed
454 455
	must_pass(p_write(fd, "libgit2 rocks\n", 14));
	must_pass(p_close(fd));
456 457 458 459 460

	must_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND));
	must_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
	must_pass(git_filebuf_commit(&file));

Vicent Marti committed
461
	must_pass(p_unlink(test));
462 463
END_TEST

464 465 466 467 468 469 470 471 472 473
BEGIN_TEST(filebuf2, "make sure git_filebuf_write writes large buffer correctly")
	git_filebuf file;
	char test[] = "test";
	unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */

	memset(buf, 0xfe, sizeof(buf));
	must_pass(git_filebuf_open(&file, test, 0));
	must_pass(git_filebuf_write(&file, buf, sizeof(buf)));
	must_pass(git_filebuf_commit(&file));

Vicent Marti committed
474
	must_pass(p_unlink(test));
475 476
END_TEST

477 478 479
BEGIN_SUITE(core)
	ADD_TEST(string0);
	ADD_TEST(string1);
480

481 482
	ADD_TEST(vector0);
	ADD_TEST(vector1);
483

484 485 486 487 488
	ADD_TEST(path0);
	ADD_TEST(path1);
	ADD_TEST(path2);
	ADD_TEST(path5);
	ADD_TEST(path6);
489

490 491 492 493 494
	ADD_TEST(dirent0);
	ADD_TEST(dirent1);
	ADD_TEST(dirent2);
	ADD_TEST(dirent3);
	ADD_TEST(dirent4);
495 496

	ADD_TEST(filebuf0);
497
	ADD_TEST(filebuf1);
498
	ADD_TEST(filebuf2);
499
END_SUITE