gitstr.c 28.9 KB
Newer Older
1
#include "clar_libgit2.h"
2
#include "futils.h"
3 4 5 6 7 8 9 10 11 12 13

#define TESTSTR "Have you seen that? Have you seeeen that??"
const char *test_string = TESTSTR;
const char *test_string_x2 = TESTSTR TESTSTR;

#define TESTSTR_4096 REP1024("1234")
#define TESTSTR_8192 REP1024("12341234")
const char *test_4096 = TESTSTR_4096;
const char *test_8192 = TESTSTR_8192;

/* test basic data concatenation */
14
void test_gitstr__0(void)
15
{
16
	git_str buf = GIT_STR_INIT;
17 18 19

	cl_assert(buf.size == 0);

20 21 22
	git_str_puts(&buf, test_string);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_string, git_str_cstr(&buf));
23

24 25 26
	git_str_puts(&buf, test_string);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_string_x2, git_str_cstr(&buf));
27

28
	git_str_dispose(&buf);
29 30
}

31
/* test git_str_printf */
32
void test_gitstr__1(void)
33
{
34
	git_str buf = GIT_STR_INIT;
35

36 37 38
	git_str_printf(&buf, "%s %s %d ", "shoop", "da", 23);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s("shoop da 23 ", git_str_cstr(&buf));
39

40 41 42
	git_str_printf(&buf, "%s %d", "woop", 42);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s("shoop da 23 woop 42", git_str_cstr(&buf));
43

44
	git_str_dispose(&buf);
45 46 47
}

/* more thorough test of concatenation options */
48
void test_gitstr__2(void)
49
{
50
	git_str buf = GIT_STR_INIT;
51
	int i;
52
	char data[128];
53 54 55 56

	cl_assert(buf.size == 0);

	/* this must be safe to do */
57
	git_str_dispose(&buf);
58 59 60 61
	cl_assert(buf.size == 0);
	cl_assert(buf.asize == 0);

	/* empty buffer should be empty string */
62
	cl_assert_equal_s("", git_str_cstr(&buf));
63
	cl_assert(buf.size == 0);
64
	/* cl_assert(buf.asize == 0); -- should not assume what git_str does */
65 66

	/* free should set us back to the beginning */
67
	git_str_dispose(&buf);
68 69 70 71
	cl_assert(buf.size == 0);
	cl_assert(buf.asize == 0);

	/* add letter */
72 73 74
	git_str_putc(&buf, '+');
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s("+", git_str_cstr(&buf));
75 76

	/* add letter again */
77 78 79
	git_str_putc(&buf, '+');
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s("++", git_str_cstr(&buf));
80 81 82

	/* let's try that a few times */
	for (i = 0; i < 16; ++i) {
83 84
		git_str_putc(&buf, '+');
		cl_assert(git_str_oom(&buf) == 0);
85
	}
86
	cl_assert_equal_s("++++++++++++++++++", git_str_cstr(&buf));
87

88
	git_str_dispose(&buf);
89 90

	/* add data */
91 92 93
	git_str_put(&buf, "xo", 2);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s("xo", git_str_cstr(&buf));
94 95

	/* add letter again */
96 97 98
	git_str_put(&buf, "xo", 2);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s("xoxo", git_str_cstr(&buf));
99 100 101

	/* let's try that a few times */
	for (i = 0; i < 16; ++i) {
102 103
		git_str_put(&buf, "xo", 2);
		cl_assert(git_str_oom(&buf) == 0);
104
	}
105
	cl_assert_equal_s("xoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxo",
106
					   git_str_cstr(&buf));
107

108
	git_str_dispose(&buf);
109 110

	/* set to string */
111 112 113
	git_str_sets(&buf, test_string);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_string, git_str_cstr(&buf));
114 115

	/* append string */
116 117 118
	git_str_puts(&buf, test_string);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_string_x2, git_str_cstr(&buf));
119 120

	/* set to string again (should overwrite - not append) */
121 122 123
	git_str_sets(&buf, test_string);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_string, git_str_cstr(&buf));
124 125

	/* test clear */
126 127
	git_str_clear(&buf);
	cl_assert_equal_s("", git_str_cstr(&buf));
128

129
	git_str_dispose(&buf);
130 131

	/* test extracting data into buffer */
132 133
	git_str_puts(&buf, REP4("0123456789"));
	cl_assert(git_str_oom(&buf) == 0);
134

135
	git_str_copy_cstr(data, sizeof(data), &buf);
136
	cl_assert_equal_s(REP4("0123456789"), data);
137
	git_str_copy_cstr(data, 11, &buf);
138
	cl_assert_equal_s("0123456789", data);
139
	git_str_copy_cstr(data, 3, &buf);
140
	cl_assert_equal_s("01", data);
141
	git_str_copy_cstr(data, 1, &buf);
142
	cl_assert_equal_s("", data);
143

144
	git_str_copy_cstr(data, sizeof(data), &buf);
145
	cl_assert_equal_s(REP4("0123456789"), data);
146

147 148
	git_str_sets(&buf, REP256("x"));
	git_str_copy_cstr(data, sizeof(data), &buf);
149
	/* since sizeof(data) == 128, only 127 bytes should be copied */
150
	cl_assert_equal_s(REP4(REP16("x")) REP16("x") REP16("x")
151
					   REP16("x") "xxxxxxxxxxxxxxx", data);
152

153
	git_str_dispose(&buf);
154

155
	git_str_copy_cstr(data, sizeof(data), &buf);
156
	cl_assert_equal_s("", data);
157 158 159
}

/* let's do some tests with larger buffers to push our limits */
160
void test_gitstr__3(void)
161
{
162
	git_str buf = GIT_STR_INIT;
163 164

	/* set to string */
165 166 167
	git_str_set(&buf, test_4096, 4096);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_4096, git_str_cstr(&buf));
168 169

	/* append string */
170 171 172
	git_str_puts(&buf, test_4096);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_8192, git_str_cstr(&buf));
173 174

	/* set to string again (should overwrite - not append) */
175 176 177
	git_str_set(&buf, test_4096, 4096);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(test_4096, git_str_cstr(&buf));
178

179
	git_str_dispose(&buf);
180 181 182
}

/* let's try some producer/consumer tests */
183
void test_gitstr__4(void)
184
{
185
	git_str buf = GIT_STR_INIT;
186 187 188
	int i;

	for (i = 0; i < 10; ++i) {
189 190 191 192
		git_str_puts(&buf, "1234"); /* add 4 */
		cl_assert(git_str_oom(&buf) == 0);
		git_str_consume(&buf, buf.ptr + 2); /* eat the first two */
		cl_assert(strlen(git_str_cstr(&buf)) == (size_t)((i + 1) * 2));
193 194
	}
	/* we have appended 1234 10x and removed the first 20 letters */
195
	cl_assert_equal_s("12341234123412341234", git_str_cstr(&buf));
196

197 198
	git_str_consume(&buf, NULL);
	cl_assert_equal_s("12341234123412341234", git_str_cstr(&buf));
199

200 201
	git_str_consume(&buf, "invalid pointer");
	cl_assert_equal_s("12341234123412341234", git_str_cstr(&buf));
202

203 204
	git_str_consume(&buf, buf.ptr);
	cl_assert_equal_s("12341234123412341234", git_str_cstr(&buf));
205

206 207
	git_str_consume(&buf, buf.ptr + 1);
	cl_assert_equal_s("2341234123412341234", git_str_cstr(&buf));
208

209 210
	git_str_consume(&buf, buf.ptr + buf.size);
	cl_assert_equal_s("", git_str_cstr(&buf));
211

212
	git_str_dispose(&buf);
213 214 215 216 217 218 219 220
}


static void
check_buf_append(
	const char* data_a,
	const char* data_b,
	const char* expected_data,
221 222
	size_t expected_size,
	size_t expected_asize)
223
{
224
	git_str tgt = GIT_STR_INIT;
225

226 227 228 229 230
	git_str_sets(&tgt, data_a);
	cl_assert(git_str_oom(&tgt) == 0);
	git_str_puts(&tgt, data_b);
	cl_assert(git_str_oom(&tgt) == 0);
	cl_assert_equal_s(expected_data, git_str_cstr(&tgt));
231
	cl_assert_equal_i(tgt.size, expected_size);
232
	if (expected_asize > 0)
233
		cl_assert_equal_i(tgt.asize, expected_asize);
234

235
	git_str_dispose(&tgt);
236 237 238 239 240 241 242 243 244 245 246 247 248
}

static void
check_buf_append_abc(
	const char* buf_a,
	const char* buf_b,
	const char* buf_c,
	const char* expected_ab,
	const char* expected_abc,
	const char* expected_abca,
	const char* expected_abcab,
	const char* expected_abcabc)
{
249
	git_str buf = GIT_STR_INIT;
250

251 252 253
	git_str_sets(&buf, buf_a);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(buf_a, git_str_cstr(&buf));
254

255 256 257
	git_str_puts(&buf, buf_b);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected_ab, git_str_cstr(&buf));
258

259 260 261
	git_str_puts(&buf, buf_c);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected_abc, git_str_cstr(&buf));
262

263 264 265
	git_str_puts(&buf, buf_a);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected_abca, git_str_cstr(&buf));
266

267 268 269
	git_str_puts(&buf, buf_b);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected_abcab, git_str_cstr(&buf));
270

271 272 273
	git_str_puts(&buf, buf_c);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected_abcabc, git_str_cstr(&buf));
274

275
	git_str_dispose(&buf);
276 277 278
}

/* more variations on append tests */
279
void test_gitstr__5(void)
280
{
281 282
	check_buf_append("", "", "", 0, 0);
	check_buf_append("a", "", "a", 1, 0);
283
	check_buf_append("", "a", "a", 1, 8);
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	check_buf_append("", "a", "a", 1, 8);
	check_buf_append("a", "b", "ab", 2, 8);
	check_buf_append("", "abcdefgh", "abcdefgh", 8, 16);
	check_buf_append("abcdefgh", "", "abcdefgh", 8, 16);

	/* buffer with starting asize will grow to:
	 *  1 ->  2,  2 ->  3,  3 ->  5,  4 ->  6,  5 ->  8,  6 ->  9,
	 *  7 -> 11,  8 -> 12,  9 -> 14, 10 -> 15, 11 -> 17, 12 -> 18,
	 * 13 -> 20, 14 -> 21, 15 -> 23, 16 -> 24, 17 -> 26, 18 -> 27,
	 * 19 -> 29, 20 -> 30, 21 -> 32, 22 -> 33, 23 -> 35, 24 -> 36,
	 * ...
	 * follow sequence until value > target size,
	 * then round up to nearest multiple of 8.
	 */

	check_buf_append("abcdefgh", "/", "abcdefgh/", 9, 16);
300
	check_buf_append("abcdefgh", "ijklmno", "abcdefghijklmno", 15, 16);
301 302 303 304 305 306
	check_buf_append("abcdefgh", "ijklmnop", "abcdefghijklmnop", 16, 24);
	check_buf_append("0123456789", "0123456789",
					 "01234567890123456789", 20, 24);
	check_buf_append(REP16("x"), REP16("o"),
					 REP16("x") REP16("o"), 32, 40);

307
	check_buf_append(test_4096, "", test_4096, 4096, 4104);
308
	check_buf_append(test_4096, test_4096, test_8192, 8192, 8200);
309 310 311 312 313 314 315 316 317 318 319 320 321

	/* check sequences of appends */
	check_buf_append_abc("a", "b", "c",
						 "ab", "abc", "abca", "abcab", "abcabc");
	check_buf_append_abc("a1", "b2", "c3",
						 "a1b2", "a1b2c3", "a1b2c3a1",
						 "a1b2c3a1b2", "a1b2c3a1b2c3");
	check_buf_append_abc("a1/", "b2/", "c3/",
						 "a1/b2/", "a1/b2/c3/", "a1/b2/c3/a1/",
						 "a1/b2/c3/a1/b2/", "a1/b2/c3/a1/b2/c3/");
}

/* test swap */
322
void test_gitstr__6(void)
323
{
324 325
	git_str a = GIT_STR_INIT;
	git_str b = GIT_STR_INIT;
326

327 328 329 330
	git_str_sets(&a, "foo");
	cl_assert(git_str_oom(&a) == 0);
	git_str_sets(&b, "bar");
	cl_assert(git_str_oom(&b) == 0);
331

332 333
	cl_assert_equal_s("foo", git_str_cstr(&a));
	cl_assert_equal_s("bar", git_str_cstr(&b));
334

335
	git_str_swap(&a, &b);
336

337 338
	cl_assert_equal_s("bar", git_str_cstr(&a));
	cl_assert_equal_s("foo", git_str_cstr(&b));
339

340 341
	git_str_dispose(&a);
	git_str_dispose(&b);
342 343 344
}


345
/* test detach/attach data */
346
void test_gitstr__7(void)
347
{
348
	const char *fun = "This is fun";
349
	git_str a = GIT_STR_INIT;
350 351
	char *b = NULL;

352 353 354
	git_str_sets(&a, "foo");
	cl_assert(git_str_oom(&a) == 0);
	cl_assert_equal_s("foo", git_str_cstr(&a));
355

356
	b = git_str_detach(&a);
357

358 359
	cl_assert_equal_s("foo", b);
	cl_assert_equal_s("", a.ptr);
360 361
	git__free(b);

362
	b = git_str_detach(&a);
363

364 365
	cl_assert_equal_s(NULL, b);
	cl_assert_equal_s("", a.ptr);
366

367
	git_str_dispose(&a);
368 369

	b = git__strdup(fun);
370
	git_str_attach(&a, b, 0);
371

372
	cl_assert_equal_s(fun, a.ptr);
373 374
	cl_assert(a.size == strlen(fun));
	cl_assert(a.asize == strlen(fun) + 1);
375

376
	git_str_dispose(&a);
377 378

	b = git__strdup(fun);
379
	git_str_attach(&a, b, strlen(fun) + 1);
380

381
	cl_assert_equal_s(fun, a.ptr);
382 383
	cl_assert(a.size == strlen(fun));
	cl_assert(a.asize == strlen(fun) + 1);
384

385
	git_str_dispose(&a);
386 387 388 389
}


static void
390 391 392 393 394 395
check_joinbuf_2(
	const char *a,
	const char *b,
	const char *expected)
{
	char sep = '/';
396
	git_str buf = GIT_STR_INIT;
397

398 399 400 401
	git_str_join(&buf, sep, a, b);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected, git_str_cstr(&buf));
	git_str_dispose(&buf);
402 403 404
}

static void
405 406 407 408 409 410 411
check_joinbuf_overlapped(
	const char *oldval,
	int ofs_a,
	const char *b,
	const char *expected)
{
	char sep = '/';
412
	git_str buf = GIT_STR_INIT;
413

414 415 416 417 418
	git_str_sets(&buf, oldval);
	git_str_join(&buf, sep, buf.ptr + ofs_a, b);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected, git_str_cstr(&buf));
	git_str_dispose(&buf);
419 420 421
}

static void
422
check_joinbuf_n_2(
423 424 425 426 427
	const char *a,
	const char *b,
	const char *expected)
{
	char sep = '/';
428
	git_str buf = GIT_STR_INIT;
429

430 431
	git_str_sets(&buf, a);
	cl_assert(git_str_oom(&buf) == 0);
432

433 434 435
	git_str_join_n(&buf, sep, 1, b);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected, git_str_cstr(&buf));
436

437
	git_str_dispose(&buf);
438 439 440
}

static void
441
check_joinbuf_n_4(
442 443 444 445 446 447 448
	const char *a,
	const char *b,
	const char *c,
	const char *d,
	const char *expected)
{
	char sep = ';';
449 450 451 452 453
	git_str buf = GIT_STR_INIT;
	git_str_join_n(&buf, sep, 4, a, b, c, d);
	cl_assert(git_str_oom(&buf) == 0);
	cl_assert_equal_s(expected, git_str_cstr(&buf));
	git_str_dispose(&buf);
454 455 456
}

/* test join */
457
void test_gitstr__8(void)
458
{
459
	git_str a = GIT_STR_INIT;
460

461 462 463
	git_str_join_n(&a, '/', 1, "foo");
	cl_assert(git_str_oom(&a) == 0);
	cl_assert_equal_s("foo", git_str_cstr(&a));
464

465 466 467
	git_str_join_n(&a, '/', 1, "bar");
	cl_assert(git_str_oom(&a) == 0);
	cl_assert_equal_s("foo/bar", git_str_cstr(&a));
468

469 470 471
	git_str_join_n(&a, '/', 1, "baz");
	cl_assert(git_str_oom(&a) == 0);
	cl_assert_equal_s("foo/bar/baz", git_str_cstr(&a));
472

473
	git_str_dispose(&a);
474

475 476 477
	check_joinbuf_2(NULL, "", "");
	check_joinbuf_2(NULL, "a", "a");
	check_joinbuf_2(NULL, "/a", "/a");
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
	check_joinbuf_2("", "", "");
	check_joinbuf_2("", "a", "a");
	check_joinbuf_2("", "/a", "/a");
	check_joinbuf_2("a", "", "a/");
	check_joinbuf_2("a", "/", "a/");
	check_joinbuf_2("a", "b", "a/b");
	check_joinbuf_2("/", "a", "/a");
	check_joinbuf_2("/", "", "/");
	check_joinbuf_2("/a", "/b", "/a/b");
	check_joinbuf_2("/a", "/b/", "/a/b/");
	check_joinbuf_2("/a/", "b/", "/a/b/");
	check_joinbuf_2("/a/", "/b/", "/a/b/");
	check_joinbuf_2("/a/", "//b/", "/a/b/");
	check_joinbuf_2("/abcd", "/defg", "/abcd/defg");
	check_joinbuf_2("/abcd", "/defg/", "/abcd/defg/");
	check_joinbuf_2("/abcd/", "defg/", "/abcd/defg/");
	check_joinbuf_2("/abcd/", "/defg/", "/abcd/defg/");

496 497 498 499 500 501 502 503 504 505 506 507 508 509
	check_joinbuf_overlapped("abcd", 0, "efg", "abcd/efg");
	check_joinbuf_overlapped("abcd", 1, "efg", "bcd/efg");
	check_joinbuf_overlapped("abcd", 2, "efg", "cd/efg");
	check_joinbuf_overlapped("abcd", 3, "efg", "d/efg");
	check_joinbuf_overlapped("abcd", 4, "efg", "efg");
	check_joinbuf_overlapped("abc/", 2, "efg", "c/efg");
	check_joinbuf_overlapped("abc/", 3, "efg", "/efg");
	check_joinbuf_overlapped("abc/", 4, "efg", "efg");
	check_joinbuf_overlapped("abcd", 3, "", "d/");
	check_joinbuf_overlapped("abcd", 4, "", "");
	check_joinbuf_overlapped("abc/", 2, "", "c/");
	check_joinbuf_overlapped("abc/", 3, "", "/");
	check_joinbuf_overlapped("abc/", 4, "", "");

510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
	check_joinbuf_n_2("", "", "");
	check_joinbuf_n_2("", "a", "a");
	check_joinbuf_n_2("", "/a", "/a");
	check_joinbuf_n_2("a", "", "a/");
	check_joinbuf_n_2("a", "/", "a/");
	check_joinbuf_n_2("a", "b", "a/b");
	check_joinbuf_n_2("/", "a", "/a");
	check_joinbuf_n_2("/", "", "/");
	check_joinbuf_n_2("/a", "/b", "/a/b");
	check_joinbuf_n_2("/a", "/b/", "/a/b/");
	check_joinbuf_n_2("/a/", "b/", "/a/b/");
	check_joinbuf_n_2("/a/", "/b/", "/a/b/");
	check_joinbuf_n_2("/abcd", "/defg", "/abcd/defg");
	check_joinbuf_n_2("/abcd", "/defg/", "/abcd/defg/");
	check_joinbuf_n_2("/abcd/", "defg/", "/abcd/defg/");
	check_joinbuf_n_2("/abcd/", "/defg/", "/abcd/defg/");

	check_joinbuf_n_4("", "", "", "", "");
	check_joinbuf_n_4("", "a", "", "", "a;");
	check_joinbuf_n_4("a", "", "", "", "a;");
	check_joinbuf_n_4("", "", "", "a", "a");
	check_joinbuf_n_4("a", "b", "", ";c;d;", "a;b;c;d;");
	check_joinbuf_n_4("a", "b", "", ";c;d", "a;b;c;d");
	check_joinbuf_n_4("abcd", "efgh", "ijkl", "mnop", "abcd;efgh;ijkl;mnop");
	check_joinbuf_n_4("abcd;", "efgh;", "ijkl;", "mnop;", "abcd;efgh;ijkl;mnop;");
	check_joinbuf_n_4(";abcd;", ";efgh;", ";ijkl;", ";mnop;", ";abcd;efgh;ijkl;mnop;");
536 537
}

538
void test_gitstr__9(void)
539
{
540
	git_str buf = GIT_STR_INIT;
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570

	/* just some exhaustive tests of various separator placement */
	char *a[] = { "", "-", "a-", "-a", "-a-" };
	char *b[] = { "", "-", "b-", "-b", "-b-" };
	char sep[] = { 0, '-', '/' };
	char *expect_null[] = { "",    "-",     "a-",     "-a",     "-a-",
							"-",   "--",    "a--",    "-a-",    "-a--",
							"b-",  "-b-",   "a-b-",   "-ab-",   "-a-b-",
							"-b",  "--b",   "a--b",   "-a-b",   "-a--b",
							"-b-", "--b-",  "a--b-",  "-a-b-",  "-a--b-" };
	char *expect_dash[] = { "",    "-",     "a-",     "-a-",    "-a-",
							"-",   "-",     "a-",     "-a-",    "-a-",
							"b-",  "-b-",   "a-b-",   "-a-b-",  "-a-b-",
							"-b",  "-b",    "a-b",    "-a-b",   "-a-b",
							"-b-", "-b-",   "a-b-",   "-a-b-",  "-a-b-" };
	char *expect_slas[] = { "",    "-/",    "a-/",    "-a/",    "-a-/",
							"-",   "-/-",   "a-/-",   "-a/-",   "-a-/-",
							"b-",  "-/b-",  "a-/b-",  "-a/b-",  "-a-/b-",
							"-b",  "-/-b",  "a-/-b",  "-a/-b",  "-a-/-b",
							"-b-", "-/-b-", "a-/-b-", "-a/-b-", "-a-/-b-" };
	char **expect_values[] = { expect_null, expect_dash, expect_slas };
	char separator, **expect;
	unsigned int s, i, j;

	for (s = 0; s < sizeof(sep) / sizeof(char); ++s) {
		separator = sep[s];
		expect = expect_values[s];

		for (j = 0; j < sizeof(b) / sizeof(char*); ++j) {
			for (i = 0; i < sizeof(a) / sizeof(char*); ++i) {
571
				git_str_join(&buf, separator, a[i], b[j]);
572
				cl_assert_equal_s(*expect, buf.ptr);
573 574 575 576 577
				expect++;
			}
		}
	}

578
	git_str_dispose(&buf);
579
}
580

581
void test_gitstr__10(void)
582
{
583
	git_str a = GIT_STR_INIT;
584

585
	cl_git_pass(git_str_join_n(&a, '/', 1, "test"));
586
	cl_assert_equal_s(a.ptr, "test");
587
	cl_git_pass(git_str_join_n(&a, '/', 1, "string"));
588
	cl_assert_equal_s(a.ptr, "test/string");
589 590
	git_str_clear(&a);
	cl_git_pass(git_str_join_n(&a, '/', 3, "test", "string", "join"));
591
	cl_assert_equal_s(a.ptr, "test/string/join");
592
	cl_git_pass(git_str_join_n(&a, '/', 2, a.ptr, "more"));
593
	cl_assert_equal_s(a.ptr, "test/string/join/test/string/join/more");
594

595
	git_str_dispose(&a);
596
}
597

598
void test_gitstr__join3(void)
599
{
600
	git_str a = GIT_STR_INIT;
601

602
	cl_git_pass(git_str_join3(&a, '/', "test", "string", "join"));
603
	cl_assert_equal_s("test/string/join", a.ptr);
604
	cl_git_pass(git_str_join3(&a, '/', "test/", "string", "join"));
605
	cl_assert_equal_s("test/string/join", a.ptr);
606
	cl_git_pass(git_str_join3(&a, '/', "test/", "/string", "join"));
607
	cl_assert_equal_s("test/string/join", a.ptr);
608
	cl_git_pass(git_str_join3(&a, '/', "test/", "/string/", "join"));
609
	cl_assert_equal_s("test/string/join", a.ptr);
610
	cl_git_pass(git_str_join3(&a, '/', "test/", "/string/", "/join"));
611 612
	cl_assert_equal_s("test/string/join", a.ptr);

613
	cl_git_pass(git_str_join3(&a, '/', "", "string", "join"));
614
	cl_assert_equal_s("string/join", a.ptr);
615
	cl_git_pass(git_str_join3(&a, '/', "", "string/", "join"));
616
	cl_assert_equal_s("string/join", a.ptr);
617
	cl_git_pass(git_str_join3(&a, '/', "", "string/", "/join"));
618 619
	cl_assert_equal_s("string/join", a.ptr);

620
	cl_git_pass(git_str_join3(&a, '/', "string", "", "join"));
621
	cl_assert_equal_s("string/join", a.ptr);
622
	cl_git_pass(git_str_join3(&a, '/', "string/", "", "join"));
623
	cl_assert_equal_s("string/join", a.ptr);
624
	cl_git_pass(git_str_join3(&a, '/', "string/", "", "/join"));
625 626
	cl_assert_equal_s("string/join", a.ptr);

627
	git_str_dispose(&a);
628 629
}

630
void test_gitstr__11(void)
631
{
632
	git_str a = GIT_STR_INIT;
633 634 635 636 637 638 639 640
	char *t1[] = { "nothing", "in", "common" };
	char *t2[] = { "something", "something else", "some other" };
	char *t3[] = { "something", "some fun", "no fun" };
	char *t4[] = { "happy", "happier", "happiest" };
	char *t5[] = { "happiest", "happier", "happy" };
	char *t6[] = { "no", "nope", "" };
	char *t7[] = { "", "doesn't matter" };

641
	cl_git_pass(git_str_common_prefix(&a, t1, 3));
642 643
	cl_assert_equal_s(a.ptr, "");

644
	cl_git_pass(git_str_common_prefix(&a, t2, 3));
645 646
	cl_assert_equal_s(a.ptr, "some");

647
	cl_git_pass(git_str_common_prefix(&a, t3, 3));
648 649
	cl_assert_equal_s(a.ptr, "");

650
	cl_git_pass(git_str_common_prefix(&a, t4, 3));
651 652
	cl_assert_equal_s(a.ptr, "happ");

653
	cl_git_pass(git_str_common_prefix(&a, t5, 3));
654 655
	cl_assert_equal_s(a.ptr, "happ");

656
	cl_git_pass(git_str_common_prefix(&a, t6, 3));
657 658
	cl_assert_equal_s(a.ptr, "");

659
	cl_git_pass(git_str_common_prefix(&a, t7, 3));
660 661
	cl_assert_equal_s(a.ptr, "");

662
	git_str_dispose(&a);
663
}
664

665
void test_gitstr__rfind_variants(void)
666
{
667
	git_str a = GIT_STR_INIT;
668 669
	ssize_t len;

670
	cl_git_pass(git_str_sets(&a, "/this/is/it/"));
671

672
	len = (ssize_t)git_str_len(&a);
673

674 675
	cl_assert(git_str_rfind(&a, '/') == len - 1);
	cl_assert(git_str_rfind_next(&a, '/') == len - 4);
676

677 678
	cl_assert(git_str_rfind(&a, 'i') == len - 3);
	cl_assert(git_str_rfind_next(&a, 'i') == len - 3);
679

680 681
	cl_assert(git_str_rfind(&a, 'h') == 2);
	cl_assert(git_str_rfind_next(&a, 'h') == 2);
682

683 684
	cl_assert(git_str_rfind(&a, 'q') == -1);
	cl_assert(git_str_rfind_next(&a, 'q') == -1);
685

686
	git_str_dispose(&a);
687 688
}

689
void test_gitstr__puts_escaped(void)
690
{
691
	git_str a = GIT_STR_INIT;
692

693 694
	git_str_clear(&a);
	cl_git_pass(git_str_puts_escaped(&a, "this is a test", "", ""));
695 696
	cl_assert_equal_s("this is a test", a.ptr);

697 698
	git_str_clear(&a);
	cl_git_pass(git_str_puts_escaped(&a, "this is a test", "t", "\\"));
699 700
	cl_assert_equal_s("\\this is a \\tes\\t", a.ptr);

701 702
	git_str_clear(&a);
	cl_git_pass(git_str_puts_escaped(&a, "this is a test", "i ", "__"));
703 704
	cl_assert_equal_s("th__is__ __is__ a__ test", a.ptr);

705 706
	git_str_clear(&a);
	cl_git_pass(git_str_puts_escape_regex(&a, "^match\\s*[A-Z]+.*"));
707 708
	cl_assert_equal_s("\\^match\\\\s\\*\\[A-Z\\]\\+\\.\\*", a.ptr);

709
	git_str_dispose(&a);
710
}
711 712

static void assert_unescape(char *expected, char *to_unescape) {
713
	git_str buf = GIT_STR_INIT;
714

715 716
	cl_git_pass(git_str_sets(&buf, to_unescape));
	git_str_unescape(&buf);
717
	cl_assert_equal_s(expected, buf.ptr);
718
	cl_assert_equal_sz(strlen(expected), buf.size);
719

720
	git_str_dispose(&buf);
721 722
}

723
void test_gitstr__unescape(void)
724 725 726 727 728 729 730
{
	assert_unescape("Escaped\\", "Es\\ca\\ped\\");
	assert_unescape("Es\\caped\\", "Es\\\\ca\\ped\\\\");
	assert_unescape("\\", "\\");
	assert_unescape("\\", "\\\\");
	assert_unescape("", "");
}
731

732
void test_gitstr__encode_base64(void)
733
{
734
	git_str buf = GIT_STR_INIT;
735 736 737 738 739 740 741 742

	/*     t  h  i  s
	 * 0x 74 68 69 73
     * 0b 01110100 01101000 01101001 01110011
	 * 0b 011101 000110 100001 101001 011100 110000
	 * 0x 1d 06 21 29 1c 30
	 *     d  G  h  p  c  w
	 */
743
	cl_git_pass(git_str_encode_base64(&buf, "this", 4));
744 745
	cl_assert_equal_s("dGhpcw==", buf.ptr);

746 747
	git_str_clear(&buf);
	cl_git_pass(git_str_encode_base64(&buf, "this!", 5));
748 749
	cl_assert_equal_s("dGhpcyE=", buf.ptr);

750 751
	git_str_clear(&buf);
	cl_git_pass(git_str_encode_base64(&buf, "this!\n", 6));
752 753
	cl_assert_equal_s("dGhpcyEK", buf.ptr);

754
	git_str_dispose(&buf);
755
}
756

757
void test_gitstr__decode_base64(void)
758
{
759
	git_str buf = GIT_STR_INIT;
760

761
	cl_git_pass(git_str_decode_base64(&buf, "dGhpcw==", 8));
762 763
	cl_assert_equal_s("this", buf.ptr);

764 765
	git_str_clear(&buf);
	cl_git_pass(git_str_decode_base64(&buf, "dGhpcyE=", 8));
766 767
	cl_assert_equal_s("this!", buf.ptr);

768 769
	git_str_clear(&buf);
	cl_git_pass(git_str_decode_base64(&buf, "dGhpcyEK", 8));
770 771
	cl_assert_equal_s("this!\n", buf.ptr);

772
	cl_git_fail(git_str_decode_base64(&buf, "This is not a valid base64 string!!!", 36));
773 774
	cl_assert_equal_s("this!\n", buf.ptr);

775
	git_str_dispose(&buf);
776 777
}

778
void test_gitstr__encode_base85(void)
779
{
780
	git_str buf = GIT_STR_INIT;
781

782
	cl_git_pass(git_str_encode_base85(&buf, "this", 4));
783
	cl_assert_equal_s("bZBXF", buf.ptr);
784
	git_str_clear(&buf);
785

786
	cl_git_pass(git_str_encode_base85(&buf, "two rnds", 8));
787
	cl_assert_equal_s("ba!tca&BaE", buf.ptr);
788
	git_str_clear(&buf);
789

790
	cl_git_pass(git_str_encode_base85(&buf, "this is base 85 encoded",
791 792
		strlen("this is base 85 encoded")));
	cl_assert_equal_s("bZBXFAZc?TVqtS-AUHK3Wo~0{WMyOk", buf.ptr);
793
	git_str_clear(&buf);
794

795
	git_str_dispose(&buf);
796 797
}

798
void test_gitstr__decode_base85(void)
799
{
800
	git_str buf = GIT_STR_INIT;
801

802
	cl_git_pass(git_str_decode_base85(&buf, "bZBXF", 5, 4));
803 804
	cl_assert_equal_sz(4, buf.size);
	cl_assert_equal_s("this", buf.ptr);
805
	git_str_clear(&buf);
806

807
	cl_git_pass(git_str_decode_base85(&buf, "ba!tca&BaE", 10, 8));
808 809
	cl_assert_equal_sz(8, buf.size);
	cl_assert_equal_s("two rnds", buf.ptr);
810
	git_str_clear(&buf);
811

812
	cl_git_pass(git_str_decode_base85(&buf, "bZBXFAZc?TVqtS-AUHK3Wo~0{WMyOk", 30, 23));
813 814
	cl_assert_equal_sz(23, buf.size);
	cl_assert_equal_s("this is base 85 encoded", buf.ptr);
815
	git_str_clear(&buf);
816

817
	git_str_dispose(&buf);
818 819
}

820
void test_gitstr__decode_base85_fails_gracefully(void)
821
{
822
	git_str buf = GIT_STR_INIT;
823

824
	git_str_puts(&buf, "foobar");
825

826 827 828 829
	cl_git_fail(git_str_decode_base85(&buf, "invalid charsZZ", 15, 42));
	cl_git_fail(git_str_decode_base85(&buf, "invalidchars__ ", 15, 42));
	cl_git_fail(git_str_decode_base85(&buf, "overflowZZ~~~~~", 15, 42));
	cl_git_fail(git_str_decode_base85(&buf, "truncated", 9, 42));
830 831
	cl_assert_equal_sz(6, buf.size);
	cl_assert_equal_s("foobar", buf.ptr);
832

833
	git_str_dispose(&buf);
834 835
}

836
void test_gitstr__classify_with_utf8(void)
837 838 839 840 841 842 843
{
	char *data0 = "Simple text\n";
	size_t data0len = 12;
	char *data1 = "Is that UTF-8 data I see…\nYep!\n";
	size_t data1len = 31;
	char *data2 = "Internal NUL!!!\000\n\nI see you!\n";
	size_t data2len = 29;
844 845
	char *data3 = "\xef\xbb\xbfThis is UTF-8 with a BOM.\n";
	size_t data3len = 20;
846
	git_str b;
847 848

	b.ptr = data0; b.size = b.asize = data0len;
849 850
	cl_assert(!git_str_is_binary(&b));
	cl_assert(!git_str_contains_nul(&b));
851 852

	b.ptr = data1; b.size = b.asize = data1len;
853 854
	cl_assert(!git_str_is_binary(&b));
	cl_assert(!git_str_contains_nul(&b));
855 856

	b.ptr = data2; b.size = b.asize = data2len;
857 858
	cl_assert(git_str_is_binary(&b));
	cl_assert(git_str_contains_nul(&b));
859 860

	b.ptr = data3; b.size = b.asize = data3len;
861 862
	cl_assert(!git_str_is_binary(&b));
	cl_assert(!git_str_contains_nul(&b));
863
}
864

865
#include "crlf.h"
866

867 868 869 870
#define check_buf(expected,buf) do { \
	cl_assert_equal_s(expected, buf.ptr); \
	cl_assert_equal_sz(strlen(expected), buf.size); } while (0)

871
void test_gitstr__lf_and_crlf_conversions(void)
872
{
873
	git_str src = GIT_STR_INIT, tgt = GIT_STR_INIT;
874 875 876

	/* LF source */

877
	git_str_sets(&src, "lf\nlf\nlf\nlf\n");
878

879
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
880 881
	check_buf("lf\r\nlf\r\nlf\r\nlf\r\n", tgt);

882
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
883
	check_buf(src.ptr, tgt);
884

885
	git_str_sets(&src, "\nlf\nlf\nlf\nlf\nlf");
886

887
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
888 889
	check_buf("\r\nlf\r\nlf\r\nlf\r\nlf\r\nlf", tgt);

890
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
891
	check_buf(src.ptr, tgt);
892 893 894

	/* CRLF source */

895
	git_str_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n");
896

897
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
898 899
	check_buf("crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n", tgt);

900
	git_str_sets(&src, "crlf\r\ncrlf\r\ncrlf\r\ncrlf\r\n");
901

902
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
903 904
	check_buf("crlf\ncrlf\ncrlf\ncrlf\n", tgt);

905
	git_str_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf");
906

907
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
908 909
	check_buf("\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf", tgt);

910
	git_str_sets(&src, "\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf\r\ncrlf");
911

912
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
913 914 915 916
	check_buf("\ncrlf\ncrlf\ncrlf\ncrlf\ncrlf", tgt);

	/* CRLF in LF text */

917
	git_str_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n");
918

919
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
920 921
	check_buf("\r\nlf\r\nlf\r\ncrlf\r\nlf\r\nlf\r\ncrlf\r\n", tgt);

922
	git_str_sets(&src, "\nlf\nlf\ncrlf\r\nlf\nlf\ncrlf\r\n");
923

924
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
925 926 927 928
	check_buf("\nlf\nlf\ncrlf\nlf\nlf\ncrlf\n", tgt);

	/* LF in CRLF text */

929
	git_str_sets(&src, "\ncrlf\r\ncrlf\r\nlf\ncrlf\r\ncrlf");
930

931
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
932 933
	check_buf("\r\ncrlf\r\ncrlf\r\nlf\r\ncrlf\r\ncrlf", tgt);

934
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
935 936 937 938
	check_buf("\ncrlf\ncrlf\nlf\ncrlf\ncrlf", tgt);

	/* bare CR test */

939
	git_str_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r");
940

941
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
942 943
	check_buf("\rcrlf\r\nlf\r\nlf\r\ncr\rcrlf\r\nlf\r\ncr\r", tgt);

944
	git_str_sets(&src, "\rcrlf\r\nlf\nlf\ncr\rcrlf\r\nlf\ncr\r");
945

946
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
947 948
	check_buf("\rcrlf\nlf\nlf\ncr\rcrlf\nlf\ncr\r", tgt);

949 950
	git_str_sets(&src, "\rcr\r");
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
951
	check_buf(src.ptr, tgt);
952
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
953 954
	check_buf("\rcr\r", tgt);

955 956
	git_str_dispose(&src);
	git_str_dispose(&tgt);
957 958 959

	/* blob correspondence tests */

960 961
	git_str_sets(&src, ALL_CRLF_TEXT_RAW);
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
962
	check_buf(ALL_CRLF_TEXT_AS_CRLF, tgt);
963 964
	git_str_sets(&src, ALL_CRLF_TEXT_RAW);
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
965
	check_buf(ALL_CRLF_TEXT_AS_LF, tgt);
966 967
	git_str_dispose(&src);
	git_str_dispose(&tgt);
968

969 970
	git_str_sets(&src, ALL_LF_TEXT_RAW);
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
971
	check_buf(ALL_LF_TEXT_AS_CRLF, tgt);
972 973
	git_str_sets(&src, ALL_LF_TEXT_RAW);
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
974
	check_buf(ALL_LF_TEXT_AS_LF, tgt);
975 976
	git_str_dispose(&src);
	git_str_dispose(&tgt);
977

978 979
	git_str_sets(&src, MORE_CRLF_TEXT_RAW);
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
980
	check_buf(MORE_CRLF_TEXT_AS_CRLF, tgt);
981 982
	git_str_sets(&src, MORE_CRLF_TEXT_RAW);
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
983
	check_buf(MORE_CRLF_TEXT_AS_LF, tgt);
984 985
	git_str_dispose(&src);
	git_str_dispose(&tgt);
986

987 988
	git_str_sets(&src, MORE_LF_TEXT_RAW);
	cl_git_pass(git_str_lf_to_crlf(&tgt, &src));
989
	check_buf(MORE_LF_TEXT_AS_CRLF, tgt);
990 991
	git_str_sets(&src, MORE_LF_TEXT_RAW);
	cl_git_pass(git_str_crlf_to_lf(&tgt, &src));
992
	check_buf(MORE_LF_TEXT_AS_LF, tgt);
993 994
	git_str_dispose(&src);
	git_str_dispose(&tgt);
995
}
996

997
void test_gitstr__dont_grow_borrowed(void)
998 999
{
	const char *somestring = "blah blah";
1000
	git_str buf = GIT_STR_INIT;
1001

1002
	git_str_attach_notowned(&buf, somestring, strlen(somestring) + 1);
1003 1004 1005 1006
	cl_assert_equal_p(somestring, buf.ptr);
	cl_assert_equal_i(0, buf.asize);
	cl_assert_equal_i(strlen(somestring) + 1, buf.size);

1007
	cl_git_fail_with(GIT_EINVALID, git_str_grow(&buf, 1024));
1008
}
1009

1010
void test_gitstr__dont_hit_infinite_loop_when_resizing(void)
1011
{
1012
	git_str buf = GIT_STR_INIT;
1013

1014
	cl_git_pass(git_str_puts(&buf, "foobar"));
1015 1016 1017 1018 1019 1020
	/*
	 * We do not care whether this succeeds or fails, which
	 * would depend on platform-specific allocation
	 * semantics. We only want to know that the function
	 * actually returns.
	 */
1021
	(void)git_str_try_grow(&buf, SIZE_MAX, true);
1022

1023
	git_str_dispose(&buf);
1024
}
1025

1026
void test_gitstr__avoid_printing_into_oom_buffer(void)
1027
{
1028
	git_str buf = GIT_STR_INIT;
1029 1030 1031

	/* Emulate OOM situation with a previous allocation */
	buf.asize = 8;
1032
	buf.ptr = git_str__oom;
1033 1034 1035 1036 1037

	/*
	 * Print the same string again. As the buffer still has
	 * an `asize` of 8 due to the previous print,
	 * `ENSURE_SIZE` would not try to reallocate the array at
1038
	 * all. As it didn't explicitly check for `git_str__oom`
1039
	 * in earlier versions, this would've resulted in it
1040 1041
	 * returning successfully and thus `git_str_puts` would
	 * just print into the `git_str__oom` array.
1042
	 */
1043
	cl_git_fail(git_str_puts(&buf, "foobar"));
1044
}