1 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "test-common.h"
5 
6 #include <stdio.h>
7 #include <setjmp.h> /* for fatal tests */
8 
9 static bool test_deinit_lib;
10 
11 /* To test the firing of i_assert, we need non-local jumps, i.e. setjmp */
12 static volatile bool expecting_fatal = FALSE;
13 static jmp_buf fatal_jmpbuf;
14 
15 #define OUT_NAME_ALIGN 70
16 
17 static char *test_prefix;
18 static bool test_success;
19 static unsigned int failure_count;
20 static unsigned int total_count;
21 static unsigned int expected_errors;
22 static char *expected_error_str, *expected_fatal_str;
23 static test_fatal_callback_t *test_fatal_callback;
24 static void *test_fatal_context;
25 
test_begin(const char * name)26 void test_begin(const char *name)
27 {
28 	test_success = TRUE;
29 	expected_errors = 0;
30 	if (!expecting_fatal)
31 		i_assert(test_prefix == NULL);
32 	else
33 		test_assert((test_success = (test_prefix == NULL)));
34 	test_prefix = i_strdup(name);
35 }
36 
test_has_failed(void)37 bool test_has_failed(void)
38 {
39 	return !test_success;
40 }
41 
test_assert_failed(const char * code,const char * file,unsigned int line)42 void test_assert_failed(const char *code, const char *file, unsigned int line)
43 {
44 	printf("%s:%u: Assert failed: %s\n", file, line, code);
45 	fflush(stdout);
46 	test_success = FALSE;
47 #ifdef STATIC_CHECKER
48 	i_unreached();
49 #endif
50 }
51 
test_assert_failed_idx(const char * code,const char * file,unsigned int line,long long i)52 void test_assert_failed_idx(const char *code, const char *file, unsigned int line, long long i)
53 {
54 	printf("%s:%u: Assert(#%lld) failed: %s\n", file, line, i, code);
55 	fflush(stdout);
56 	test_success = FALSE;
57 #ifdef STATIC_CHECKER
58 	i_unreached();
59 #endif
60 }
61 
test_assert_failed_strcmp_idx(const char * code,const char * file,unsigned int line,const char * src,const char * dst,long long i)62 void test_assert_failed_strcmp_idx(const char *code, const char *file, unsigned int line,
63 				   const char * src, const char * dst, long long i)
64 {
65 	printf("%s:%u: Assert", file, line);
66 	if (i == LLONG_MIN)
67 		printf(" failed: %s\n", code);
68 	else
69 		printf("(#%lld) failed: %s\n", i, code);
70 	if (src != NULL)
71 		printf("        \"%s\" != ", src);
72 	else
73 		printf("        NULL != ");
74 	if (dst != NULL)
75 		printf("\"%s\"\n", dst);
76 	else
77 		printf("NULL\n");
78 	fflush(stdout);
79 	test_success = FALSE;
80 #ifdef STATIC_CHECKER
81 	i_unreached();
82 #endif
83 }
84 
test_assert_failed_cmp_intmax_idx(const char * code,const char * file,unsigned int line,intmax_t src,intmax_t dst,const char * op,long long i)85 void test_assert_failed_cmp_intmax_idx(const char *code, const char *file,
86 				       unsigned int line,
87 				       intmax_t src, intmax_t dst,
88 				       const char *op, long long i)
89 {
90 	printf("%s:%u: Assert", file, line);
91 	if (i == LLONG_MIN)
92 		printf(" failed: %s\n", code);
93 	else
94 		printf("(#%lld) failed: %s\n", i, code);
95 	printf("        %jd %s %jd is not true\n", src, op, dst);
96 	fflush(stdout);
97 	test_success = FALSE;
98 #ifdef STATIC_CHECKER
99 	i_unreached();
100 #endif
101 }
102 
test_assert_failed_ucmp_intmax_idx(const char * code,const char * file,unsigned int line,uintmax_t src,uintmax_t dst,const char * op,long long i)103 void test_assert_failed_ucmp_intmax_idx(const char *code, const char *file,
104 					unsigned int line,
105 					uintmax_t src, uintmax_t dst,
106 					const char *op, long long i)
107 {
108 	printf("%s:%u: Assert", file, line);
109 	if (i == LLONG_MIN)
110 		printf(" failed: %s\n", code);
111 	else
112 		printf("(#%lld) failed: %s\n", i, code);
113 	printf("        %ju %s %ju is not true\n", src, op, dst);
114 	fflush(stdout);
115 	test_success = FALSE;
116 #ifdef STATIC_CHECKER
117 	i_unreached();
118 #endif
119 }
120 
121 #ifdef DEBUG
122 #include "randgen.h"
123 static void
test_dump_rand_state(void)124 test_dump_rand_state(void)
125 {
126 	static int64_t seen_seed = -1;
127 	unsigned int seed;
128 	if (rand_get_last_seed(&seed) < 0) {
129 		if (seen_seed == -1) {
130 			printf("test: random sequence not reproduceable, use DOVECOT_SRAND=kiss\n");
131 			seen_seed = -2;
132 		}
133 		return;
134 	}
135 	if (seed == seen_seed)
136 		return;
137 	seen_seed = seed;
138 	printf("test: DOVECOT_SRAND random seed was %u\n", seed);
139 }
140 #else
test_dump_rand_state(void)141 static inline void test_dump_rand_state(void) { }
142 #endif
143 
test_end(void)144 void test_end(void)
145 {
146 	if (!expecting_fatal)
147 		i_assert(test_prefix != NULL);
148 	else
149 		test_assert(test_prefix != NULL);
150 
151 	test_out("", test_success);
152 	if (!test_success)
153 		test_dump_rand_state();
154 	i_free_and_null(test_prefix);
155 	test_success = FALSE;
156 }
157 
test_out(const char * name,bool success)158 void test_out(const char *name, bool success)
159 {
160 	test_out_reason(name, success, NULL);
161 }
162 
test_out_quiet(const char * name,bool success)163 void test_out_quiet(const char *name, bool success)
164 {
165 	if (success) {
166 		total_count++;
167 		return;
168 	}
169 	test_out(name, success);
170 }
171 
test_out_reason(const char * name,bool success,const char * reason)172 void test_out_reason(const char *name, bool success, const char *reason)
173 {
174 	int i = 0;
175 
176 	if (test_prefix != NULL) {
177 		fputs(test_prefix, stdout);
178 		i += strlen(test_prefix);
179 		if (*name != '\0') {
180 			putchar(':');
181 			i++;
182 		}
183 		putchar(' ');
184 		i++;
185 	}
186 	if (*name != '\0') {
187 		fputs(name, stdout);
188 		putchar(' ');
189 		i += strlen(name) + 1;
190 	}
191 	for (; i < OUT_NAME_ALIGN; i++)
192 		putchar('.');
193 	fputs(" : ", stdout);
194 	if (success)
195 		fputs("ok", stdout);
196 	else {
197 		fputs("FAILED", stdout);
198 		test_success = FALSE;
199 		failure_count++;
200 	}
201 	if (reason != NULL && *reason != '\0')
202 		printf(": %s", reason);
203 	putchar('\n');
204 	fflush(stdout);
205 	total_count++;
206 }
207 
208 void
test_expect_error_string_n_times(const char * substr,unsigned int times)209 test_expect_error_string_n_times(const char *substr, unsigned int times)
210 {
211 	i_assert(expected_errors == 0);
212 	expected_errors = times;
213 	expected_error_str = i_strdup(substr);
214 }
215 void
test_expect_error_string(const char * substr)216 test_expect_error_string(const char *substr)
217 {
218 	test_expect_error_string_n_times(substr, 1);
219 }
220 void
test_expect_errors(unsigned int expected)221 test_expect_errors(unsigned int expected)
222 {
223 	i_assert(expected_errors == 0);
224 	expected_errors = expected;
225 }
226 void
test_expect_no_more_errors(void)227 test_expect_no_more_errors(void)
228 {
229 	test_assert(expected_errors == 0 && expected_error_str == NULL);
230 	i_free_and_null(expected_error_str);
231 	expected_errors = 0;
232 }
233 
234 static bool ATTR_FORMAT(2, 0)
expect_error_check(char ** error_strp,const char * format,va_list args)235 expect_error_check(char **error_strp, const char *format, va_list args)
236 {
237 	if (*error_strp == NULL)
238 		return TRUE;
239 
240 	bool suppress;
241 	T_BEGIN {
242 		/* test_assert() will reset test_success if need be. */
243 		const char *str = t_strdup_vprintf(format, args);
244 		suppress = strstr(str, *error_strp) != NULL;
245 		test_assert(suppress == TRUE);
246 		i_free_and_null(*error_strp);
247 	} T_END;
248 	return suppress;
249 }
250 
251 static void ATTR_FORMAT(2, 0)
test_error_handler(const struct failure_context * ctx,const char * format,va_list args)252 test_error_handler(const struct failure_context *ctx,
253 		   const char *format, va_list args)
254 {
255 	bool suppress = FALSE;
256 
257 	if (expected_errors > 0) {
258 		va_list args2;
259 		VA_COPY(args2, args);
260 		suppress = expect_error_check(&expected_error_str, format, args2);
261 		expected_errors--;
262 		va_end(args2);
263 	} else {
264 		test_success = FALSE;
265 	}
266 
267 	if (!suppress) {
268 		test_dump_rand_state();
269 		default_error_handler(ctx, format, args);
270 	}
271 }
272 
test_expect_fatal_string(const char * substr)273 void test_expect_fatal_string(const char *substr)
274 {
275 	i_free(expected_fatal_str);
276 	expected_fatal_str = i_strdup(substr);
277 }
278 
279 #undef test_fatal_set_callback
test_fatal_set_callback(test_fatal_callback_t * callback,void * context)280 void test_fatal_set_callback(test_fatal_callback_t *callback, void *context)
281 {
282 	i_assert(test_fatal_callback == NULL);
283 	test_fatal_callback = callback;
284 	test_fatal_context = context;
285 }
286 
287 static void ATTR_FORMAT(2, 0) ATTR_NORETURN
test_fatal_handler(const struct failure_context * ctx,const char * format,va_list args)288 test_fatal_handler(const struct failure_context *ctx,
289 		   const char *format, va_list args)
290 {
291 	/* Prevent recursion, we can't handle our own errors */
292 	i_set_fatal_handler(default_fatal_handler);
293 	i_assert(expecting_fatal); /* if not at the right time, bail */
294 
295 	va_list args2;
296 	VA_COPY(args2, args);
297 	bool suppress = expect_error_check(&expected_fatal_str, format, args2);
298 	va_end(args);
299 
300 	if (suppress) {
301 		if (test_fatal_callback != NULL) {
302 			test_fatal_callback(test_fatal_context);
303 			test_fatal_callback = NULL;
304 			test_fatal_context = NULL;
305 		}
306 
307 		i_set_fatal_handler(test_fatal_handler);
308 		longjmp(fatal_jmpbuf, 1);
309 	} else {
310 		default_fatal_handler(ctx, format, args);
311 	}
312 	i_unreached(); /* we simply can't get here */
313 }
314 
test_init(void)315 static void test_init(void)
316 {
317 	test_prefix = NULL;
318 	failure_count = 0;
319 	total_count = 0;
320 
321 	if (!lib_is_initialized()) {
322 		lib_init();
323 		test_deinit_lib = TRUE;
324 	} else
325 		test_deinit_lib = FALSE;
326 
327 	i_set_error_handler(test_error_handler);
328 	/* Don't set fatal handler until actually needed for fatal testing */
329 }
330 
test_deinit(void)331 static int test_deinit(void)
332 {
333 	i_assert(test_prefix == NULL);
334 	printf("%u / %u tests failed\n", failure_count, total_count);
335 	if (test_deinit_lib)
336 		lib_deinit();
337 	return failure_count == 0 ? 0 : 1;
338 }
339 
test_run_funcs(void (* const test_functions[])(void))340 static void test_run_funcs(void (*const test_functions[])(void))
341 {
342 	unsigned int i;
343 
344 	for (i = 0; test_functions[i] != NULL; i++) {
345 		T_BEGIN {
346 			test_functions[i]();
347 		} T_END;
348 	}
349 }
test_run_named_funcs(const struct named_test tests[],const char * match)350 static void test_run_named_funcs(const struct named_test tests[],
351 				 const char *match)
352 {
353 	unsigned int i;
354 
355 	for (i = 0; tests[i].func != NULL; i++) {
356 		if (strstr(tests[i].name, match) != NULL) T_BEGIN {
357 			tests[i].func();
358 		} T_END;
359 	}
360 }
361 
run_one_fatal(test_fatal_func_t * fatal_function)362 static void run_one_fatal(test_fatal_func_t *fatal_function)
363 {
364 	static unsigned int index = 0;
365 	for (;;) {
366 		volatile int jumped = setjmp(fatal_jmpbuf);
367 		if (jumped == 0) {
368 			/* normal flow */
369 			expecting_fatal = TRUE;
370 			enum fatal_test_state ret = fatal_function(index);
371 			expecting_fatal = FALSE;
372 			if (ret == FATAL_TEST_FINISHED) {
373 				/* ran out of tests - good */
374 				index = 0;
375 				break;
376 			} else if (ret == FATAL_TEST_FAILURE) {
377 				/* failed to fire assert - bad, but can continue */
378 				test_success = FALSE;
379 				i_error("Desired assert failed to fire at step %i", index);
380 				index++;
381 			} else { /* FATAL_TEST_ABORT or other value */
382 				test_success = FALSE;
383 				test_end();
384 				index = 0;
385 				break;
386 			}
387 		} else {
388 			/* assert fired, continue with next test */
389 			index++;
390 		}
391 	}
392 }
test_run_fatals(test_fatal_func_t * const fatal_functions[])393 static void test_run_fatals(test_fatal_func_t *const fatal_functions[])
394 {
395 	unsigned int i;
396 
397 	for (i = 0; fatal_functions[i] != NULL; i++) {
398 		T_BEGIN {
399 			run_one_fatal(fatal_functions[i]);
400 		} T_END;
401 	}
402 }
test_run_named_fatals(const struct named_fatal fatals[],const char * match)403 static void test_run_named_fatals(const struct named_fatal fatals[], const char *match)
404 {
405 	unsigned int i;
406 
407 	for (i = 0; fatals[i].func != NULL; i++) {
408 		if (strstr(fatals[i].name, match) != NULL) T_BEGIN {
409 			run_one_fatal(fatals[i].func);
410 		} T_END;
411 	}
412 }
413 
test_run(void (* const test_functions[])(void))414 int test_run(void (*const test_functions[])(void))
415 {
416 	test_init();
417 	test_run_funcs(test_functions);
418 	return test_deinit();
419 }
test_run_named(const struct named_test tests[],const char * match)420 int test_run_named(const struct named_test tests[], const char *match)
421 {
422 	test_init();
423 	test_run_named_funcs(tests, match);
424 	return test_deinit();
425 }
test_run_with_fatals(void (* const test_functions[])(void),test_fatal_func_t * const fatal_functions[])426 int test_run_with_fatals(void (*const test_functions[])(void),
427 			 test_fatal_func_t *const fatal_functions[])
428 {
429 	test_init();
430 	test_run_funcs(test_functions);
431 	i_set_fatal_handler(test_fatal_handler);
432 	test_run_fatals(fatal_functions);
433 	return test_deinit();
434 }
test_run_named_with_fatals(const char * match,const struct named_test tests[],const struct named_fatal fatals[])435 int test_run_named_with_fatals(const char *match, const struct named_test tests[],
436 			       const struct named_fatal fatals[])
437 {
438 	test_init();
439 	test_run_named_funcs(tests, match);
440 	i_set_fatal_handler(test_fatal_handler);
441 	test_run_named_fatals(fatals, match);
442 	return test_deinit();
443 }
444 
test_forked_end(void)445 void test_forked_end(void)
446 {
447 	i_set_error_handler(default_error_handler);
448 	i_set_fatal_handler(default_fatal_handler);
449 
450 	i_free_and_null(expected_error_str);
451 	i_free_and_null(expected_fatal_str);
452 	i_free_and_null(test_prefix);
453 	t_pop_last_unsafe(); /* as we were within a T_BEGIN { tests[i].func(); } T_END */
454 }
455 
456 void ATTR_NORETURN
test_exit(int status)457 test_exit(int status)
458 {
459 	i_free_and_null(expected_error_str);
460 	i_free_and_null(expected_fatal_str);
461 	i_free_and_null(test_prefix);
462 	t_pop_last_unsafe(); /* as we were within a T_BEGIN { tests[i].func(); } T_END */
463 	lib_deinit();
464 	lib_exit(status);
465 }
466