This commit...
* adds an automake-based system.
* removes glib dependencies from the library code (i.e. not from the tests),
replacing them with home-grown code.
* sets up the tests to run using the TAP library [1].
[1] https://github.com/shlomif/libtap-prev
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
--- /dev/null
+SUBDIRS = \
+ argpar \
+ tests
+
+ACLOCAL_AMFLAGS = -I m4
--- /dev/null
+noinst_LTLIBRARIES = libargpar.la
+
+libargpar_la_SOURCES = argpar.c argpar.h
* SOFTWARE.
*/
+#include <assert.h>
+#include <stdarg.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <glib.h>
-
-#include "common/assert.h"
-#include "common/common.h"
#include "argpar.h"
+#define argpar_realloc(_ptr, _type, _nmemb) ((_type *) realloc(_ptr, (_nmemb) * sizeof(_type)))
+#define argpar_calloc(_type, _nmemb) ((_type *) calloc((_nmemb), sizeof(_type)))
+#define argpar_zalloc(_type) argpar_calloc(_type, 1)
+
+#define ARGPAR_ASSERT(_cond) assert(_cond)
+
+static
+char *argpar_vasprintf(const char *fmt, va_list args)
+{
+ int len1, len2;
+ char *str;
+ va_list args2;
+
+ va_copy(args2, args);
+
+ len1 = vsnprintf(NULL, 0, fmt, args);
+ if (len1 < 0) {
+ str = NULL;
+ goto end;
+ }
+
+ str = malloc(len1 + 1);
+ if (!str) {
+ goto end;
+ }
+
+ len2 = vsnprintf(str, len1 + 1, fmt, args2);
+
+ ARGPAR_ASSERT(len1 == len2);
+
+end:
+ return str;
+}
+
+
+static
+char *argpar_asprintf(const char *fmt, ...)
+{
+ va_list args;
+ char *str;
+
+ va_start(args, fmt);
+ str = argpar_vasprintf(fmt, args);
+ va_end(args);
+
+ return str;
+}
+
+static
+bool argpar_string_append_printf(char **str, const char *fmt, ...)
+{
+ char *new_str = NULL;
+ char *addendum;
+ bool success;
+ va_list args;
+
+ ARGPAR_ASSERT(str);
+
+ va_start(args, fmt);
+ addendum = argpar_vasprintf(fmt, args);
+ va_end(args);
+
+ if (!addendum) {
+ success = false;
+ goto end;
+ }
+
+ new_str = argpar_asprintf("%s%s", *str ? *str : "", addendum);
+ if (!new_str) {
+ success = false;
+ goto end;
+ }
+
+ free(*str);
+ *str = new_str;
+
+ success = true;
+
+end:
+ free(addendum);
+
+ return success;
+}
+
static
void destroy_item(struct bt_argpar_item * const item)
{
if (item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
struct bt_argpar_item_opt * const opt_item = (void *) item;
- g_free((void *) opt_item->arg);
+ free((void *) opt_item->arg);
}
- g_free(item);
+ free(item);
end:
return;
}
+static
+bool push_item(struct bt_argpar_item_array * const array,
+ struct bt_argpar_item * const item)
+{
+ bool success;
+
+ ARGPAR_ASSERT(array);
+ ARGPAR_ASSERT(item);
+
+ if (array->n_items == array->n_alloc) {
+ unsigned int new_n_alloc = array->n_alloc * 2;
+ struct bt_argpar_item **new_items;
+
+ new_items = argpar_realloc(array->items,
+ struct bt_argpar_item *, new_n_alloc);
+ if (!new_items) {
+ success = false;
+ goto end;
+ }
+
+ array->n_alloc = new_n_alloc;
+ array->items = new_items;
+ }
+
+ array->items[array->n_items] = item;
+ array->n_items++;
+
+ success = true;
+
+end:
+ return success;
+}
+
+static
+void destroy_item_array(struct bt_argpar_item_array * const array)
+{
+ if (array) {
+ unsigned int i;
+
+ for (i = 0; i < array->n_items; i++) {
+ destroy_item(array->items[i]);
+ }
+
+ free(array->items);
+ free(array);
+ }
+}
+
+static
+struct bt_argpar_item_array *new_item_array(void)
+{
+ struct bt_argpar_item_array *ret;
+ const int initial_size = 10;
+
+ ret = argpar_zalloc(struct bt_argpar_item_array);
+ if (!ret) {
+ goto end;
+ }
+
+ ret->items = argpar_calloc(struct bt_argpar_item *, initial_size);
+ if (!ret->items) {
+ goto error;
+ }
+
+ ret->n_alloc = initial_size;
+
+ goto end;
+
+error:
+ destroy_item_array(ret);
+ ret = NULL;
+
+end:
+ return ret;
+}
+
static
struct bt_argpar_item_opt *create_opt_item(
const struct bt_argpar_opt_descr * const descr,
const char * const arg)
{
struct bt_argpar_item_opt *opt_item =
- g_new0(struct bt_argpar_item_opt, 1);
+ argpar_zalloc(struct bt_argpar_item_opt);
if (!opt_item) {
goto end;
opt_item->descr = descr;
if (arg) {
- opt_item->arg = g_strdup(arg);
+ opt_item->arg = strdup(arg);
if (!opt_item->arg) {
goto error;
}
const unsigned int non_opt_index)
{
struct bt_argpar_item_non_opt * const non_opt_item =
- g_new0(struct bt_argpar_item_non_opt, 1);
+ argpar_zalloc(struct bt_argpar_item_non_opt);
if (!non_opt_item) {
goto end;
const char *short_opt_ch = short_opts;
if (strlen(short_opts) == 0) {
- g_string_append(parse_ret->error, "Invalid argument");
+ argpar_string_append_printf(&parse_ret->error, "Invalid argument");
goto error;
}
descr = find_descr(descrs, *short_opt_ch, NULL);
if (!descr) {
ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
- g_string_append_printf(parse_ret->error,
+ argpar_string_append_printf(&parse_ret->error,
"Unknown option `-%c`", *short_opt_ch);
goto error;
}
* expected.
*/
if (!opt_arg || (short_opt_ch[1] && strlen(opt_arg) == 0)) {
- g_string_append_printf(parse_ret->error,
+ argpar_string_append_printf(&parse_ret->error,
"Missing required argument for option `-%c`",
*short_opt_ch);
*used_next_orig_arg = false;
goto error;
}
- g_ptr_array_add(parse_ret->items, opt_item);
+ if (!push_item(parse_ret->items, &opt_item->base)) {
+ goto error;
+ }
if (descr->with_arg) {
/* Option has an argument: no more options */
const char *long_opt_name = long_opt_arg;
if (strlen(long_opt_arg) == 0) {
- g_string_append(parse_ret->error, "Invalid argument");
+ argpar_string_append_printf(&parse_ret->error,
+ "Invalid argument");
goto error;
}
/* Isolate the option name */
if (long_opt_name_size > max_len) {
- g_string_append_printf(parse_ret->error,
+ argpar_string_append_printf(&parse_ret->error,
"Invalid argument `--%s`", long_opt_arg);
goto error;
}
/* Find corresponding option descriptor */
descr = find_descr(descrs, '\0', long_opt_name);
if (!descr) {
- g_string_append_printf(parse_ret->error,
+ argpar_string_append_printf(&parse_ret->error,
"Unknown option `--%s`", long_opt_name);
ret = PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT;
goto error;
} else {
/* `--long-opt arg` style */
if (!next_orig_arg) {
- g_string_append_printf(parse_ret->error,
+ argpar_string_append_printf(&parse_ret->error,
"Missing required argument for option `--%s`",
long_opt_name);
goto error;
goto error;
}
- g_ptr_array_add(parse_ret->items, opt_item);
+ if (!push_item(parse_ret->items, &opt_item->base)) {
+ goto error;
+ }
+
goto end;
error:
{
enum parse_orig_arg_opt_ret ret = PARSE_ORIG_ARG_OPT_RET_OK;
- BT_ASSERT(orig_arg[0] == '-');
+ ARGPAR_ASSERT(orig_arg[0] == '-');
if (orig_arg[1] == '-') {
/* Long option */
}
static
-void prepend_while_parsing_arg_to_error(GString * const error,
+bool prepend_while_parsing_arg_to_error(char **error,
const unsigned int i, const char * const arg)
{
- /* 🙁 There's no g_string_prepend_printf()! */
- GString * const tmp_str = g_string_new(NULL);
+ char *new_error;
+ bool success;
- BT_ASSERT(error);
- BT_ASSERT(arg);
+ ARGPAR_ASSERT(error);
+ ARGPAR_ASSERT(*error);
- if (!tmp_str) {
+ new_error = argpar_asprintf("While parsing argument #%u (`%s`): %s",
+ i + 1, arg, *error);
+ if (!new_error) {
+ success = false;
goto end;
}
- g_string_append_printf(tmp_str, "While parsing argument #%u (`%s`): %s",
- i + 1, arg, error->str);
- g_string_assign(error, tmp_str->str);
- g_string_free(tmp_str, TRUE);
+ free(*error);
+ *error = new_error;
+ success = true;
end:
- return;
+ return success;
}
-BT_HIDDEN
+ARGPAR_HIDDEN
struct bt_argpar_parse_ret bt_argpar_parse(unsigned int argc,
const char * const *argv,
const struct bt_argpar_opt_descr * const descrs,
unsigned int i;
unsigned int non_opt_index = 0;
- parse_ret.error = g_string_new(NULL);
- if (!parse_ret.error) {
- goto error;
- }
-
- parse_ret.items = g_ptr_array_new_with_free_func(
- (GDestroyNotify) destroy_item);
+ parse_ret.items = new_item_array();
if (!parse_ret.items) {
goto error;
}
}
non_opt_index++;
- g_ptr_array_add(parse_ret.items, non_opt_item);
+
+ if (!push_item(parse_ret.items, &non_opt_item->base)) {
+ goto error;
+ }
+
continue;
}
case PARSE_ORIG_ARG_OPT_RET_OK:
break;
case PARSE_ORIG_ARG_OPT_RET_ERROR_UNKNOWN_OPT:
- BT_ASSERT(!used_next_orig_arg);
+ ARGPAR_ASSERT(!used_next_orig_arg);
if (fail_on_unknown_opt) {
prepend_while_parsing_arg_to_error(
- parse_ret.error, i, orig_arg);
+ &parse_ret.error, i, orig_arg);
goto error;
}
* unknown option.
*/
parse_ret.ingested_orig_args = i;
- g_string_free(parse_ret.error, TRUE);
+ free(parse_ret.error);
parse_ret.error = NULL;
goto end;
case PARSE_ORIG_ARG_OPT_RET_ERROR:
prepend_while_parsing_arg_to_error(
- parse_ret.error, i, orig_arg);
+ &parse_ret.error, i, orig_arg);
goto error;
default:
- bt_common_abort();
+ abort();
}
if (used_next_orig_arg) {
}
parse_ret.ingested_orig_args = argc;
- g_string_free(parse_ret.error, TRUE);
+ free(parse_ret.error);
parse_ret.error = NULL;
goto end;
error:
- if (parse_ret.items) {
- /* That's how we indicate that an error occured */
- g_ptr_array_free(parse_ret.items, TRUE);
- parse_ret.items = NULL;
- }
+ /* That's how we indicate that an error occured */
+ destroy_item_array(parse_ret.items);
+ parse_ret.items = NULL;
end:
return parse_ret;
}
-BT_HIDDEN
+ARGPAR_HIDDEN
void bt_argpar_parse_ret_fini(struct bt_argpar_parse_ret *ret)
{
- BT_ASSERT(ret);
+ ARGPAR_ASSERT(ret);
- if (ret->items) {
- g_ptr_array_free(ret->items, TRUE);
- ret->items = NULL;
- }
+ destroy_item_array(ret->items);
+ ret->items = NULL;
- if (ret->error) {
- g_string_free(ret->error, TRUE);
- ret->error = NULL;
- }
+ free(ret->error);
+ ret->error = NULL;
}
* SOFTWARE.
*/
-#include <glib.h>
#include <stdbool.h>
-#include "common/macros.h"
-
/* Sentinel for an option descriptor array */
#define BT_ARGPAR_OPT_DESCR_SENTINEL { -1, '\0', NULL, false }
+/*
+ * ARGPAR_HIDDEN: if argpar is used in some shared library, we don't want them
+ * to be exported by that library, so mark them as "hidden".
+ *
+ * On Windows, symbols are local unless explicitly exported,
+ * see https://gcc.gnu.org/wiki/Visibility
+ */
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define ARGPAR_HIDDEN
+#else
+#define ARGPAR_HIDDEN __attribute__((visibility("hidden")))
+#endif
+
/* Option descriptor */
struct bt_argpar_opt_descr {
/* Numeric ID for this option */
unsigned int non_opt_index;
};
+struct bt_argpar_item_array {
+ /* Array of `struct bt_argpar_item *`, or `NULL` on error */
+ struct bt_argpar_item **items;
+
+ /* Number of used slots in `data`. */
+ unsigned int n_items;
+
+ /* Number of allocated slots in `data`. */
+ unsigned int n_alloc;
+};
+
/* What is returned by bt_argpar_parse() */
struct bt_argpar_parse_ret {
/* Array of `struct bt_argpar_item *`, or `NULL` on error */
- GPtrArray *items;
+ struct bt_argpar_item_array *items;
/* Error string, or `NULL` if none */
- GString *error;
+ char *error;
/* Number of original arguments (`argv`) ingested */
unsigned int ingested_orig_args;
* You can finalize the returned structure with
* bt_argpar_parse_ret_fini().
*/
-BT_HIDDEN
+ARGPAR_HIDDEN
struct bt_argpar_parse_ret bt_argpar_parse(unsigned int argc,
const char * const *argv,
const struct bt_argpar_opt_descr *descrs,
* It is safe to call bt_argpar_parse() multiple times with the same
* structure.
*/
-BT_HIDDEN
+ARGPAR_HIDDEN
void bt_argpar_parse_ret_fini(struct bt_argpar_parse_ret *ret);
#endif /* BABELTRACE_ARGPAR_H */
--- /dev/null
+AC_INIT([argpar], [1])
+AM_INIT_AUTOMAKE([foreign])
+LT_INIT
+
+AC_CONFIG_MACRO_DIRS([m4])
+
+# Depend on glib just for the tests.
+PKG_CHECK_MODULES([GLIB], [glib-2.0])
+
+AC_CONFIG_FILES([
+ Makefile
+ argpar/Makefile
+ tests/Makefile
+ tests/tap/Makefile
+])
+
+AC_OUTPUT
--- /dev/null
+SUBDIRS = tap
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/tests/tap \
+ $(GLIB_CFLAGS)
+
+noinst_PROGRAMS = test_argpar
+test_argpar_SOURCES = test_argpar.c
+test_argpar_LDADD = \
+ $(top_builddir)/tests/tap/libtap.la \
+ $(top_builddir)/argpar/libargpar.la \
+ $(GLIB_LIBS)
+
+TESTS = test_argpar
--- /dev/null
+noinst_LTLIBRARIES = libtap.la
+
+libtap_la_SOURCES = tap.c tap.h
--- /dev/null
+/*-
+ * Copyright (c) 2004 Nik Clayton
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tap.h"
+
+static int no_plan = 0;
+static int skip_all = 0;
+static int have_plan = 0;
+static unsigned int test_count = 0; /* Number of tests that have been run */
+static unsigned int e_tests = 0; /* Expected number of tests to run */
+static unsigned int failures = 0; /* Number of tests that failed */
+static char *todo_msg = NULL;
+static char *todo_msg_fixed = "libtap malloc issue";
+static int todo = 0;
+static int test_died = 0;
+static const int exit_die = 255; /* exit-code on die() */
+
+
+/* Encapsulate the pthread code in a conditional. In the absence of
+ libpthread the code does nothing */
+#if defined(LIBTAP_ENABLE_BROKEN_THREAD_SAFE) && defined(HAVE_LIBPTHREAD)
+#include <pthread.h>
+static pthread_mutex_t M = PTHREAD_MUTEX_INITIALIZER;
+# define LOCK pthread_mutex_lock(&M);
+# define UNLOCK pthread_mutex_unlock(&M);
+#else
+# define LOCK
+# define UNLOCK
+#endif
+
+static void _expected_tests(unsigned int);
+static void _tap_init(void);
+static void _cleanup(void);
+
+/*
+ * Generate a test result.
+ *
+ * ok -- boolean, indicates whether or not the test passed.
+ * test_name -- the name of the test, may be NULL
+ * test_comment -- a comment to print afterwards, may be NULL
+ */
+unsigned int
+_gen_result(int ok, const char *func, const char *file, unsigned int line,
+ const char *test_name, ...)
+{
+ va_list ap;
+ char *local_test_name = NULL;
+ char *c;
+ int name_is_digits;
+
+ LOCK;
+
+ test_count++;
+
+ /* Start by taking the test name and performing any printf()
+ expansions on it */
+ if(test_name != NULL) {
+ va_start(ap, test_name);
+ if (vasprintf(&local_test_name, test_name, ap) < 0)
+ {
+ local_test_name = NULL;
+ }
+ va_end(ap);
+
+ /* Make sure the test name contains more than digits
+ and spaces. Emit an error message and exit if it
+ does */
+ if(local_test_name) {
+ name_is_digits = 1;
+ for(c = local_test_name; *c != '\0'; c++) {
+ if(!isdigit(*c) && !isspace(*c)) {
+ name_is_digits = 0;
+ break;
+ }
+ }
+
+ if(name_is_digits) {
+ diag(" You named your test '%s'. You shouldn't use numbers for your test names.", local_test_name);
+ diag(" Very confusing.");
+ }
+ }
+ }
+
+ if(!ok) {
+ printf("not ");
+ failures++;
+ }
+
+ printf("ok %d", test_count);
+
+ if(test_name != NULL) {
+ printf(" - ");
+
+ /* Print the test name, escaping any '#' characters it
+ might contain */
+ if(local_test_name != NULL) {
+ flockfile(stdout);
+ for(c = local_test_name; *c != '\0'; c++) {
+ if(*c == '#')
+ fputc('\\', stdout);
+ fputc((int)*c, stdout);
+ }
+ funlockfile(stdout);
+ } else { /* vasprintf() failed, use a fixed message */
+ printf("%s", todo_msg_fixed);
+ }
+ }
+
+ /* If we're in a todo_start() block then flag the test as being
+ TODO. todo_msg should contain the message to print at this
+ point. If it's NULL then asprintf() failed, and we should
+ use the fixed message.
+
+ This is not counted as a failure, so decrement the counter if
+ the test failed. */
+ if(todo) {
+ printf(" # TODO %s", todo_msg ? todo_msg : todo_msg_fixed);
+ if(!ok)
+ failures--;
+ }
+
+ printf("\n");
+
+ if(!ok)
+ diag(" Failed %stest (%s:%s() at line %d)",
+ todo ? "(TODO) " : "", file, func, line);
+
+ free(local_test_name);
+
+ UNLOCK;
+
+ /* We only care (when testing) that ok is positive, but here we
+ specifically only want to return 1 or 0 */
+ return ok ? 1 : 0;
+}
+
+/*
+ * Initialise the TAP library. Will only do so once, however many times it's
+ * called.
+ */
+void
+_tap_init(void)
+{
+ static int run_once = 0;
+
+ LOCK;
+
+ if(!run_once) {
+ atexit(_cleanup);
+
+ /* stdout needs to be unbuffered so that the output appears
+ in the same place relative to stderr output as it does
+ with Test::Harness */
+ setbuf(stdout, 0);
+ run_once = 1;
+ }
+
+ UNLOCK;
+}
+
+/*
+ * Note that there's no plan.
+ */
+int
+plan_no_plan(void)
+{
+
+ LOCK;
+
+ _tap_init();
+
+ if(have_plan != 0) {
+ fprintf(stderr, "You tried to plan twice!\n");
+ test_died = 1;
+ UNLOCK;
+ exit(exit_die);
+ }
+
+ have_plan = 1;
+ no_plan = 1;
+
+ UNLOCK;
+
+ return 1;
+}
+
+/*
+ * Note that the plan is to skip all tests
+ */
+int
+plan_skip_all(const char *reason)
+{
+
+ LOCK;
+
+ _tap_init();
+
+ skip_all = 1;
+
+ printf("1..0");
+
+ if(reason != NULL)
+ printf(" # SKIP %s", reason);
+
+ printf("\n");
+
+ UNLOCK;
+
+ exit(0);
+}
+
+/*
+ * Note the number of tests that will be run.
+ */
+int
+plan_tests(unsigned int tests)
+{
+
+ LOCK;
+
+ _tap_init();
+
+ if(have_plan != 0) {
+ fprintf(stderr, "You tried to plan twice!\n");
+ test_died = 1;
+ UNLOCK;
+ exit(exit_die);
+ }
+
+ if(tests == 0) {
+ fprintf(stderr, "You said to run 0 tests! You've got to run something.\n");
+ test_died = 1;
+ UNLOCK;
+ exit(exit_die);
+ }
+
+ have_plan = 1;
+
+ _expected_tests(tests);
+
+ UNLOCK;
+
+ return 1;
+}
+
+unsigned int
+diag(const char *fmt, ...)
+{
+ va_list ap;
+
+ LOCK;
+
+ fputs("# ", stderr);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fputs("\n", stderr);
+
+ UNLOCK;
+
+ return 0;
+}
+
+void
+_expected_tests(unsigned int tests)
+{
+
+ LOCK;
+
+ printf("1..%d\n", tests);
+ e_tests = tests;
+
+ UNLOCK;
+}
+
+int
+skip(unsigned int n, const char *fmt, ...)
+{
+ va_list ap;
+ char *skip_msg;
+
+ LOCK;
+
+ va_start(ap, fmt);
+ if (vasprintf(&skip_msg, fmt, ap) < 0)
+ {
+ skip_msg = NULL;
+ }
+ va_end(ap);
+
+ while(n-- > 0) {
+ test_count++;
+ printf("ok %d # skip %s\n", test_count,
+ skip_msg != NULL ?
+ skip_msg : "libtap():malloc() failed");
+ }
+
+ free(skip_msg);
+
+ UNLOCK;
+
+ return 1;
+}
+
+void
+todo_start(const char *fmt, ...)
+{
+ va_list ap;
+
+ LOCK;
+
+ va_start(ap, fmt);
+ if (vasprintf(&todo_msg, fmt, ap) < 0)
+ {
+ todo_msg = NULL;
+ }
+ va_end(ap);
+
+ todo = 1;
+
+ UNLOCK;
+}
+
+void
+todo_end(void)
+{
+
+ LOCK;
+
+ todo = 0;
+ free(todo_msg);
+
+ UNLOCK;
+}
+
+int
+exit_status(void)
+{
+ int r;
+
+ LOCK;
+
+ /* If there's no plan, just return the number of failures */
+ if(no_plan || !have_plan) {
+ UNLOCK;
+ return failures;
+ }
+
+ /* Ran too many tests? Return the number of tests that were run
+ that shouldn't have been */
+ if(e_tests < test_count) {
+ r = test_count - e_tests;
+ UNLOCK;
+ return r;
+ }
+
+ /* Return the number of tests that failed + the number of tests
+ that weren't run */
+ r = failures + e_tests - test_count;
+ UNLOCK;
+
+ return r;
+}
+
+/*
+ * Cleanup at the end of the run, produce any final output that might be
+ * required.
+ */
+void
+_cleanup(void)
+{
+
+ LOCK;
+
+ /* If plan_no_plan() wasn't called, and we don't have a plan,
+ and we're not skipping everything, then something happened
+ before we could produce any output */
+ if(!no_plan && !have_plan && !skip_all) {
+ diag("Looks like your test died before it could output anything.");
+ UNLOCK;
+ return;
+ }
+
+ if(test_died) {
+ diag("Looks like your test exited with %d just after %d.", exit_die, test_count);
+ UNLOCK;
+ return;
+ }
+
+
+ /* No plan provided, but now we know how many tests were run, and can
+ print the header at the end */
+ if(!skip_all && (no_plan || !have_plan)) {
+ printf("1..%d\n", test_count);
+ }
+
+ if((have_plan && !no_plan) && e_tests < test_count) {
+ diag("Looks like you planned %d test%s but ran %d extra.",
+ e_tests, e_tests == 1 ? "":"s", test_count - e_tests);
+ UNLOCK;
+ return;
+ }
+
+ if((have_plan || !no_plan) && e_tests > test_count) {
+ diag("Looks like you planned %d test%s but ran %d.",
+ e_tests, e_tests == 1 ? "":"s", test_count);
+ UNLOCK;
+ return;
+ }
+
+ if(failures)
+ diag("Looks like you failed %d test%s of %d.",
+ failures, failures == 1 ? "":"s", test_count);
+
+ UNLOCK;
+}
--- /dev/null
+/*-
+ * Copyright (c) 2004 Nik Clayton
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/**
+ * plan_tests - announce the number of tests you plan to run
+ * @tests: the number of tests
+ *
+ * This should be the first call in your test program: it allows tracing
+ * of failures which mean that not all tests are run.
+ *
+ * If you don't know how many tests will actually be run, assume all of them
+ * and use skip() if you don't actually run some tests.
+ *
+ * Example:
+ * plan_tests(13);
+ */
+int plan_tests(unsigned int tests);
+static inline int plan(unsigned int tests)
+{
+ return plan_tests(tests);
+}
+#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(__GNUC__)
+# error "Needs gcc or C99 compiler for variadic macros."
+#else
+
+/**
+ * ok1 - Simple conditional test
+ * @e: the expression which we expect to be true.
+ *
+ * This is the simplest kind of test: if the expression is true, the
+ * test passes. The name of the test which is printed will simply be
+ * file name, line number, and the expression itself.
+ *
+ * Example:
+ * ok1(init_subsystem() == 1);
+ */
+# define ok1(e) ((e) ? \
+ _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \
+ _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e))
+
+/**
+ * ok - Conditional test with a name
+ * @e: the expression which we expect to be true.
+ * @...: the printf-style name of the test.
+ *
+ * If the expression is true, the test passes. The name of the test will be
+ * the filename, line number, and the printf-style string. This can be clearer
+ * than simply the expression itself.
+ *
+ * Example:
+ * ok1(init_subsystem() == 1);
+ * ok(init_subsystem() == 0, "Second initialization should fail");
+ */
+# define ok(e, ...) ((e) ? \
+ _gen_result(1, __func__, __FILE__, __LINE__, \
+ __VA_ARGS__) : \
+ _gen_result(0, __func__, __FILE__, __LINE__, \
+ __VA_ARGS__))
+
+/**
+ * pass - Note that a test passed
+ * @...: the printf-style name of the test.
+ *
+ * For complicated code paths, it can be easiest to simply call pass() in one
+ * branch and fail() in another.
+ *
+ * Example:
+ * x = do_something();
+ * if (!checkable(x) || check_value(x))
+ * pass("do_something() returned a valid value");
+ * else
+ * fail("do_something() returned an invalid value");
+ */
+# define pass(...) ok(1, __VA_ARGS__)
+
+/**
+ * fail - Note that a test failed
+ * @...: the printf-style name of the test.
+ *
+ * For complicated code paths, it can be easiest to simply call pass() in one
+ * branch and fail() in another.
+ */
+# define fail(...) ok(0, __VA_ARGS__)
+
+/* I don't find these to be useful. */
+# define skip_if(cond, n, ...) \
+ if (cond) skip((n), __VA_ARGS__); \
+ else
+
+# define skip_start(test, n, ...) \
+ do { \
+ if((test)) { \
+ skip(n, __VA_ARGS__); \
+ continue; \
+ }
+
+# define skip_end } while(0)
+
+#ifndef PRINTF_ATTRIBUTE
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+unsigned int _gen_result(int, const char *, const char *, unsigned int,
+ const char *, ...) PRINTF_ATTRIBUTE(5, 6);
+
+/**
+ * diag - print a diagnostic message (use instead of printf/fprintf)
+ * @fmt: the format of the printf-style message
+ *
+ * diag ensures that the output will not be considered to be a test
+ * result by the TAP test harness. It will append '\n' for you.
+ *
+ * Example:
+ * diag("Now running complex tests");
+ */
+unsigned int diag(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/**
+ * skip - print a diagnostic message (use instead of printf/fprintf)
+ * @n: number of tests you're skipping.
+ * @fmt: the format of the reason you're skipping the tests.
+ *
+ * Sometimes tests cannot be run because the test system lacks some feature:
+ * you should explicitly document that you're skipping tests using skip().
+ *
+ * From the Test::More documentation:
+ * If it's something the user might not be able to do, use SKIP. This
+ * includes optional modules that aren't installed, running under an OS that
+ * doesn't have some feature (like fork() or symlinks), or maybe you need an
+ * Internet connection and one isn't available.
+ *
+ * Example:
+ * #ifdef HAVE_SOME_FEATURE
+ * ok1(test_some_feature());
+ * #else
+ * skip(1, "Don't have SOME_FEATURE");
+ * #endif
+ */
+int skip(unsigned int n, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
+
+/**
+ * todo_start - mark tests that you expect to fail.
+ * @fmt: the reason they currently fail.
+ *
+ * It's extremely useful to write tests before you implement the matching fix
+ * or features: surround these tests by todo_start()/todo_end(). These tests
+ * will still be run, but with additional output that indicates that they are
+ * expected to fail.
+ *
+ * This way, should a test start to succeed unexpectedly, tools like prove(1)
+ * will indicate this and you can move the test out of the todo block. This
+ * is much more useful than simply commenting out (or '#if 0') the tests.
+ *
+ * From the Test::More documentation:
+ * If it's something the programmer hasn't done yet, use TODO. This is for
+ * any code you haven't written yet, or bugs you have yet to fix, but want to
+ * put tests in your testing script (always a good idea).
+ *
+ * Example:
+ * todo_start("dwim() not returning true yet");
+ * ok(dwim(), "Did what the user wanted");
+ * todo_end();
+ */
+void todo_start(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/**
+ * todo_end - end of tests you expect to fail.
+ *
+ * See todo_start().
+ */
+void todo_end(void);
+
+/**
+ * exit_status - the value that main should return.
+ *
+ * For maximum compatability your test program should return a particular exit
+ * code (ie. 0 if all tests were run, and every test which was expected to
+ * succeed succeeded).
+ *
+ * Example:
+ * exit(exit_status());
+ */
+int exit_status(void);
+
+/**
+ * plan_no_plan - I have no idea how many tests I'm going to run.
+ *
+ * In some situations you may not know how many tests you will be running, or
+ * you are developing your test program, and do not want to update the
+ * plan_tests() call every time you make a change. For those situations use
+ * plan_no_plan() instead of plan_tests(). It indicates to the test harness
+ * that an indeterminate number of tests will be run.
+ *
+ * Remember, if you fail to plan, you plan to fail.
+ *
+ * Example:
+ * plan_no_plan();
+ * while (random() % 2)
+ * ok1(some_test());
+ * exit(exit_status());
+ */
+int plan_no_plan(void);
+
+/**
+ * plan_skip_all - Indicate that you will skip all tests.
+ * @reason: the string indicating why you can't run any tests.
+ *
+ * If your test program detects at run time that some required functionality
+ * is missing (for example, it relies on a database connection which is not
+ * present, or a particular configuration option that has not been included
+ * in the running kernel) use plan_skip_all() instead of plan_tests().
+ *
+ * Example:
+ * if (!have_some_feature) {
+ * plan_skip_all("Need some_feature support");
+ * exit(exit_status());
+ * }
+ * plan_tests(13);
+ */
+int plan_skip_all(const char *reason);
+
+#endif /* C99 or gcc */
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "tap/tap.h"
-#include "common/assert.h"
-
#include "argpar/argpar.h"
/*
gchar **argv = g_strsplit(cmdline, " ", 0);
unsigned int i;
- BT_ASSERT(argv);
- BT_ASSERT(res_str);
+ assert(argv);
+ assert(res_str);
parse_ret = bt_argpar_parse(g_strv_length(argv),
(const char * const *) argv, descrs, false);
ok(parse_ret.items,
goto end;
}
- for (i = 0; i < parse_ret.items->len; i++) {
- const struct bt_argpar_item *arg = parse_ret.items->pdata[i];
+ for (i = 0; i < parse_ret.items->n_items; i++) {
+ const struct bt_argpar_item *arg = parse_ret.items->items[i];
switch (arg->type) {
case BT_ARGPAR_ITEM_TYPE_OPT:
goto end;
}
- ok(strcmp(expected_error, parse_ret.error->str) == 0,
+ ok(strcmp(expected_error, parse_ret.error) == 0,
"bt_argpar_parse() writes the expected error string "
"for command line `%s`", cmdline);
- if (strcmp(expected_error, parse_ret.error->str) != 0) {
+ if (strcmp(expected_error, parse_ret.error) != 0) {
diag("Expected: `%s`", expected_error);
- diag("Got: `%s`", parse_ret.error->str);
+ diag("Got: `%s`", parse_ret.error);
}
end: