68static const char *
const test_result2str[] = {
91 ast_test_init_cb_t *init_cb;
97static struct ast_test_execute_results {
98 unsigned int total_tests;
99 unsigned int total_passed;
100 unsigned int total_failed;
101 unsigned int total_time;
102 unsigned int last_passed;
103 unsigned int last_failed;
104 unsigned int last_time;
110 TEST_NAME_CATEGORY = 2,
114 ({ if (fp != NULL) { \
129#define movefd(oldfd, newfd) \
130 ({ if (oldfd != newfd) { \
131 dup2(oldfd, newfd); \
138#define lowerfd(oldfd) \
139 ({ int newfd = dup(oldfd); \
152static struct ast_test *
test_alloc(ast_test_cb_t *cb);
153static struct ast_test *test_free(
struct ast_test *
test);
154static int test_insert(
struct ast_test *
test);
155static struct ast_test *test_remove(ast_test_cb_t *cb);
156static int test_cat_cmp(
const char *
cat1,
const char *
cat2);
157static int registration_errors = 0;
180int __ast_test_status_update(
const char *
file,
const char *func,
int line,
struct ast_test *
test,
const char *fmt, ...)
206int ast_test_register_init(
const char *category, ast_test_init_cb_t *cb)
208 struct ast_test *
test;
213 if (!(test_cat_cmp(
test->info.category, category))) {
223int ast_test_register_cleanup(
const char *category, ast_test_cleanup_cb_t *cb)
225 struct ast_test *
test;
230 if (!(test_cat_cmp(
test->info.category, category))) {
231 test->cleanup_cb = cb;
240int ast_test_register(ast_test_cb_t *cb)
242 struct ast_test *
test;
245 ast_log(
LOG_ERROR,
"Attempted to register test without all required information\n");
246 registration_errors++;
251 registration_errors++;
255 if (test_insert(
test)) {
257 registration_errors++;
264int ast_test_unregister(ast_test_cb_t *cb)
266 struct ast_test *
test;
268 if (!(
test = test_remove(cb))) {
284static void test_execute(
struct ast_test *
test)
286 struct timeval begin;
338int ast_test_capture_command(
struct ast_test_capture *capture,
const char *
file,
char *
const argv[],
const char *data,
unsigned datalen)
340 int fd0[2] = { -1, -1 }, fd1[2] = { -1, -1 }, fd2[2] = { -1, -1 };
345 ast_test_capture_init(capture);
347 if (data !=
NULL && datalen > 0) {
348 if (pipe(fd0) == -1) {
352 fcntl(fd0[1], F_SETFL, fcntl(fd0[1], F_GETFL, 0) | O_NONBLOCK);
354 if ((fd0[0] = open(
"/dev/null", O_RDONLY)) == -1) {
360 if (pipe(fd1) == -1) {
365 if (pipe(fd2) == -1) {
373 if ((pid = fork()) == -1) {
377 }
else if (pid == 0) {
393 int wstatus, n, nfds;
394 fd_set readfds, writefds;
405 if ((cmd = fmemopen(
buf,
sizeof(
buf),
"w")) ==
NULL) {
410 for (i = 0; argv[i] !=
NULL; ++i) {
433 n = waitpid(pid, &wstatus, WNOHANG);
454 nfds =
MAX(fd0[1],
MAX(fd1[0], fd2[0])) + 1;
460 if (data !=
NULL && datalen > 0)
461 FD_SET(fd0[1], &writefds);
473 n = select(nfds, &readfds, &writefds,
NULL,
NULL);
476#define SAFE_FD_ISSET(fd, setptr) ((fd) != -1 && FD_ISSET((fd), setptr))
478 if (SAFE_FD_ISSET(fd0[1], &writefds)) {
479 n = write(fd0[1], data, datalen);
482 datalen -=
MIN(datalen, n);
491 if (SAFE_FD_ISSET(fd1[0], &readfds)) {
492 n = read(fd1[0],
buf,
sizeof(
buf));
494 fwrite(
buf,
sizeof(
char), n,
out);
500 if (SAFE_FD_ISSET(fd2[0], &readfds)) {
501 n = read(fd2[0],
buf,
sizeof(
buf));
503 fwrite(
buf,
sizeof(
char), n, err);
534static char *reserved_words[] = {
535 "abstract",
"arguments",
"as",
"assert",
"await",
536 "boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
537 "const",
"continue",
"debugger",
"def",
"default",
"delete",
"do",
538 "double",
"else",
"enum",
"eval",
"export",
"extends",
"false",
539 "final",
"finally",
"float",
"for",
"function",
"goto",
"if",
540 "implements",
"import",
"in",
"instanceof",
"int",
"interface",
541 "let",
"long",
"native",
"new",
"null",
"package",
"private",
542 "protected",
"public",
"return",
"short",
"static",
"strictfp",
543 "string",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
544 "trait",
"transient",
"true",
"try",
"typeof",
"var",
"void",
545 "volatile",
"while",
"with",
"yield" };
547static int is_reserved_word(
const char *
word)
551 for (i = 0; i <
ARRAY_LEN(reserved_words); i++) {
552 if (strcmp(
word, reserved_words[i]) == 0) {
560static void test_xml_entry(
struct ast_test *
test, FILE *f)
565 char *test_name = (
char *)
test->info.
name;
577 if (is_reserved_word(next_cat)) {
586 if (is_reserved_word(
test->info.
name)) {
587 size_t name_length = strlen(
test->info.
name) + 2;
590 snprintf(test_name, name_length,
"_%s",
test->info.
name);
593 fprintf(f,
"\t\t<testcase time=\"%u.%u\" classname=\"%s\" name=\"%s\"%s>\n",
594 test->time / 1000,
test->time % 1000,
601 fprintf(f,
"\t\t\t<failure><![CDATA[\n%s\n\t\t]]></failure>\n",
603 fprintf(f,
"\t\t</testcase>\n");
608static void test_txt_entry(
struct ast_test *
test, FILE *f)
614 fprintf(f,
"\nName: %s\n",
test->info.
name);
615 fprintf(f,
"Category: %s\n",
test->info.category);
616 fprintf(f,
"Summary: %s\n",
test->info.summary);
617 fprintf(f,
"Description: %s\n",
test->info.description);
618 fprintf(f,
"Result: %s\n", test_result2str[
test->state]);
620 fprintf(f,
"Time: %u\n",
test->time);
642static int test_execute_multiple(
const char *
name,
const char *category,
struct ast_cli_args *
cli)
646 enum test_mode mode = TEST_ALL;
652 mode = TEST_NAME_CATEGORY;
660 memset(&last_results, 0,
sizeof(last_results));
666 if (!test_cat_cmp(
test->info.category, category) && !
test->info.explicit_only) {
670 case TEST_NAME_CATEGORY:
671 if (!(test_cat_cmp(
test->info.category, category)) && !(strcmp(
test->info.
name,
name))) {
693 last_results.last_time +=
test->time;
695 last_results.last_passed++;
697 last_results.last_failed++;
702 test_result2str[
test->state],
706 ast_cli(
cli->fd,
"END %s - %s Time: %s%ums Result: %s\n",
709 test->time ?
"" :
"<",
717 last_results.total_time +=
test->time;
719 last_results.total_tests++;
721 last_results.total_passed++;
723 last_results.total_failed++;
727 res = last_results.last_passed + last_results.last_failed;
752static int test_generate_results(
const char *
name,
const char *category,
const char *xml_path,
const char *txt_path)
754 enum test_mode mode = TEST_ALL;
767 mode = TEST_NAME_CATEGORY;
774 if (!(f_xml = fopen(xml_path,
"w"))) {
781 if (!(f_txt = fopen(txt_path,
"w"))) {
782 ast_log(
LOG_WARNING,
"Could not open file %s for text output of test results\n", txt_path);
794 fprintf(f_xml,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
795 fprintf(f_xml,
"<testsuites>\n");
796 fprintf(f_xml,
"\t<testsuite errors=\"0\" time=\"%u.%u\" tests=\"%u\" failures=\"%u\" "
797 "name=\"AsteriskUnitTests\">\n",
798 last_results.total_time / 1000, last_results.total_time % 1000,
799 last_results.total_tests, last_results.total_failed);
800 fprintf(f_xml,
"\t\t<properties>\n");
801 fprintf(f_xml,
"\t\t\t<property name=\"version\" value=\"%s\"/>\n",
ast_get_version());
802 fprintf(f_xml,
"\t\t</properties>\n");
809 fprintf(f_txt,
"Number of Tests: %u\n", last_results.total_tests);
810 fprintf(f_txt,
"Number of Tests Executed: %u\n", (last_results.total_passed + last_results.total_failed));
811 fprintf(f_txt,
"Passed Tests: %u\n", last_results.total_passed);
812 fprintf(f_txt,
"Failed Tests: %u\n", last_results.total_failed);
813 fprintf(f_txt,
"Total Execution Time: %u\n", last_results.total_time);
820 if (!test_cat_cmp(
test->info.category, category)) {
821 test_xml_entry(
test, f_xml);
822 test_txt_entry(
test, f_txt);
825 case TEST_NAME_CATEGORY:
826 if (!(strcmp(
test->info.category, category)) && !(strcmp(
test->info.
name,
name))) {
827 test_xml_entry(
test, f_xml);
828 test_txt_entry(
test, f_txt);
832 test_xml_entry(
test, f_xml);
833 test_txt_entry(
test, f_txt);
840 fprintf(f_xml,
"\t</testsuite>\n");
841 fprintf(f_xml,
"</testsuites>\n");
858static int test_insert(
struct ast_test *
test)
878static struct ast_test *test_remove(ast_test_cb_t *cb)
880 struct ast_test *cur =
NULL;
903static int test_cat_cmp(
const char *
cat1,
const char *
cat2)
919 return strncmp(
cat1,
cat2, len2) ? 1 : 0;
926static struct ast_test *test_free(
struct ast_test *
test)
942static struct ast_test *
test_alloc(ast_test_cb_t *cb)
944 struct ast_test *
test;
958 return test_free(
test);
964 return test_free(
test);
967 if (
test->info.category[0] !=
'/' ||
test->info.category[strlen(
test->info.category) - 1] !=
'/') {
968 ast_log(
LOG_WARNING,
"Test category '%s' for test '%s' is missing a leading or trailing slash.\n",
974 ++registration_errors;
978 ast_log(
LOG_ERROR,
"Test %s%s has no summary, test registration refused.\n",
980 return test_free(
test);
982 if (
test->info.summary[strlen(
test->info.summary) - 1] ==
'\n') {
989 ++registration_errors;
993 ast_log(
LOG_ERROR,
"Test %s%s has no description, test registration refused.\n",
995 return test_free(
test);
997 if (
test->info.description[strlen(
test->info.description) - 1] ==
'\n') {
1004 ++registration_errors;
1008 ast_log(
LOG_ERROR,
"Failed to allocate status_str for %s%s, test registration failed.\n",
1010 return test_free(
test);
1021static char *complete_test_category(
const char *
word)
1023 int wordlen = strlen(
word);
1024 struct ast_test *
test;
1028 if (!strncasecmp(
word,
test->info.category, wordlen)) {
1039static char *complete_test_name(
const char *
word,
const char *category)
1041 int wordlen = strlen(
word);
1042 struct ast_test *
test;
1046 if (!test_cat_cmp(
test->info.category, category) && !strncasecmp(
word,
test->info.
name, wordlen)) {
1060#define FORMAT "%-25.25s %-30.30s %-40.40s %-13.13s\n"
1061 static const char *
const option1[] = {
"all",
"category",
NULL };
1062 static const char *
const option2[] = {
"name",
NULL };
1067 e->
command =
"test show registered";
1070 "Usage: 'test show registered' can be used in three ways.\n"
1071 " 1. 'test show registered all' shows all registered tests\n"
1072 " 2. 'test show registered category [test category]' shows all tests in the given\n"
1074 " 3. 'test show registered category [test category] name [test name]' shows all\n"
1075 " tests in a given category matching a given name\n";
1081 if (
a->pos == 4 && !strcasecmp(
a->argv[3],
"category")) {
1082 return complete_test_category(
a->word);
1088 return complete_test_name(
a->word,
a->argv[4]);
1092 if ((
a->argc < 4) || (
a->argc == 6) || (
a->argc > 7) ||
1093 ((
a->argc == 4) && strcasecmp(
a->argv[3],
"all")) ||
1094 ((
a->argc == 7) && strcasecmp(
a->argv[5],
"name"))) {
1097 ast_cli(
a->fd,
FORMAT,
"Category",
"Name",
"Summary",
"Test Result");
1098 ast_cli(
a->fd,
FORMAT,
"--------",
"----",
"-------",
"-----------");
1101 if ((
a->argc == 4) ||
1102 ((
a->argc == 5) && !test_cat_cmp(
test->info.category,
a->argv[4])) ||
1103 ((
a->argc == 7) && !strcmp(
test->info.category,
a->argv[4]) && !strcmp(
test->info.
name,
a->argv[6]))) {
1106 test->info.summary, test_result2str[
test->state]);
1111 ast_cli(
a->fd,
FORMAT,
"--------",
"----",
"-------",
"-----------");
1112 ast_cli(
a->fd,
"\n%d Registered Tests Matched\n", count);
1122 static const char *
const option1[] = {
"all",
"category",
NULL };
1123 static const char *
const option2[] = {
"name",
"options",
NULL };
1124 static const char *
const option3[] = {
"options",
NULL };
1130 "Usage: test execute can be used in several ways.\n"
1131 " 1. 'test execute all' runs all registered tests\n"
1132 " 2. 'test execute category [test category]' runs all tests in the given\n"
1134 " 3. 'test execute category [test category] options [test option]...' runs all\n"
1135 " tests in the given category with options supplied to each test\n"
1136 " 4. 'test execute category [test category] name [test name]' runs all\n"
1137 " tests in a given category matching a given name\n"
1138 " 5. 'test execute category [test category] name [test name] options [test option]...' runs all\n"
1139 " tests in a given category matching a given name with the specified options\n"
1146 if (
a->pos == 3 && !strcasecmp(
a->argv[2],
"category")) {
1147 return complete_test_category(
a->word);
1152 if (
a->pos == 5 && !strcasecmp(
a->argv[4],
"name")) {
1153 return complete_test_name(
a->word,
a->argv[3]);
1155 if (
a->pos == 5 && !strcasecmp(
a->argv[4],
"options")) {
1158 if (
a->pos == 6 && !strcasecmp(
a->argv[4],
"name")) {
1168 if ((
a->argc == 3) && !strcasecmp(
a->argv[2],
"all")) {
1169 ast_cli(
a->fd,
"Running all available tests...\n\n");
1171 }
else if (
a->argc == 4) {
1172 ast_cli(
a->fd,
"Running all available tests matching category %s\n\n",
a->argv[3]);
1173 test_execute_multiple(
NULL,
a->argv[3],
a);
1174 }
else if (
a->argc >= 6 && !strcasecmp(
a->argv[4],
"options")) {
1175 ast_cli(
a->fd,
"Running all available tests matching category %s with options\n\n",
a->argv[3]);
1176 test_execute_multiple(
NULL,
a->argv[3],
a);
1177 }
else if (
a->argc == 6 && !strcasecmp(
a->argv[4],
"name")) {
1178 ast_cli(
a->fd,
"Running all available tests matching category %s and name %s\n\n",
a->argv[3],
a->argv[5]);
1179 test_execute_multiple(
a->argv[5],
a->argv[3],
a);
1180 }
else if (
a->argc > 7) {
1181 ast_cli(
a->fd,
"Running all available tests matching category %s and name %s with options\n\n",
a->argv[3],
a->argv[5]);
1182 test_execute_multiple(
a->argv[5],
a->argv[3],
a);
1188 if (!(last_results.last_passed + last_results.last_failed)) {
1189 ast_cli(
a->fd,
"--- No Tests Found! ---\n");
1191 ast_cli(
a->fd,
"\n%u Test(s) Executed %u Passed %u Failed\n",
1192 (last_results.last_passed + last_results.last_failed),
1193 last_results.last_passed,
1194 last_results.last_failed);
1205#define FORMAT_RES_ALL1 "%s%s %-30.30s %-25.25s %-10.10s\n"
1206#define FORMAT_RES_ALL2 "%s%s %-30.30s %-25.25s %s%ums\n"
1207 static const char *
const option1[] = {
"all",
"failed",
"passed",
NULL };
1216 e->
command =
"test show results";
1218 "Usage: test show results can be used in three ways\n"
1219 " 1. 'test show results all' Displays results for all executed tests.\n"
1220 " 2. 'test show results passed' Displays results for all passed tests.\n"
1221 " 3. 'test show results failed' Displays results for all failed tests.\n";
1233 }
else if (!strcasecmp(
a->argv[3],
"passed")) {
1235 }
else if (!strcasecmp(
a->argv[3],
"failed")) {
1237 }
else if (!strcasecmp(
a->argv[3],
"all")) {
1243 ast_cli(
a->fd, FORMAT_RES_ALL1,
"Result",
"",
"Name",
"Category",
"Time");
1260 test->info.category,
1261 test->time ?
" " :
"<",
1267 ast_cli(
a->fd,
"%d Test(s) Executed %d Passed %d Failed\n", (failed + passed), passed, failed);
1276 static const char *
const option[] = {
"xml",
"txt",
NULL };
1278 const char *
type =
"";
1286 e->
command =
"test generate results";
1288 "Usage: 'test generate results'\n"
1289 " Generates test results in either xml or txt format. An optional \n"
1290 " file path may be provided to specify the location of the xml or\n"
1292 " \nExample usage:\n"
1293 " 'test generate results xml' this writes to a default file\n"
1294 " 'test generate results xml /path/to/file.xml' writes to specified file\n";
1304 if (
a->argc < 4 ||
a->argc > 5) {
1306 }
else if (!strcasecmp(
a->argv[3],
"xml")) {
1309 }
else if (!strcasecmp(
a->argv[3],
"txt")) {
1347 AST_CLI_DEFINE(test_cli_show_registered,
"show registered tests"),
1348 AST_CLI_DEFINE(test_cli_execute_registered,
"execute registered tests"),
1350 AST_CLI_DEFINE(test_cli_generate_results,
"generate test results to file"),
1355 return test_suite_topic;
1362struct ast_test_suite_message_payload {
1370static void test_suite_message_payload_dtor(
void *obj)
1372 struct ast_test_suite_message_payload *payload = obj;
1374 if (payload->blob) {
1379struct ast_json *ast_test_suite_get_blob(
struct ast_test_suite_message_payload *payload)
1381 return payload->blob;
1387 struct ast_test_suite_message_payload *payload;
1395 blob = ast_test_suite_get_blob(payload);
1427 .
to_ami = test_suite_event_to_ami);
1429void __ast_test_suite_event_notify(
const char *
file,
const char *func,
int line,
const char *
state,
const char *fmt, ...)
1431 RAII_VAR(
struct ast_test_suite_message_payload *, payload,
1438 if (!ast_test_suite_message_type()) {
1447 payload =
ao2_alloc(
sizeof(*payload), test_suite_message_payload_dtor);
1455 payload->blob =
ast_json_pack(
"{s: s, s: s, s: s, s: s, s: i, s: s}",
1456 "type",
"testevent",
1459 "appfunction", func,
1462 if (!payload->blob) {
1476 info->name =
"registrations";
1477 info->category =
"/main/test/";
1478 info->summary =
"Validate Test Registration Data.";
1479 info->description =
"Validate Test Registration Data.";
1485 if (registration_errors) {
1487 "%d test registration error%s occurred. See startup logs for details.\n",
1488 registration_errors, registration_errors > 1 ?
"s" :
"");
1495static void test_cleanup(
void)
1500 test_suite_topic =
NULL;
1507#ifdef TEST_FRAMEWORK
1512 if (!test_suite_topic) {
Prototypes for public functions only of internal interest,.
Asterisk version information.
const char * ast_get_version(void)
Retrieve the Asterisk version string.
const char * ast_get_version_num(void)
Retrieve the numeric Asterisk version.
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
void ast_std_free(void *ptr)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_calloc(num, len)
A wrapper for calloc()
#define ao2_alloc(data_size, destructor_fn)
Standard Command Line Interface.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_CLI_DEFINE(fn, txt,...)
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
void ast_cli(int fd, const char *fmt,...)
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
static struct ast_cli_entry cli[]
static struct ast_threadstorage result_buf
static SQLHSTMT execute(struct odbc_obj *obj, void *data, int silent)
Common execution function for SQL queries.
static char prefix[MAX_PREFIX]
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
Support for logging to various files, console and syslog Configuration in file logger....
Asterisk JSON abstraction layer.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_INSERT_SORTALPHA(head, elm, field, sortfield)
Inserts a list entry into a alphabetically sorted list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_LOCK(head)
Locks a list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
#define WEXITSTATUS(status)
#define WIFEXITED(status)
#define EVENT_FLAG_REPORTING
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_LOG_DIR
static void * cleanup(void *unused)
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
static int cleanup_cb(void *obj, void *arg, int flags)
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
struct stasis_topic * stasis_topic_create(const char *name)
Create a new topic.
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
descriptor for a cli entry.
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Support for dynamic strings.
A capture of running an external process.
char * outbuf
buffer holding stdout
char * errbuf
buffer holding stderr
size_t errlen
length of buffer holding stderr
pid_t pid
process id of child
size_t outlen
length of buffer holding stdout
int exitcode
exit code of child
Contains all the initialization information required to store a new test definition.
Handy terminal functions for vt* terms.
char * term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout)
Colorize a specified string by adding terminal color codes.
#define ast_test_debug(test, fmt,...)
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
#define AST_TEST_DEFINE(hdr)
static struct test_listener_data * test_alloc(void)
Time-related functions and macros.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.