2 * BIRD -- Unit Test Framework (BIRD Test)
4 * Can be freely distributed and used under the terms of the GNU GPL.
15 #include <sys/ioctl.h>
16 #include <sys/resource.h>
19 #include "test/birdtest.h"
20 #include "lib/string.h"
22 #ifdef HAVE_EXECINFO_H
26 #define BACKTRACE_MAX_LINES 100
28 #define sprintf_concat(s, format, ...) \
29 snprintf(s + strlen(s), sizeof(s) - strlen(s), format, ##__VA_ARGS__)
31 static const char *request
;
32 static int list_tests
;
35 static int no_timeout
;
36 static int is_terminal
; /* Whether stdout is a live terminal or pipe redirect */
39 const char *bt_filename
;
40 const char *bt_test_id
;
42 int bt_result
; /* Overall program run result */
43 int bt_suite_result
; /* One suit result */
44 char bt_out_fmt_buf
[1024]; /* Temporary memory buffer for output of testing function */
49 /* Seeded in bt_init() */
50 long int rand_low
, rand_high
;
54 return (rand_low
& 0xffff) | ((rand_high
& 0xffff) << 16);
58 bt_init(int argc
, char *argv
[])
62 srandom(BT_RANDOM_SEED
);
65 bt_filename
= argv
[0];
66 bt_result
= BT_SUCCESS
;
68 is_terminal
= isatty(fileno(stdout
));
70 while ((c
= getopt(argc
, argv
, "lcftv")) >= 0)
97 /* Optional requested test_id */
98 if ((optind
+ 1) == argc
)
99 request
= argv
[optind
++];
106 struct rlimit rl
= {RLIM_INFINITY
, RLIM_INFINITY
};
107 int rv
= setrlimit(RLIMIT_CORE
, &rl
);
108 bt_syscall(rv
< 0, "setrlimit RLIMIT_CORE");
114 printf("Usage: %s [-l] [-c] [-f] [-t] [-vvv] [<test_suit_name>]\n", argv
[0]);
115 printf("Options: \n");
116 printf(" -l List all test suite names and descriptions \n");
117 printf(" -c Force unlimit core dumps (needs root privileges) \n");
118 printf(" -f No forking \n");
119 printf(" -t No timeout limit \n");
120 printf(" -v More verbosity, maximum is 3 -vvv \n");
125 bt_dump_backtrace(void)
127 #ifdef HAVE_EXECINFO_H
128 void *buf
[BACKTRACE_MAX_LINES
];
135 lines
= backtrace(buf
, BACKTRACE_MAX_LINES
);
136 bt_log("backtrace() returned %d addresses", lines
);
138 pp_backtrace
= backtrace_symbols(buf
, lines
);
139 if (pp_backtrace
== NULL
)
141 perror("backtrace_symbols");
145 for (j
= 0; j
< lines
; j
++)
146 bt_log("%s", pp_backtrace
[j
]);
149 #endif /* HAVE_EXECINFO_H */
153 int bt_run_test_fn(int (*fn
)(const void *), const void *fn_arg
, int timeout
)
161 result
= ((int (*)(void))fn
)();
163 if (bt_suite_result
!= BT_SUCCESS
)
170 get_num_terminal_cols(void)
172 struct winsize w
= {};
173 ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &w
);
174 uint cols
= w
.ws_col
;
175 return (cols
> 0 ? cols
: 80);
179 * bt_log_result - pretty print of test result
180 * @result: BT_SUCCESS or BT_FAILURE
181 * @fmt: a description message (could be long, over more lines)
182 * @argptr: variable argument list
184 * This function is used for pretty printing of test results on all verbose
188 bt_log_result(int result
, const char *fmt
, va_list argptr
)
190 char fmt_buf
[BT_BUFFER_SIZE
];
191 char msg_buf
[BT_BUFFER_SIZE
];
194 snprintf(msg_buf
, sizeof(msg_buf
), "%s%s%s%s",
196 bt_test_id
? ": " : "",
197 bt_test_id
? bt_test_id
: "",
198 (fmt
&& strlen(fmt
) > 0) ? ": " : "");
199 pos
= msg_buf
+ strlen(msg_buf
);
201 vsnprintf(pos
, sizeof(msg_buf
) - (pos
- msg_buf
), fmt
, argptr
);
203 /* 'll' means here Last Line */
204 uint cols
= get_num_terminal_cols();
205 uint ll_len
= (strlen(msg_buf
) % cols
) + BT_PROMPT_OK_FAIL_STRLEN
;
206 uint ll_offset
= (ll_len
/ get_num_terminal_cols() + 1) * cols
- BT_PROMPT_OK_FAIL_STRLEN
;
207 uint offset
= ll_offset
+ (strlen(msg_buf
) / cols
) * cols
;
208 snprintf(fmt_buf
, sizeof(fmt_buf
), "%%-%us%%s\n", offset
);
210 const char *result_str
= is_terminal
? BT_PROMPT_OK
: BT_PROMPT_OK_NO_COLOR
;
211 if (result
!= BT_SUCCESS
)
212 result_str
= is_terminal
? BT_PROMPT_FAIL
: BT_PROMPT_FAIL_NO_COLOR
;
214 printf(fmt_buf
, msg_buf
, result_str
);
218 * bt_log_overall_result - pretty print of suite case result
219 * @result: BT_SUCCESS or BT_FAILURE
220 * @fmt: a description message (could be long, over more lines)
221 * ...: variable argument list
223 * This function is used for pretty printing of test suite case result.
226 bt_log_overall_result(int result
, const char *fmt
, ...)
229 va_start(argptr
, fmt
);
230 bt_log_result(result
, fmt
, argptr
);
235 * bt_log_suite_result - pretty print of suite case result
236 * @result: BT_SUCCESS or BT_FAILURE
237 * @fmt: a description message (could be long, over more lines)
238 * ...: variable argument list
240 * This function is used for pretty printing of test suite case result.
243 bt_log_suite_result(int result
, const char *fmt
, ...)
245 if(bt_verbose
>= BT_VERBOSE_SUITE
|| result
== BT_FAILURE
)
248 va_start(argptr
, fmt
);
249 bt_log_result(result
, fmt
, argptr
);
255 * bt_log_suite_case_result - pretty print of suite result
256 * @result: BT_SUCCESS or BT_FAILURE
257 * @fmt: a description message (could be long, over more lines)
258 * ...: variable argument list
260 * This function is used for pretty printing of test suite result.
263 bt_log_suite_case_result(int result
, const char *fmt
, ...)
265 if(bt_verbose
>= BT_VERBOSE_SUITE_CASE
)
268 va_start(argptr
, fmt
);
269 bt_log_result(result
, fmt
, argptr
);
275 bt_test_suite_base(int (*fn
)(const void *), const char *id
, const void *fn_arg
, int forked
, int timeout
, const char *dsc
, ...)
279 printf("%28s - ", id
);
294 if (request
&& strcmp(id
, request
))
297 bt_suite_result
= BT_SUCCESS
;
300 if (bt_verbose
>= BT_VERBOSE_ABSOLUTELY_ALL
)
305 bt_suite_result
= bt_run_test_fn(fn
, fn_arg
, timeout
);
310 bt_syscall(pid
< 0, "fork");
315 _exit(bt_run_test_fn(fn
, fn_arg
, timeout
));
319 int rv
= waitpid(pid
, &s
, 0);
320 bt_syscall(rv
< 0, "waitpid");
325 bt_suite_result
= WEXITSTATUS(s
);
327 else if (WIFSIGNALED(s
))
329 /* Stopped by signal */
330 bt_suite_result
= BT_FAILURE
;
332 int sn
= WTERMSIG(s
);
335 bt_log("Timeout expired");
337 else if (sn
== SIGSEGV
)
339 bt_log("Segmentation fault");
342 else if (sn
!= SIGABRT
)
343 bt_log("Signal %d received", sn
);
346 if (WCOREDUMP(s
) && bt_verbose
)
347 bt_log("Core dumped");
350 if (bt_suite_result
== BT_FAILURE
)
351 bt_result
= BT_FAILURE
;
353 bt_log_suite_result(bt_suite_result
, NULL
);
356 return bt_suite_result
;
362 if (!list_tests
|| (list_tests
&& bt_result
!= BT_SUCCESS
))
363 bt_log_overall_result(bt_result
, "");
364 return bt_result
== BT_SUCCESS
? EXIT_SUCCESS
: EXIT_FAILURE
;
368 * bt_assert_batch__ - test a batch of inputs/outputs tests
369 * @opts: includes all necessary data
371 * Should be called using macro bt_assert_batch().
372 * Returns BT_SUCCESS or BT_FAILURE.
375 bt_assert_batch__(struct bt_batch
*opts
)
378 for (i
= 0; i
< opts
->ndata
; i
++)
380 int bt_suit_case_result
= opts
->test_fn(opts
->out_buf
, opts
->data
[i
].in
, opts
->data
[i
].out
);
382 if (bt_suit_case_result
== BT_FAILURE
)
383 bt_suite_result
= BT_FAILURE
;
385 char b
[BT_BUFFER_SIZE
];
386 snprintf(b
, sizeof(b
), "%s(", opts
->test_fn_name
);
388 opts
->in_fmt(b
+strlen(b
), sizeof(b
)-strlen(b
), opts
->data
[i
].in
);
389 sprintf_concat(b
, ") gives ");
390 opts
->out_fmt(b
+strlen(b
), sizeof(b
)-strlen(b
), opts
->out_buf
);
392 if (bt_suit_case_result
== BT_FAILURE
)
394 sprintf_concat(b
, ", but expecting is ");
395 opts
->out_fmt(b
+strlen(b
), sizeof(b
)-strlen(b
), opts
->data
[i
].out
);
398 bt_log_suite_case_result(bt_suit_case_result
, "%s", b
);
401 return bt_suite_result
;
405 * bt_fmt_str - formating string into output buffer
406 * @buf: buffer for write
407 * @size: empty size in @buf
408 * @data: null-byte terminated string
410 * This function can be used with bt_assert_batch() function.
411 * Input @data should be const char * string.
414 bt_fmt_str(char *buf
, size_t size
, const void *data
)
416 const byte
*s
= data
;
418 snprintf(buf
, size
, "\"");
421 snprintf(buf
+strlen(buf
), size
-strlen(buf
), bt_is_char(*s
) ? "%c" : "\\%03u", *s
);
424 snprintf(buf
+strlen(buf
), size
-strlen(buf
), "\"");
428 * bt_fmt_unsigned - formating unsigned int into output buffer
429 * @buf: buffer for write
430 * @size: empty size in @buf
431 * @data: unsigned number
433 * This function can be used with bt_assert_batch() function.
436 bt_fmt_unsigned(char *buf
, size_t size
, const void *data
)
438 const uint
*n
= data
;
439 snprintf(buf
, size
, "0x%x (%u)", *n
, *n
);
443 * bt_fmt_ipa - formating ip_addr into output buffer
444 * @buf: buffer for write
445 * @size: empty size in @buf
446 * @data: should be struct ip_addr *
448 * This function can be used with bt_assert_batch() function.
451 bt_fmt_ipa(char *buf
, size_t size
, const void *data
)
453 const ip_addr
*ip
= data
;
454 bsnprintf(buf
, size
, "%I", *ip
);
460 return (c
>= (byte
) 32 && c
<= (byte
) 126);
464 * Mock-ups of all necessary public functions in main.c
468 void async_config(void) {}
469 void async_dump(void) {}
470 void async_shutdown(void) {}
471 void cmd_check_config(char *name UNUSED
) {}
472 void cmd_reconfig(char *name UNUSED
, int type UNUSED
, int timeout UNUSED
) {}
473 void cmd_reconfig_confirm(void) {}
474 void cmd_reconfig_undo(void) {}
475 void cmd_shutdown(void) {}
476 void cmd_reconfig_undo_notify(void) {}
478 #include "nest/bird.h"
480 #include "conf/conf.h"
481 void sysdep_preconfig(struct config
*c UNUSED
) {}
482 int sysdep_commit(struct config
*new UNUSED
, struct config
*old UNUSED
) { return 0; }
483 void sysdep_shutdown_done(void) {}
485 #include "nest/cli.h"
486 int cli_get_command(cli
*c UNUSED
) { return 0; }
487 void cli_write_trigger(cli
*c UNUSED
) {}
488 cli
*cmd_reconfig_stored_cli
;