path.c 20.8 KB
Newer Older
1
#include "clar_libgit2.h"
2
#include "futils.h"
3
#include "fs_path.h"
Vicent Marti committed
4

5 6
static char *path_save;

7
void test_path__initialize(void)
8 9 10 11
{
	path_save = cl_getenv("PATH");
}

12
void test_path__cleanup(void)
13 14 15 16 17 18
{
	cl_setenv("PATH", path_save);
	git__free(path_save);
	path_save = NULL;
}

Vicent Marti committed
19 20 21
static void
check_dirname(const char *A, const char *B)
{
22
	git_str dir = GIT_STR_INIT;
23
	char *dir2;
Vicent Marti committed
24

25
	cl_assert(git_fs_path_dirname_r(&dir, A) >= 0);
26
	cl_assert_equal_s(B, dir.ptr);
27
	git_str_dispose(&dir);
Vicent Marti committed
28

29
	cl_assert((dir2 = git_fs_path_dirname(A)) != NULL);
30
	cl_assert_equal_s(B, dir2);
31
	git__free(dir2);
Vicent Marti committed
32 33 34 35 36
}

static void
check_basename(const char *A, const char *B)
{
37
	git_str base = GIT_STR_INIT;
38
	char *base2;
Vicent Marti committed
39

40
	cl_assert(git_fs_path_basename_r(&base, A) >= 0);
41
	cl_assert_equal_s(B, base.ptr);
42
	git_str_dispose(&base);
Vicent Marti committed
43

44
	cl_assert((base2 = git_fs_path_basename(A)) != NULL);
45
	cl_assert_equal_s(B, base2);
46
	git__free(base2);
Vicent Marti committed
47 48 49 50 51
}

static void
check_joinpath(const char *path_a, const char *path_b, const char *expected_path)
{
52
	git_str joined_path = GIT_STR_INIT;
Vicent Marti committed
53

54
	cl_git_pass(git_str_joinpath(&joined_path, path_a, path_b));
55
	cl_assert_equal_s(expected_path, joined_path.ptr);
56

57
	git_str_dispose(&joined_path);
Vicent Marti committed
58 59 60 61 62 63 64 65 66 67
}

static void
check_joinpath_n(
	const char *path_a,
	const char *path_b,
	const char *path_c,
	const char *path_d,
	const char *expected_path)
{
68
	git_str joined_path = GIT_STR_INIT;
69

70
	cl_git_pass(git_str_join_n(&joined_path, '/', 4,
71
							   path_a, path_b, path_c, path_d));
72
	cl_assert_equal_s(expected_path, joined_path.ptr);
Vicent Marti committed
73

74
	git_str_dispose(&joined_path);
Vicent Marti committed
75 76
}

77 78 79 80 81 82 83 84 85 86 87 88 89 90
static void check_setenv(const char* name, const char* value)
{
    char* check;

    cl_git_pass(cl_setenv(name, value));
    check = cl_getenv(name);

    if (value)
	cl_assert_equal_s(value, check);
    else
	cl_assert(check == NULL);

    git__free(check);
}
Vicent Marti committed
91 92

/* get the dirname of a path */
93
void test_path__00_dirname(void)
Vicent Marti committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107
{
	check_dirname(NULL, ".");
	check_dirname("", ".");
	check_dirname("a", ".");
	check_dirname("/", "/");
	check_dirname("/usr", "/");
	check_dirname("/usr/", "/");
	check_dirname("/usr/lib", "/usr");
	check_dirname("/usr/lib/", "/usr");
	check_dirname("/usr/lib//", "/usr");
	check_dirname("usr/lib", "usr");
	check_dirname("usr/lib/", "usr");
	check_dirname("usr/lib//", "usr");
	check_dirname(".git/", ".");
108 109

	check_dirname(REP16("/abc"), REP15("/abc"));
110 111

#ifdef GIT_WIN32
112
	check_dirname("C:/", "C:/");
113
	check_dirname("C:", "C:/");
114 115
	check_dirname("C:/path/", "C:/");
	check_dirname("C:/path", "C:/");
116
	check_dirname("//computername/", "//computername/");
117
	check_dirname("//computername", "//computername/");
118 119 120 121
	check_dirname("//computername/path/", "//computername/");
	check_dirname("//computername/path", "//computername/");
	check_dirname("//computername/sub/path/", "//computername/sub");
	check_dirname("//computername/sub/path", "//computername/sub");
122
#endif
Vicent Marti committed
123 124 125
}

/* get the base name of a path */
126
void test_path__01_basename(void)
Vicent Marti committed
127 128 129 130 131 132 133 134 135 136
{
	check_basename(NULL, ".");
	check_basename("", ".");
	check_basename("a", "a");
	check_basename("/", "/");
	check_basename("/usr", "usr");
	check_basename("/usr/", "usr");
	check_basename("/usr/lib", "lib");
	check_basename("/usr/lib//", "lib");
	check_basename("usr/lib", "lib");
137 138 139

	check_basename(REP16("/abc"), "abc");
	check_basename(REP1024("/abc"), "abc");
Vicent Marti committed
140 141 142
}

/* properly join path components */
143
void test_path__05_joins(void)
Vicent Marti committed
144 145 146 147 148 149 150 151 152 153 154 155 156
{
	check_joinpath("", "", "");
	check_joinpath("", "a", "a");
	check_joinpath("", "/a", "/a");
	check_joinpath("a", "", "a/");
	check_joinpath("a", "/", "a/");
	check_joinpath("a", "b", "a/b");
	check_joinpath("/", "a", "/a");
	check_joinpath("/", "", "/");
	check_joinpath("/a", "/b", "/a/b");
	check_joinpath("/a", "/b/", "/a/b/");
	check_joinpath("/a/", "b/", "/a/b/");
	check_joinpath("/a/", "/b/", "/a/b/");
157 158 159 160 161 162 163 164 165 166

	check_joinpath("/abcd", "/defg", "/abcd/defg");
	check_joinpath("/abcd", "/defg/", "/abcd/defg/");
	check_joinpath("/abcd/", "defg/", "/abcd/defg/");
	check_joinpath("/abcd/", "/defg/", "/abcd/defg/");

	check_joinpath("/abcdefgh", "/12345678", "/abcdefgh/12345678");
	check_joinpath("/abcdefgh", "/12345678/", "/abcdefgh/12345678/");
	check_joinpath("/abcdefgh/", "12345678/", "/abcdefgh/12345678/");

167 168 169 170
	check_joinpath(REP1024("aaaa"), "", REP1024("aaaa") "/");
	check_joinpath(REP1024("aaaa/"), "", REP1024("aaaa/"));
	check_joinpath(REP1024("/aaaa"), "", REP1024("/aaaa") "/");

171 172 173 174
	check_joinpath(REP1024("aaaa"), REP1024("bbbb"),
				   REP1024("aaaa") "/" REP1024("bbbb"));
	check_joinpath(REP1024("/aaaa"), REP1024("/bbbb"),
				   REP1024("/aaaa") REP1024("/bbbb"));
Vicent Marti committed
175 176 177
}

/* properly join path components for more than one path */
178
void test_path__06_long_joins(void)
Vicent Marti committed
179 180 181 182 183 184 185
{
	check_joinpath_n("", "", "", "", "");
	check_joinpath_n("", "a", "", "", "a/");
	check_joinpath_n("a", "", "", "", "a/");
	check_joinpath_n("", "", "", "a", "a");
	check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/");
	check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d");
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
	check_joinpath_n("abcd", "efgh", "ijkl", "mnop", "abcd/efgh/ijkl/mnop");
	check_joinpath_n("abcd/", "efgh/", "ijkl/", "mnop/", "abcd/efgh/ijkl/mnop/");
	check_joinpath_n("/abcd/", "/efgh/", "/ijkl/", "/mnop/", "/abcd/efgh/ijkl/mnop/");

	check_joinpath_n(REP1024("a"), REP1024("b"), REP1024("c"), REP1024("d"),
					 REP1024("a") "/" REP1024("b") "/"
					 REP1024("c") "/" REP1024("d"));
	check_joinpath_n(REP1024("/a"), REP1024("/b"), REP1024("/c"), REP1024("/d"),
					 REP1024("/a") REP1024("/b")
					 REP1024("/c") REP1024("/d"));
}


static void
check_path_to_dir(
	const char* path,
    const char* expected)
{
204
	git_str tgt = GIT_STR_INIT;
205

206
	git_str_sets(&tgt, path);
207
	cl_git_pass(git_fs_path_to_dir(&tgt));
208
	cl_assert_equal_s(expected, tgt.ptr);
209

210
	git_str_dispose(&tgt);
211 212 213 214 215
}

static void
check_string_to_dir(
	const char* path,
216
	size_t      maxlen,
217 218
    const char* expected)
{
219
	size_t len = strlen(path);
220
	char *buf = git__malloc(len + 2);
221 222
	cl_assert(buf);

223 224
	strncpy(buf, path, len + 2);

225
	git_fs_path_string_to_dir(buf, maxlen);
226

227
	cl_assert_equal_s(expected, buf);
228 229 230 231 232

	git__free(buf);
}

/* convert paths to dirs */
233
void test_path__07_path_to_dir(void)
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
{
	check_path_to_dir("", "");
	check_path_to_dir(".", "./");
	check_path_to_dir("./", "./");
	check_path_to_dir("a/", "a/");
	check_path_to_dir("ab", "ab/");
	/* make sure we try just under and just over an expansion that will
	 * require a realloc
	 */
	check_path_to_dir("abcdef", "abcdef/");
	check_path_to_dir("abcdefg", "abcdefg/");
	check_path_to_dir("abcdefgh", "abcdefgh/");
	check_path_to_dir("abcdefghi", "abcdefghi/");
	check_path_to_dir(REP1024("abcd") "/", REP1024("abcd") "/");
	check_path_to_dir(REP1024("abcd"), REP1024("abcd") "/");

	check_string_to_dir("", 1, "");
	check_string_to_dir(".", 1, ".");
	check_string_to_dir(".", 2, "./");
	check_string_to_dir(".", 3, "./");
	check_string_to_dir("abcd", 3, "abcd");
	check_string_to_dir("abcd", 4, "abcd");
	check_string_to_dir("abcd", 5, "abcd/");
	check_string_to_dir("abcd", 6, "abcd/");
Vicent Marti committed
258
}
259 260

/* join path to itself */
261
void test_path__08_self_join(void)
262
{
263
	git_str path = GIT_STR_INIT;
264
	size_t asize = 0;
265 266

	asize = path.asize;
267
	cl_git_pass(git_str_sets(&path, "/foo"));
268
	cl_assert_equal_s(path.ptr, "/foo");
269 270 271
	cl_assert(asize < path.asize);

	asize = path.asize;
272
	cl_git_pass(git_str_joinpath(&path, path.ptr, "this is a new string"));
273
	cl_assert_equal_s(path.ptr, "/foo/this is a new string");
274 275 276
	cl_assert(asize < path.asize);

	asize = path.asize;
277
	cl_git_pass(git_str_joinpath(&path, path.ptr, "/grow the buffer, grow the buffer, grow the buffer"));
278
	cl_assert_equal_s(path.ptr, "/foo/this is a new string/grow the buffer, grow the buffer, grow the buffer");
279 280
	cl_assert(asize < path.asize);

281 282
	git_str_dispose(&path);
	cl_git_pass(git_str_sets(&path, "/foo/bar"));
283

284
	cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "baz"));
285
	cl_assert_equal_s(path.ptr, "/bar/baz");
286 287

	asize = path.asize;
288
	cl_git_pass(git_str_joinpath(&path, path.ptr + 4, "somethinglongenoughtorealloc"));
289
	cl_assert_equal_s(path.ptr, "/baz/somethinglongenoughtorealloc");
290
	cl_assert(asize < path.asize);
291

292
	git_str_dispose(&path);
293
}
294 295 296

static void check_percent_decoding(const char *expected_result, const char *input)
{
297
	git_str buf = GIT_STR_INIT;
298 299

	cl_git_pass(git__percent_decode(&buf, input));
300
	cl_assert_equal_s(expected_result, git_str_cstr(&buf));
301

302
	git_str_dispose(&buf);
303 304
}

305
void test_path__09_percent_decode(void)
306 307 308 309 310 311 312 313 314 315 316 317
{
	check_percent_decoding("abcd", "abcd");
	check_percent_decoding("a2%", "a2%");
	check_percent_decoding("a2%3", "a2%3");
	check_percent_decoding("a2%%3", "a2%%3");
	check_percent_decoding("a2%3z", "a2%3z");
	check_percent_decoding("a,", "a%2c");
	check_percent_decoding("a21", "a2%31");
	check_percent_decoding("a2%1", "a2%%31");
	check_percent_decoding("a bc ", "a%20bc%20");
	check_percent_decoding("Vicent Mart" "\355", "Vicent%20Mart%ED");
}
nulltoken committed
318 319 320

static void check_fromurl(const char *expected_result, const char *input, int should_fail)
{
321
	git_str buf = GIT_STR_INIT;
nulltoken committed
322 323 324 325

	assert(should_fail || expected_result);

	if (!should_fail) {
326
		cl_git_pass(git_fs_path_fromurl(&buf, input));
327
		cl_assert_equal_s(expected_result, git_str_cstr(&buf));
nulltoken committed
328
	} else
329
		cl_git_fail(git_fs_path_fromurl(&buf, input));
nulltoken committed
330

331
	git_str_dispose(&buf);
nulltoken committed
332 333
}

334
#ifdef GIT_WIN32
nulltoken committed
335 336 337 338 339
#define ABS_PATH_MARKER ""
#else
#define ABS_PATH_MARKER "/"
#endif

340
void test_path__10_fromurl(void)
nulltoken committed
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
{
	/* Failing cases */
	check_fromurl(NULL, "a", 1);
	check_fromurl(NULL, "http:///c:/Temp%20folder/note.txt", 1);
	check_fromurl(NULL, "file://c:/Temp%20folder/note.txt", 1);
	check_fromurl(NULL, "file:////c:/Temp%20folder/note.txt", 1);
	check_fromurl(NULL, "file:///", 1);
	check_fromurl(NULL, "file:////", 1);
	check_fromurl(NULL, "file://servername/c:/Temp%20folder/note.txt", 1);

	/* Passing cases */
	check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file:///c:/Temp%20folder/note.txt", 0);
	check_fromurl(ABS_PATH_MARKER "c:/Temp folder/note.txt", "file://localhost/c:/Temp%20folder/note.txt", 0);
	check_fromurl(ABS_PATH_MARKER "c:/Temp+folder/note.txt", "file:///c:/Temp+folder/note.txt", 0);
	check_fromurl(ABS_PATH_MARKER "a", "file:///a", 0);
}
357

358 359
typedef struct {
	int expect_idx;
360
	int cancel_after;
361 362 363
	char **expect;
} check_walkup_info;

364 365
#define CANCEL_VALUE 1234

366
static int check_one_walkup_step(void *ref, const char *path)
367 368
{
	check_walkup_info *info = (check_walkup_info *)ref;
369 370 371

	if (!info->cancel_after) {
		cl_assert_equal_s(info->expect[info->expect_idx], "[CANCEL]");
372
		return CANCEL_VALUE;
373 374 375
	}
	info->cancel_after--;

376
	cl_assert(info->expect[info->expect_idx] != NULL);
377
	cl_assert_equal_s(info->expect[info->expect_idx], path);
378
	info->expect_idx++;
379

380
	return 0;
381 382
}

383
void test_path__11_walkup(void)
384
{
385
	git_str p = GIT_STR_INIT;
386

387
	char *expect[] = {
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
		/*  1 */ "/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
		/*  2 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
		/*  3 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
		/*  4 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", "/a/", "/", NULL,
		/*  5 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL,
		/*  6 */ "/a/b/c/d/e", "/a/b/c/d/", "/a/b/c/", "/a/b/", NULL,
		/*  7 */ "this_is_a_path", "", NULL,
		/*  8 */ "this_is_a_path/", "", NULL,
		/*  9 */ "///a///b///c///d///e///", "///a///b///c///d///", "///a///b///c///", "///a///b///", "///a///", "///", NULL,
		/* 10 */ "a/b/c/", "a/b/", "a/", "", NULL,
		/* 11 */ "a/b/c", "a/b/", "a/", "", NULL,
		/* 12 */ "a/b/c/", "a/b/", "a/", NULL,
		/* 13 */ "", NULL,
		/* 14 */ "/", NULL,
		/* 15 */ NULL
	};

	char *root[] = {
		/*  1 */ NULL,
		/*  2 */ NULL,
		/*  3 */ "/",
		/*  4 */ "",
		/*  5 */ "/a/b",
		/*  6 */ "/a/b/",
		/*  7 */ NULL,
		/*  8 */ NULL,
		/*  9 */ NULL,
		/* 10 */ NULL,
		/* 11 */ NULL,
		/* 12 */ "a/",
		/* 13 */ NULL,
		/* 14 */ NULL,
420
	};
421

422
	int i, j;
423 424 425
	check_walkup_info info;

	info.expect = expect;
426
	info.cancel_after = -1;
427 428 429

	for (i = 0, j = 0; expect[i] != NULL; i++, j++) {

430
		git_str_sets(&p, expect[i]);
431

432 433
		info.expect_idx = i;
		cl_git_pass(
434
			git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info)
435
		);
436

437
		cl_assert_equal_s(p.ptr, expect[i]);
438 439
		cl_assert(expect[info.expect_idx] == NULL);
		i = info.expect_idx;
440 441
	}

442
	git_str_dispose(&p);
443 444
}

445
void test_path__11a_walkup_cancel(void)
446
{
447
	git_str p = GIT_STR_INIT;
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
	int cancel[] = { 3, 2, 1, 0 };
	char *expect[] = {
		"/a/b/c/d/e/", "/a/b/c/d/", "/a/b/c/", "[CANCEL]", NULL,
		"/a/b/c/d/e", "/a/b/c/d/", "[CANCEL]", NULL,
		"/a/b/c/d/e", "[CANCEL]", NULL,
		"[CANCEL]", NULL,
		NULL
	};
	char *root[] = { NULL, NULL, "/", "", NULL };
	int i, j;
	check_walkup_info info;

	info.expect = expect;

	for (i = 0, j = 0; expect[i] != NULL; i++, j++) {

464
		git_str_sets(&p, expect[i]);
465 466 467 468 469

		info.cancel_after = cancel[j];
		info.expect_idx = i;

		cl_assert_equal_i(
470
			CANCEL_VALUE,
471
			git_fs_path_walk_up(&p, root[j], check_one_walkup_step, &info)
472 473 474 475
		);

		/* skip to next run of expectations */
		while (expect[i] != NULL) i++;
476 477
	}

478
	git_str_dispose(&p);
479
}
480

481
void test_path__12_offset_to_path_root(void)
482
{
483 484
	cl_assert(git_fs_path_root("non/rooted/path") == -1);
	cl_assert(git_fs_path_root("/rooted/path") == 0);
485 486 487

#ifdef GIT_WIN32
	/* Windows specific tests */
488 489 490 491 492
	cl_assert(git_fs_path_root("C:non/rooted/path") == -1);
	cl_assert(git_fs_path_root("C:/rooted/path") == 2);
	cl_assert(git_fs_path_root("//computername/sharefolder/resource") == 14);
	cl_assert(git_fs_path_root("//computername/sharefolder") == 14);
	cl_assert(git_fs_path_root("//computername") == -1);
493 494
#endif
}
495 496 497

#define NON_EXISTING_FILEPATH "i_hope_i_do_not_exist"

498
void test_path__13_cannot_prettify_a_non_existing_file(void)
499
{
500
	git_str p = GIT_STR_INIT;
501

502 503 504
	cl_assert_equal_b(git_fs_path_exists(NON_EXISTING_FILEPATH), false);
	cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH, NULL));
	cl_assert_equal_i(GIT_ENOTFOUND, git_fs_path_prettify(&p, NON_EXISTING_FILEPATH "/so-do-i", NULL));
505

506
	git_str_dispose(&p);
507
}
508

509
void test_path__14_apply_relative(void)
510
{
511
	git_str p = GIT_STR_INIT;
512

513
	cl_git_pass(git_str_sets(&p, "/this/is/a/base"));
514

515
	cl_git_pass(git_fs_path_apply_relative(&p, "../test"));
516 517
	cl_assert_equal_s("/this/is/a/test", p.ptr);

518
	cl_git_pass(git_fs_path_apply_relative(&p, "../../the/./end"));
519 520
	cl_assert_equal_s("/this/is/the/end", p.ptr);

521
	cl_git_pass(git_fs_path_apply_relative(&p, "./of/this/../the/string"));
522 523
	cl_assert_equal_s("/this/is/the/end/of/the/string", p.ptr);

524
	cl_git_pass(git_fs_path_apply_relative(&p, "../../../../../.."));
525 526
	cl_assert_equal_s("/this/", p.ptr);

527
	cl_git_pass(git_fs_path_apply_relative(&p, "../"));
528 529
	cl_assert_equal_s("/", p.ptr);

530
	cl_git_fail(git_fs_path_apply_relative(&p, "../../.."));
531 532


533
	cl_git_pass(git_str_sets(&p, "d:/another/test"));
534

535
	cl_git_pass(git_fs_path_apply_relative(&p, "../.."));
536 537
	cl_assert_equal_s("d:/", p.ptr);

538
	cl_git_pass(git_fs_path_apply_relative(&p, "from/here/to/../and/./back/."));
539 540 541
	cl_assert_equal_s("d:/from/here/and/back/", p.ptr);


542
	cl_git_pass(git_str_sets(&p, "https://my.url.com/test.git"));
543

544
	cl_git_pass(git_fs_path_apply_relative(&p, "../another.git"));
545 546
	cl_assert_equal_s("https://my.url.com/another.git", p.ptr);

547
	cl_git_pass(git_fs_path_apply_relative(&p, "../full/path/url.patch"));
548 549
	cl_assert_equal_s("https://my.url.com/full/path/url.patch", p.ptr);

550
	cl_git_pass(git_fs_path_apply_relative(&p, ".."));
551 552
	cl_assert_equal_s("https://my.url.com/full/path/", p.ptr);

553
	cl_git_pass(git_fs_path_apply_relative(&p, "../../../"));
554 555
	cl_assert_equal_s("https://", p.ptr);

556

557
	cl_git_pass(git_str_sets(&p, "../../this/is/relative"));
558

559
	cl_git_pass(git_fs_path_apply_relative(&p, "../../preserves/the/prefix"));
560 561
	cl_assert_equal_s("../../this/preserves/the/prefix", p.ptr);

562
	cl_git_pass(git_fs_path_apply_relative(&p, "../../../../that"));
563 564
	cl_assert_equal_s("../../that", p.ptr);

565
	cl_git_pass(git_fs_path_apply_relative(&p, "../there"));
566
	cl_assert_equal_s("../../there", p.ptr);
567
	git_str_dispose(&p);
568
}
569

570
static void assert_resolve_relative(
571
	git_str *buf, const char *expected, const char *path)
572
{
573
	cl_git_pass(git_str_sets(buf, path));
574
	cl_git_pass(git_fs_path_resolve_relative(buf, 0));
575 576 577
	cl_assert_equal_s(expected, buf->ptr);
}

578
void test_path__15_resolve_relative(void)
579
{
580
	git_str buf = GIT_STR_INIT;
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626

	assert_resolve_relative(&buf, "", "");
	assert_resolve_relative(&buf, "", ".");
	assert_resolve_relative(&buf, "", "./");
	assert_resolve_relative(&buf, "..", "..");
	assert_resolve_relative(&buf, "../", "../");
	assert_resolve_relative(&buf, "..", "./..");
	assert_resolve_relative(&buf, "../", "./../");
	assert_resolve_relative(&buf, "../", "../.");
	assert_resolve_relative(&buf, "../", ".././");
	assert_resolve_relative(&buf, "../..", "../..");
	assert_resolve_relative(&buf, "../../", "../../");

	assert_resolve_relative(&buf, "/", "/");
	assert_resolve_relative(&buf, "/", "/.");

	assert_resolve_relative(&buf, "", "a/..");
	assert_resolve_relative(&buf, "", "a/../");
	assert_resolve_relative(&buf, "", "a/../.");

	assert_resolve_relative(&buf, "/a", "/a");
	assert_resolve_relative(&buf, "/a/", "/a/.");
	assert_resolve_relative(&buf, "/", "/a/../");
	assert_resolve_relative(&buf, "/", "/a/../.");
	assert_resolve_relative(&buf, "/", "/a/.././");

	assert_resolve_relative(&buf, "a", "a");
	assert_resolve_relative(&buf, "a/", "a/");
	assert_resolve_relative(&buf, "a/", "a/.");
	assert_resolve_relative(&buf, "a/", "a/./");

	assert_resolve_relative(&buf, "a/b", "a//b");
	assert_resolve_relative(&buf, "a/b/c", "a/b/c");
	assert_resolve_relative(&buf, "b/c", "./b/c");
	assert_resolve_relative(&buf, "a/c", "a/./c");
	assert_resolve_relative(&buf, "a/b/", "a/b/.");

	assert_resolve_relative(&buf, "/a/b/c", "///a/b/c");
	assert_resolve_relative(&buf, "/", "////");
	assert_resolve_relative(&buf, "/a", "///a");
	assert_resolve_relative(&buf, "/", "///.");
	assert_resolve_relative(&buf, "/", "///a/..");

	assert_resolve_relative(&buf, "../../path", "../../test//../././path");
	assert_resolve_relative(&buf, "../d", "a/b/../../../c/../d");

627
	cl_git_pass(git_str_sets(&buf, "/.."));
628
	cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
629

630
	cl_git_pass(git_str_sets(&buf, "/./.."));
631
	cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
632

633
	cl_git_pass(git_str_sets(&buf, "/.//.."));
634
	cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
635

636
	cl_git_pass(git_str_sets(&buf, "/../."));
637
	cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
638

639
	cl_git_pass(git_str_sets(&buf, "/../.././../a"));
640
	cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
641

642
	cl_git_pass(git_str_sets(&buf, "////.."));
643
	cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
644

645 646 647 648 649 650
	/* things that start with Windows network paths */
#ifdef GIT_WIN32
	assert_resolve_relative(&buf, "//a/b/c", "//a/b/c");
	assert_resolve_relative(&buf, "//a/", "//a/b/..");
	assert_resolve_relative(&buf, "//a/b/c", "//a/Q/../b/x/y/../../c");

651
	cl_git_pass(git_str_sets(&buf, "//a/b/../.."));
652
	cl_git_fail(git_fs_path_resolve_relative(&buf, 0));
653 654 655 656 657 658 659
#else
	assert_resolve_relative(&buf, "/a/b/c", "//a/b/c");
	assert_resolve_relative(&buf, "/a/", "//a/b/..");
	assert_resolve_relative(&buf, "/a/b/c", "//a/Q/../b/x/y/../../c");
	assert_resolve_relative(&buf, "/", "//a/b/../..");
#endif

660
	git_str_dispose(&buf);
661
}
662 663

#define assert_common_dirlen(i, p, q) \
664
	cl_assert_equal_i((i), git_fs_path_common_dirlen((p), (q)));
665

666
void test_path__16_resolve_relative(void)
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
{
	assert_common_dirlen(0, "", "");
	assert_common_dirlen(0, "", "bar.txt");
	assert_common_dirlen(0, "foo.txt", "bar.txt");
	assert_common_dirlen(0, "foo.txt", "");
	assert_common_dirlen(0, "foo/bar.txt", "bar/foo.txt");
	assert_common_dirlen(0, "foo/bar.txt", "../foo.txt");

	assert_common_dirlen(1, "/one.txt", "/two.txt");
	assert_common_dirlen(4, "foo/one.txt", "foo/two.txt");
	assert_common_dirlen(5, "/foo/one.txt", "/foo/two.txt");

	assert_common_dirlen(6, "a/b/c/foo.txt", "a/b/c/d/e/bar.txt");
	assert_common_dirlen(7, "/a/b/c/foo.txt", "/a/b/c/d/e/bar.txt");
}
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696

static void fix_path(git_str *s)
{
#ifndef GIT_WIN32
	GIT_UNUSED(s);
#else
	char* c;

	for (c = s->ptr; *c; c++) {
		if (*c == '/')
			*c = '\\';
	}
#endif
}

697
void test_path__find_exe_in_path(void)
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
{
	char *orig_path;
	git_str sandbox_path = GIT_STR_INIT;
	git_str new_path = GIT_STR_INIT, full_path = GIT_STR_INIT,
	        dummy_path = GIT_STR_INIT;

#ifdef GIT_WIN32
	static const char *bogus_path_1 = "c:\\does\\not\\exist\\";
	static const char *bogus_path_2 = "e:\\non\\existent";
#else
	static const char *bogus_path_1 = "/this/path/does/not/exist/";
	static const char *bogus_path_2 = "/non/existent";
#endif

	orig_path = cl_getenv("PATH");

	git_str_puts(&sandbox_path, clar_sandbox_path());
	git_str_joinpath(&dummy_path, sandbox_path.ptr, "dummmmmmmy_libgit2_file");
	cl_git_rewritefile(dummy_path.ptr, "this is a dummy file");

	fix_path(&sandbox_path);
	fix_path(&dummy_path);

	cl_git_pass(git_str_printf(&new_path, "%s%c%s%c%s%c%s",
		bogus_path_1, GIT_PATH_LIST_SEPARATOR,
		orig_path, GIT_PATH_LIST_SEPARATOR,
		sandbox_path.ptr, GIT_PATH_LIST_SEPARATOR,
		bogus_path_2));

	check_setenv("PATH", new_path.ptr);

	cl_git_fail_with(GIT_ENOTFOUND, git_fs_path_find_executable(&full_path, "this_file_does_not_exist"));
	cl_git_pass(git_fs_path_find_executable(&full_path, "dummmmmmmy_libgit2_file"));

	cl_assert_equal_s(full_path.ptr, dummy_path.ptr);

	git_str_dispose(&full_path);
	git_str_dispose(&new_path);
	git_str_dispose(&dummy_path);
	git_str_dispose(&sandbox_path);
	git__free(orig_path);
}