1 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "test-lib.h"
4 #include "array.h"
5 
test_p_strdup(void)6 static void test_p_strdup(void)
7 {
8 	test_begin("p_strdup()");
9 	test_assert(p_strdup(default_pool, NULL) == NULL);
10 
11 	const char *src = "foo";
12 	char *str = p_strdup(default_pool, src);
13 	test_assert(str != src && str != NULL && strcmp(src, str) == 0);
14 	p_free(default_pool, str);
15 
16 	test_end();
17 }
18 
test_p_strndup(void)19 static void test_p_strndup(void)
20 {
21 	struct {
22 		const char *input;
23 		const char *output;
24 		size_t len;
25 	} tests[] = {
26 		{ "foo", "fo", 2 },
27 		{ "foo", "foo", 3 },
28 		{ "foo", "foo", 4 },
29 		{ "foo\0more", "foo", 8 },
30 	};
31 	test_begin("p_strndup()");
32 
33 	for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
34 		char *str = p_strndup(default_pool, tests[i].input,
35 				      tests[i].len);
36 		test_assert_strcmp_idx(str, tests[i].output, i);
37 		p_free(default_pool, str);
38 	}
39 	test_end();
40 }
41 
test_p_strdup_empty(void)42 static void test_p_strdup_empty(void)
43 {
44 	test_begin("p_strdup_empty()");
45 	test_assert(p_strdup_empty(default_pool, NULL) == NULL);
46 	test_assert(p_strdup_empty(default_pool, "") == NULL);
47 
48 	const char *src = "foo";
49 	char *str = p_strdup_empty(default_pool, src);
50 	test_assert(str != src && str != NULL && strcmp(src, str) == 0);
51 	p_free(default_pool, str);
52 
53 	test_end();
54 }
55 
test_p_strdup_until(void)56 static void test_p_strdup_until(void)
57 {
58 	const char src[] = "foo\0bar";
59 	char *str;
60 
61 	test_begin("p_strdup_until()");
62 	str = p_strdup_until(default_pool, src, src+2);
63 	test_assert(strcmp(str, "fo") == 0);
64 	p_free(default_pool, str);
65 
66 	str = p_strdup_until(default_pool, src, src+3);
67 	test_assert(strcmp(str, "foo") == 0);
68 	p_free(default_pool, str);
69 
70 	/* \0 is ignored */
71 	str = p_strdup_until(default_pool, src, src+7);
72 	test_assert(memcmp(str, src, sizeof(src)) == 0);
73 	p_free(default_pool, str);
74 
75 	str = p_strdup_until(default_pool, src, src+8);
76 	test_assert(memcmp(str, src, sizeof(src)) == 0);
77 	p_free(default_pool, str);
78 
79 	test_end();
80 }
81 
test_p_strarray_dup(void)82 static void test_p_strarray_dup(void)
83 {
84 	const char *input[][3] = {
85 		{ NULL },
86 		{ "a", NULL },
87 		{ "foobar", NULL },
88 		{ "a", "foo", NULL }
89 	};
90 	const char **ret;
91 	unsigned int i, j;
92 
93 	test_begin("p_strarray_dup");
94 
95 	for (i = 0; i < N_ELEMENTS(input); i++) {
96 		ret = p_strarray_dup(default_pool, input[i]);
97 		for (j = 0; input[i][j] != NULL; j++) {
98 			test_assert(strcmp(input[i][j], ret[j]) == 0);
99 			test_assert(input[i][j] != ret[j]);
100 		}
101 		test_assert(ret[j] == NULL);
102 		i_free(ret);
103 	}
104 	test_end();
105 }
106 
test_t_strsplit(void)107 static void test_t_strsplit(void)
108 {
109 	struct {
110 		const char *input;
111 		const char *const *output;
112 	} tests[] = {
113 		/* empty string -> empty array. was this perhaps a mistake for
114 		   the API to do this originally?.. can't really change now
115 		   anyway. */
116 		{ "", (const char *const []) { NULL } },
117 		{ "\n", (const char *const []) { "", "", NULL } },
118 		{ "\n\n", (const char *const []) { "", "", "", NULL } },
119 		{ "foo", (const char *const []) { "foo", NULL } },
120 		{ "foo\n", (const char *const []) { "foo", "", NULL } },
121 		{ "foo\nbar", (const char *const []) { "foo", "bar", NULL } },
122 		{ "foo\nbar\n", (const char *const []) { "foo", "bar", "", NULL } },
123 		{ "\nfoo\n\nbar\n\n", (const char *const []) { "", "foo", "", "bar", "", "", NULL } },
124 	};
125 	const char *const *args, *const *args2, *const *args3;
126 
127 	test_begin("t_strsplit");
128 
129 	for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
130 		/* split_str_fast() with single separator */
131 		args = t_strsplit(tests[i].input, "\n");
132 		/* split_str_slow() with a secondary separator */
133 		args2 = t_strsplit(tests[i].input, "\r\n");
134 		/* also as suffix */
135 		args3 = t_strsplit(tests[i].input, "\n\r");
136 		for (unsigned int j = 0; tests[i].output[j] != NULL; j++) {
137 			test_assert_idx(null_strcmp(tests[i].output[j], args[j]) == 0, i);
138 			test_assert_idx(null_strcmp(args[j], args2[j]) == 0, i);
139 			test_assert_idx(null_strcmp(args[j], args3[j]) == 0, i);
140 		}
141 	}
142 	test_end();
143 }
144 
test_t_strsplit_spaces(void)145 static void test_t_strsplit_spaces(void)
146 {
147 	struct {
148 		const char *input;
149 		const char *const *output;
150 	} tests[] = {
151 		/* empty strings */
152 		{ "", (const char *const []) { NULL } },
153 		{ "\n", (const char *const []) { NULL } },
154 		{ "\n\n", (const char *const []) { NULL } },
155 		/* normal */
156 		{ "foo", (const char *const []) { "foo", NULL } },
157 		{ "foo\n", (const char *const []) { "foo", NULL } },
158 		{ "foo\nbar", (const char *const []) { "foo", "bar", NULL } },
159 		{ "foo\nbar\n", (const char *const []) { "foo", "bar", NULL } },
160 		{ "\nfoo\n\nbar\n\n", (const char *const []) { "foo", "bar", NULL } },
161 	};
162 	const char *const *args, *const *args2, *const *args3;
163 
164 	test_begin("t_strsplit_spaces");
165 
166 	for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
167 		args = t_strsplit_spaces(tests[i].input, "\n");
168 		/* test also with a secondary nonexistent separator */
169 		args2 = t_strsplit_spaces(tests[i].input, "\r\n");
170 		/* also as suffix */
171 		args3 = t_strsplit_spaces(tests[i].input, "\n\r");
172 		for (unsigned int j = 0; tests[i].output[j] != NULL; j++) {
173 			test_assert_idx(null_strcmp(tests[i].output[j], args[j]) == 0, i);
174 			test_assert_idx(null_strcmp(args[j], args2[j]) == 0, i);
175 			test_assert_idx(null_strcmp(args[j], args3[j]) == 0, i);
176 		}
177 	}
178 
179 	/* multiple separators */
180 	args = t_strsplit_spaces(" , ,   ,str1  ,  ,,, , str2   , ", " ,");
181 	test_assert(strcmp(args[0], "str1") == 0);
182 	test_assert(strcmp(args[1], "str2") == 0);
183 	test_assert(args[2] == NULL);
184 	test_end();
185 }
186 
test_t_str_replace(void)187 static void test_t_str_replace(void)
188 {
189 	test_begin("t_str_replace");
190 	test_assert(strcmp(t_str_replace("foo", 'a', 'b'), "foo") == 0);
191 	test_assert(strcmp(t_str_replace("fooa", 'a', 'b'), "foob") == 0);
192 	test_assert(strcmp(t_str_replace("afooa", 'a', 'b'), "bfoob") == 0);
193 	test_assert(strcmp(t_str_replace("", 'a', 'b'), "") == 0);
194 	test_assert(strcmp(t_str_replace("a", 'a', 'b'), "b") == 0);
195 	test_assert(strcmp(t_str_replace("aaa", 'a', 'b'), "bbb") == 0);
196 	test_assert(strcmp(t_str_replace("bbb", 'a', 'b'), "bbb") == 0);
197 	test_assert(strcmp(t_str_replace("aba", 'a', 'b'), "bbb") == 0);
198 	test_end();
199 }
200 
test_t_str_oneline(void)201 static void test_t_str_oneline(void)
202 {
203 	test_begin("t_str_oneline");
204 	test_assert(strcmp(t_str_oneline("\n"), "") == 0);
205 	test_assert(strcmp(t_str_oneline("\r"), "") == 0);
206 	test_assert(strcmp(t_str_oneline("\n\n"), "") == 0);
207 	test_assert(strcmp(t_str_oneline("\r\r"), "") == 0);
208 	test_assert(strcmp(t_str_oneline("\r\n"), "") == 0);
209 	test_assert(strcmp(t_str_oneline("\r\n\r\n"), "") == 0);
210 	test_assert(strcmp(t_str_oneline("\n\r"), "") == 0);
211 	test_assert(strcmp(t_str_oneline("\n\r\n\r"), "") == 0);
212 	test_assert(strcmp(t_str_oneline("foo"), "foo") == 0);
213 	test_assert(strcmp(t_str_oneline("\nfoo"), "foo") == 0);
214 	test_assert(strcmp(t_str_oneline("foo\n"), "foo") == 0);
215 	test_assert(strcmp(t_str_oneline("\nfoo\n"), "foo") == 0);
216 	test_assert(strcmp(t_str_oneline("foo\nbar"), "foo bar") == 0);
217 	test_assert(strcmp(t_str_oneline("foo\n\nbar"), "foo bar") == 0);
218 	test_assert(strcmp(t_str_oneline("\nfoo\nbar"), "foo bar") == 0);
219 	test_assert(strcmp(t_str_oneline("foo\nbar\n"), "foo bar") == 0);
220 	test_assert(strcmp(t_str_oneline("foo\nbar\nbaz"), "foo bar baz") == 0);
221 	test_assert(strcmp(t_str_oneline("\rfoo"), "foo") == 0);
222 	test_assert(strcmp(t_str_oneline("foo\r"), "foo") == 0);
223 	test_assert(strcmp(t_str_oneline("\rfoo\r"), "foo") == 0);
224 	test_assert(strcmp(t_str_oneline("foo\rbar"), "foobar") == 0);
225 	test_assert(strcmp(t_str_oneline("foo\r\rbar"), "foobar") == 0);
226 	test_assert(strcmp(t_str_oneline("\rfoo\rbar"), "foobar") == 0);
227 	test_assert(strcmp(t_str_oneline("foo\rbar\r"), "foobar") == 0);
228 	test_assert(strcmp(t_str_oneline("foo\rbar\rbaz"), "foobarbaz") == 0);
229 	test_assert(strcmp(t_str_oneline("\r\nfoo\r\n"), "foo") == 0);
230 	test_assert(strcmp(t_str_oneline("foo\r\n"), "foo") == 0);
231 	test_assert(strcmp(t_str_oneline("\r\nfoo"), "foo") == 0);
232 	test_assert(strcmp(t_str_oneline("foo\r\nbar"), "foo bar") == 0);
233 	test_assert(strcmp(t_str_oneline("foo\r\n\r\nbar"), "foo bar") == 0);
234 	test_assert(strcmp(t_str_oneline("\r\nfoo\r\nbar"), "foo bar") == 0);
235 	test_assert(strcmp(t_str_oneline("foo\r\nbar\r\n"), "foo bar") == 0);
236 	test_assert(strcmp(t_str_oneline("foo\r\nbar\r\nbaz"), "foo bar baz") == 0);
237 	test_end();
238 }
239 
test_t_str_trim(void)240 static void test_t_str_trim(void)
241 {
242 	test_begin("t_str_trim");
243 	test_assert(strcmp(t_str_trim("", " "), "") == 0);
244 	test_assert(strcmp(t_str_trim(" ", " "), "") == 0);
245 	test_assert(strcmp(t_str_trim(" \t ", "\t "), "") == 0);
246 	test_assert(strcmp(t_str_trim("f \t ", "\t "), "f") == 0);
247 	test_assert(strcmp(t_str_trim("foo", ""), "foo") == 0);
248 	test_assert(strcmp(t_str_trim("foo", " "), "foo") == 0);
249 	test_assert(strcmp(t_str_trim("foo ", " "), "foo") == 0);
250 	test_assert(strcmp(t_str_trim(" foo", " "), "foo") == 0);
251 	test_assert(strcmp(t_str_trim(" foo ", " "), "foo") == 0);
252 	test_assert(strcmp(t_str_trim("\tfoo ", "\t "), "foo") == 0);
253 	test_assert(strcmp(t_str_trim(" \tfoo\t ", "\t "), "foo") == 0);
254 	test_assert(strcmp(t_str_trim("\r \tfoo\t \r", "\t \r"), "foo") == 0);
255 	test_assert(strcmp(t_str_trim("\r \tfoo foo\t \r", "\t \r"), "foo foo") == 0);
256 	test_assert(strcmp(t_str_trim("\tfoo\tfoo\t", "\t \r"), "foo\tfoo") == 0);
257 	test_end();
258 }
259 
test_t_str_ltrim(void)260 static void test_t_str_ltrim(void)
261 {
262 	test_begin("t_str_ltrim");
263 	test_assert(strcmp(t_str_ltrim("", " "), "") == 0);
264 	test_assert(strcmp(t_str_ltrim(" ", " "), "") == 0);
265 	test_assert(strcmp(t_str_ltrim(" \t ", "\t "), "") == 0);
266 	test_assert(strcmp(t_str_ltrim(" \t f", "\t "), "f") == 0);
267 	test_assert(strcmp(t_str_ltrim("foo", ""), "foo") == 0);
268 	test_assert(strcmp(t_str_ltrim("foo", " "), "foo") == 0);
269 	test_assert(strcmp(t_str_ltrim("foo ", " "), "foo ") == 0);
270 	test_assert(strcmp(t_str_ltrim(" foo", " "), "foo") == 0);
271 	test_assert(strcmp(t_str_ltrim(" foo ", " "), "foo ") == 0);
272 	test_assert(strcmp(t_str_ltrim("\tfoo ", "\t "), "foo ") == 0);
273 	test_assert(strcmp(t_str_ltrim(" \tfoo\t ", "\t "), "foo\t ") == 0);
274 	test_assert(strcmp(t_str_ltrim("\r \tfoo\t \r", "\t \r"), "foo\t \r") == 0);
275 	test_assert(strcmp(t_str_ltrim("\r \tfoo foo\t \r", "\t \r"), "foo foo\t \r") == 0);
276 	test_assert(strcmp(t_str_ltrim("\tfoo\tfoo\t", "\t \r"), "foo\tfoo\t") == 0);
277 	test_end();
278 }
279 
test_t_str_rtrim(void)280 static void test_t_str_rtrim(void)
281 {
282 	test_begin("t_str_rtrim");
283 	test_assert(strcmp(t_str_rtrim("", " "), "") == 0);
284 	test_assert(strcmp(t_str_rtrim(" ", " "), "") == 0);
285 	test_assert(strcmp(t_str_rtrim(" \t ", "\t "), "") == 0);
286 	test_assert(strcmp(t_str_rtrim("f \t ", "\t "), "f") == 0);
287 	test_assert(strcmp(t_str_rtrim("foo", ""), "foo") == 0);
288 	test_assert(strcmp(t_str_rtrim("foo", " "), "foo") == 0);
289 	test_assert(strcmp(t_str_rtrim("foo ", " "), "foo") == 0);
290 	test_assert(strcmp(t_str_rtrim(" foo", " "), " foo") == 0);
291 	test_assert(strcmp(t_str_rtrim(" foo ", " "), " foo") == 0);
292 	test_assert(strcmp(t_str_rtrim("\tfoo ", "\t "), "\tfoo") == 0);
293 	test_assert(strcmp(t_str_rtrim(" \tfoo\t ", "\t "), " \tfoo") == 0);
294 	test_assert(strcmp(t_str_rtrim("\r \tfoo\t \r", "\t \r"), "\r \tfoo") == 0);
295 	test_assert(strcmp(t_str_rtrim("\r \tfoo foo\t \r", "\t \r"), "\r \tfoo foo") == 0);
296 	test_assert(strcmp(t_str_rtrim("\tfoo\tfoo\t", "\t \r"), "\tfoo\tfoo") == 0);
297 	test_end();
298 }
299 
300 static const char *const test_strarray_input[] = {
301 	"", "hello", "world", "", "yay", "", NULL
302 };
303 static const struct {
304 	const char *separator;
305 	const char *output;
306 } test_strarray_outputs[] = {
307 	{ "", "helloworldyay" },
308 	{ " ", " hello world  yay " },
309 	{ "!-?", "!-?hello!-?world!-?!-?yay!-?" }
310 };
311 
312 static const char *const test_strarray_input2[] = {
313 	"", "", "hello", "world", "", "yay", "", NULL
314 };
315 static struct {
316 	const char *separator;
317 	const char *output;
318 } test_strarray_outputs2[] = {
319 	{ "", "helloworldyay" },
320 	{ " ", "  hello world  yay " },
321 	{ "!-?", "!-?!-?hello!-?world!-?!-?yay!-?" }
322 };
323 
324 static const char *const test_strarray_input3[] = {
325 	"hello", "", "", "yay", NULL
326 };
327 static struct {
328 	const char *separator;
329 	const char *output;
330 } test_strarray_outputs3[] = {
331 	{ "", "helloyay" },
332 	{ " ", "hello   yay" },
333 	{ "!-?", "hello!-?!-?!-?yay" }
334 };
335 
test_t_strarray_join(void)336 static void test_t_strarray_join(void)
337 {
338 	const char *null = NULL;
339 	unsigned int i;
340 
341 	test_begin("t_strarray_join()");
342 
343 	/* empty array -> empty string */
344 	test_assert(strcmp(t_strarray_join(&null, " "), "") == 0);
345 
346 	for (i = 0; i < N_ELEMENTS(test_strarray_outputs); i++) {
347 		test_assert_idx(strcmp(t_strarray_join(test_strarray_input,
348 						       test_strarray_outputs[i].separator),
349 				       test_strarray_outputs[i].output) == 0, i);
350 	}
351 	for (i = 0; i < N_ELEMENTS(test_strarray_outputs2); i++) {
352 		test_assert_idx(strcmp(t_strarray_join(test_strarray_input2,
353 						       test_strarray_outputs2[i].separator),
354 				       test_strarray_outputs2[i].output) == 0, i);
355 	}
356 	for (i = 0; i < N_ELEMENTS(test_strarray_outputs3); i++) {
357 		test_assert_idx(strcmp(t_strarray_join(test_strarray_input3,
358 						       test_strarray_outputs3[i].separator),
359 				       test_strarray_outputs3[i].output) == 0, i);
360 	}
361 	test_end();
362 }
363 
test_p_array_const_string_join(void)364 static void test_p_array_const_string_join(void)
365 {
366 	ARRAY_TYPE(const_string) arr;
367 	unsigned int i;
368 	char *res;
369 
370 	test_begin("p_array_const_string_join()");
371 
372 	i_array_init(&arr, 2);
373 	/* empty array -> empty string */
374 	test_assert(strcmp(t_array_const_string_join(&arr, " "), "") == 0);
375 
376 	array_append(&arr, test_strarray_input,
377 		     str_array_length(test_strarray_input));
378 	for (i = 0; i < N_ELEMENTS(test_strarray_outputs); i++) {
379 		res = p_array_const_string_join(default_pool, &arr,
380 						test_strarray_outputs[i].separator);
381 		test_assert_idx(strcmp(res, test_strarray_outputs[i].output) == 0, i);
382 		i_free(res);
383 	}
384 
385 	array_free(&arr);
386 	test_end();
387 }
388 
test_mem_equals_timing_safe(void)389 static void test_mem_equals_timing_safe(void)
390 {
391 	const struct {
392 		const char *a, *b;
393 	} tests[] = {
394 		{ "", "" },
395 		{ "a", "a" },
396 		{ "b", "a" },
397 		{ "ab", "ab" },
398 		{ "ab", "ba" },
399 		{ "ab", "bc" },
400 	};
401 	test_begin("mem_equals_timing_safe()");
402 	for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
403 		size_t len = strlen(tests[i].a);
404 		i_assert(len == strlen(tests[i].b));
405 		test_assert((memcmp(tests[i].a, tests[i].b, len) == 0) ==
406 			    mem_equals_timing_safe(tests[i].a, tests[i].b, len));
407 		test_assert((memcmp(tests[i].a, tests[i].b, len) == 0) ==
408 			    mem_equals_timing_safe(tests[i].b, tests[i].a, len));
409 	}
410 	test_end();
411 }
412 
test_str_equals_timing_almost_safe(void)413 static void test_str_equals_timing_almost_safe(void)
414 {
415 	const struct {
416 		const char *a, *b;
417 	} tests[] = {
418 		{ "", "" },
419 		{ "a", "a" },
420 		{ "b", "a" },
421 		{ "ab", "ab" },
422 		{ "ab", "ba" },
423 		{ "ab", "bc" },
424 		{ "a", "" },
425 		{ "a", "ab" },
426 		{ "a", "abc" },
427 		{ "ab", "abc" },
428 	};
429 	test_begin("str_equals_timing_almost_safe()");
430 	for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
431 		test_assert((strcmp(tests[i].a, tests[i].b) == 0) ==
432 			    str_equals_timing_almost_safe(tests[i].a, tests[i].b));
433 		test_assert((strcmp(tests[i].a, tests[i].b) == 0) ==
434 			    str_equals_timing_almost_safe(tests[i].b, tests[i].a));
435 	}
436 	test_end();
437 }
438 
test_dec2str_buf(void)439 static void test_dec2str_buf(void)
440 {
441 	const uintmax_t test_input[] = {
442 		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
443 		99, 999, 9999, 65535, 65536, 99999, 999999, 9999999,
444 		99999999, 999999999, 4294967295, 4294967296ULL,
445 		9999999999999999999ULL,
446 		18446744073709551615ULL
447 	};
448 	char buf[MAX_INT_STRLEN], buf2[MAX_INT_STRLEN];
449 
450 	test_begin("dec2str_buf()");
451 	for (unsigned int i = 0; i < N_ELEMENTS(test_input); i++) {
452 		i_snprintf(buf2, sizeof(buf2), "%ju", test_input[i]);
453 		test_assert_idx(strcmp(dec2str_buf(buf, test_input[i]),
454 				       buf2) == 0, i);
455 	}
456 	test_end();
457 }
458 
459 static void
test_str_match(void)460 test_str_match(void)
461 {
462 	static const struct {
463 		const char*s1, *s2; size_t match;
464 	} tests[] = {
465 #define MATCH_TEST(common, left, right) { common left, common right, sizeof(common)-1 }
466 		MATCH_TEST("", "", ""),
467 		MATCH_TEST("", "x", ""),
468 		MATCH_TEST("", "", "x"),
469 		MATCH_TEST("", "foo", "bar"),
470 		MATCH_TEST("x", "", ""),
471 		MATCH_TEST("x", "y", "z"),
472 		MATCH_TEST("blahblahblah", "", ""),
473 		MATCH_TEST("blahblahblah", "", "bar"),
474 		MATCH_TEST("blahblahblah", "foo", ""),
475 		MATCH_TEST("blahblahblah", "foo", "bar"),
476 #undef MATCH_TEST
477 	};
478 
479 	unsigned int i;
480 
481 	test_begin("str_match");
482 	for (i = 0; i < N_ELEMENTS(tests); i++)
483 		test_assert_idx(str_match(tests[i].s1, tests[i].s2) == tests[i].match, i);
484 	test_end();
485 
486 	test_begin("str_begins");
487 	for (i = 0; i < N_ELEMENTS(tests); i++) {
488 		/* This is just 2 ways of wording the same test, but that also
489 		   sanity tests the match values above. */
490 		test_assert_idx(str_begins(tests[i].s1, tests[i].s2) ==
491 				(str_begins(tests[i].s1, tests[i].s2)), i);
492 		test_assert_idx(str_begins(tests[i].s1, tests[i].s2) ==
493 				(strlen(tests[i].s2) == tests[i].match), i);
494 	}
495 	test_end();
496 }
497 
test_memspn(void)498 static void test_memspn(void)
499 {
500 #undef TEST_CASE
501 /* we substract 1 to ensure we don't include the final \0 byte */
502 #define TEST_CASE(a, b, r) { \
503 	.input = (const unsigned char*)((a)), .input_len = sizeof((a))-1, \
504 	.accept = (const unsigned char*)((b)), .accept_len = sizeof((b))-1, \
505 	.result = r, \
506 }
507 
508 	static struct {
509 		const unsigned char *input;
510 		size_t input_len;
511 		const unsigned char *accept;
512 		size_t accept_len;
513 		size_t result;
514 	} tests[] = {
515 		TEST_CASE("", "", 0),
516 		TEST_CASE("", "123456789", 0),
517 		TEST_CASE("123456789", "", 0),
518 		TEST_CASE("hello, world", "helo", 5),
519 		TEST_CASE("hello, uuuuu", "helo", 5),
520 		TEST_CASE("\0\0\0\0\0hello", "\0", 5),
521 		TEST_CASE("\r\r\r\r", "\r", 4),
522 		TEST_CASE("aaa", "a", 3),
523 		TEST_CASE("bbb", "a", 0),
524 		/* null safety test */
525 		{
526 			.input = NULL, .accept = NULL,
527 			.input_len = 0, .accept_len = 0,
528 			.result = 0,
529 		}
530 	};
531 
532 	test_begin("i_memspn");
533 
534 	for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
535 		size_t a = i_memspn(tests[i].input, tests[i].input_len,
536 				    tests[i].accept, tests[i].accept_len);
537 		test_assert_ucmp_idx(a, ==, tests[i].result, i);
538 		if (tests[i].input == NULL)
539 			continue;
540 		a = i_memspn(tests[i].input, strlen((const char*)tests[i].input),
541 			     tests[i].accept, strlen((const char*)tests[i].accept));
542 		size_t b = strspn((const char*)tests[i].input,
543 				  (const char*)tests[i].accept);
544 		test_assert_ucmp_idx(a, ==, b, i);
545 	}
546 
547 	test_end();
548 }
549 
test_memcspn(void)550 static void test_memcspn(void)
551 {
552 #undef TEST_CASE
553 /* we substract 1 to ensure we don't include the final \0 byte */
554 #define TEST_CASE(a, b, r) { \
555 	.input = (const unsigned char*)((a)), .input_len = sizeof((a))-1, \
556 	.reject = (const unsigned char*)((b)), .reject_len = sizeof((b))-1, \
557 	.result = r, \
558 }
559 
560 	static struct {
561 		const unsigned char *input;
562 		size_t input_len;
563 		const unsigned char *reject;
564 		size_t reject_len;
565 		size_t result;
566 	} tests[] = {
567 		TEST_CASE("", "", 0),
568 		TEST_CASE("hello", "", 5),
569 		TEST_CASE("uuuuu, hello", "helo", 7),
570 		TEST_CASE("\0\0\0\0\0\0hello", "u", 11),
571 		TEST_CASE("this\0is\0test", "\0", 4),
572 		TEST_CASE("hello, world\r", "\r", 12),
573 		TEST_CASE("aaa", "a", 0),
574 		TEST_CASE("bbb", "a", 3),
575 		/* null safety test */
576 		{
577 			.input = NULL, .reject = NULL,
578 			.input_len = 0, .reject_len = 0,
579 			.result = 0,
580 		}
581 	};
582 
583 	test_begin("i_memcspn");
584 
585 	for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
586 		size_t a = i_memcspn(tests[i].input, tests[i].input_len,
587 				     tests[i].reject, tests[i].reject_len);
588 		test_assert_ucmp_idx(a, ==, tests[i].result, i);
589 		if (tests[i].input == NULL)
590 			continue;
591 		a = i_memcspn(tests[i].input, strlen((const char*)tests[i].input),
592 			      tests[i].reject, strlen((const char*)tests[i].reject));
593 		size_t b = strcspn((const char*)tests[i].input,
594 				   (const char*)tests[i].reject);
595 		test_assert_ucmp_idx(a, ==, b, i);
596 	}
597 
598 	test_end();
599 }
600 
test_strfuncs(void)601 void test_strfuncs(void)
602 {
603 	test_p_strdup();
604 	test_p_strndup();
605 	test_p_strdup_empty();
606 	test_p_strdup_until();
607 	test_p_strarray_dup();
608 	test_t_strsplit();
609 	test_t_strsplit_spaces();
610 	test_t_str_replace();
611 	test_t_str_oneline();
612 	test_t_str_trim();
613 	test_t_str_ltrim();
614 	test_t_str_rtrim();
615 	test_t_strarray_join();
616 	test_p_array_const_string_join();
617 	test_mem_equals_timing_safe();
618 	test_str_equals_timing_almost_safe();
619 	test_dec2str_buf();
620 	test_str_match();
621 	test_memspn();
622 	test_memcspn();
623 }
624 
fatal_strfuncs(unsigned int stage)625 enum fatal_test_state fatal_strfuncs(unsigned int stage)
626 {
627 	switch (stage) {
628 	case 0:
629 		test_begin("fatal p_strndup()");
630 		test_expect_fatal_string("(str != NULL)");
631 		(void)p_strndup(default_pool, NULL, 100);
632 		return FATAL_TEST_FAILURE;
633 	case 1:
634 		test_expect_fatal_string("(max_chars != SIZE_MAX)");
635 		(void)p_strndup(default_pool, "foo", SIZE_MAX);
636 		return FATAL_TEST_FAILURE;
637 	}
638 	test_end();
639 	return FATAL_TEST_FINISHED;
640 }
641