@@ -3,7 +3,7 @@ AM_MAKEFLAGS = --no-print-directory
GIT_SHA1 ?= `git --work-tree=$(top_srcdir) --git-dir=$(top_srcdir)/.git describe --always --long --dirty || echo unknown`
-bin_PROGRAMS = pdbg
+bin_PROGRAMS = pdbg optcmd_test
ACLOCAL_AMFLAGS = -Im4
AM_CFLAGS = -I$(top_srcdir)/ccan/array_size -Wall -Werror -O2
@@ -26,6 +26,9 @@ DT_headers = $(DT:.dts=.dt.h)
BUILT_SOURCES = $(DT) $(DT_headers)
+optcmd_test_SOURCES = src/optcmd.c src/parsers.c src/tests/optcmd_test.c
+optcmd_test_CFLAGS = -Wall -g
+
pdbg_SOURCES = \
src/main.c \
src/cfam.c \
new file mode 100644
@@ -0,0 +1,161 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <ccan/array_size/array_size.h>
+
+#include "../optcmd.h"
+#include "../parsers.h"
+
+/* The OPTCMD_TEST_BREAK_BUILD* defines can be used to test that we catch type
+ * mistmatch errors between function/flag definitions and parsers */
+#ifdef OPTCMD_TEST_BREAK_BUILD1
+struct flags {
+ bool test_bool;
+ int test_num;
+};
+#else
+struct flags {
+ bool test_bool;
+ uint64_t test_num;
+};
+#endif
+
+/* Format: (<flag>, <field>, <parser>, <default value>) */
+#define FLAG_TEST_BOOL ("--test-bool", test_bool, parse_flag_noarg, false)
+#define FLAG_TEST_NUM ("--test-num", test_num, parse_number64, 10)
+
+/* Format: (<parser>, <default value>)
+ *
+ * <default value> may be NULL if argument must be supplied.
+ */
+#define ARG_NUM (parse_number64, NULL)
+#define ARG_NUM_OPT (parse_number64, "2")
+
+static uint64_t num, opt, flag;
+static bool bool_flag;
+
+static int test(void)
+{
+ bool_flag = true;
+
+ return 0;
+}
+OPTCMD_DEFINE_CMD(test, test);
+
+#ifdef OPTCMD_TEST_BREAK_BUILD2
+static int test_args(int num_arg, int opt_arg)
+{
+ return 0;
+}
+#else
+static int test_args(uint64_t num_arg, uint64_t opt_arg)
+{
+ num = num_arg;
+ opt = opt_arg;
+
+ return 0;
+}
+#endif
+OPTCMD_DEFINE_CMD_WITH_ARGS(test_args, test_args, (ARG_NUM, ARG_NUM_OPT));
+
+static int test_flags(uint64_t num_arg, uint64_t opt_arg, struct flags flags)
+{
+ num = num_arg;
+ opt = opt_arg;
+ flag = flags.test_num;
+ bool_flag = flags.test_bool;
+
+ return 0;
+}
+OPTCMD_DEFINE_CMD_WITH_FLAGS(test_flags, test_flags, (ARG_NUM, ARG_NUM_OPT),
+ flags, (FLAG_TEST_BOOL, FLAG_TEST_NUM));
+
+int parse_argv(const char *argv[], int argc)
+{
+ int i, rc;
+ void **args, **flags;
+ struct optcmd_cmd *cmds[] = { &optcmd_test, &optcmd_test_args, &optcmd_test_flags };
+ optcmd_cmd_t *cmd;
+
+ for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+ if (!strcmp(argv[0], cmds[i]->cmd)) {
+ /* Found our command */
+ cmd = optcmd_parse(cmds[i], &argv[1], argc - 1, &args, &flags);
+ if (cmd) {
+ rc = cmd(args, flags);
+ return rc;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int main(void)
+{
+ /* Tests */
+ const char *test1_argv[] = { "test" };
+ bool_flag = false;
+ assert(!parse_argv(test1_argv, ARRAY_SIZE(test1_argv)));
+ assert(bool_flag);
+
+ const char *test2_argv[] = { "test_args", "1" };
+ assert(!parse_argv(test2_argv, ARRAY_SIZE(test2_argv)));
+ assert(num == 1);
+ assert(opt == 2);
+
+ const char *test3_argv[] = { "test_args", "2", "3" };
+ assert(!parse_argv(test3_argv, ARRAY_SIZE(test3_argv)));
+ assert(num == 2);
+ assert(opt == 3);
+
+ const char *test4_argv[] = { "test_flags", "4", "5" };
+ assert(!parse_argv(test4_argv, ARRAY_SIZE(test4_argv)));
+ assert(num == 4);
+ assert(opt == 5);
+ assert(flag == 10);
+
+ bool_flag = false;
+
+ const char *test5_argv[] = { "test_flags", "5", "6" };
+ assert(!parse_argv(test5_argv, ARRAY_SIZE(test5_argv)));
+ assert(num == 5);
+ assert(opt == 6);
+ assert(flag == 10);
+ assert(!bool_flag);
+
+ const char *test6_argv[] = { "test_flags", "7", "8", "--test-num=9" };
+ assert(!parse_argv(test6_argv, ARRAY_SIZE(test6_argv)));
+ assert(num == 7);
+ assert(opt == 8);
+ assert(flag == 9);
+ assert(!bool_flag);
+
+ const char *test7_argv[] = { "test_flags", "8", "9", "--test-bool" };
+ assert(!parse_argv(test7_argv, ARRAY_SIZE(test7_argv)));
+ assert(num == 8);
+ assert(opt == 9);
+ assert(flag == 10);
+ assert(bool_flag);
+
+ bool_flag = false;
+
+ const char *test8_argv[] = { "test_flags", "9", "10", "--test-bool", "--test-num=11" };
+ assert(!parse_argv(test8_argv, ARRAY_SIZE(test8_argv)));
+ assert(num == 9);
+ assert(opt == 10);
+ assert(flag == 11);
+ assert(bool_flag);
+
+ /* This should fail, too many arguments */
+ const char *test9_argv[] = { "test_flags", "9", "10", "11", "--test-bool", "--test-num=11" };
+ assert(parse_argv(test9_argv, ARRAY_SIZE(test9_argv)));
+
+ /* So should this, unknown flag */
+ const char *test10_argv[] = { "test_flags", "9", "10", "--test-blah", "--test-num=11" };
+ assert(parse_argv(test10_argv, ARRAY_SIZE(test10_argv)));
+
+ return 0;
+}
We don't really have infrastructure in place to easily add/build/run tests, but that shouldn't stop them being written. This adds some basic tests of the argument parsing logic. Signed-off-by: Alistair Popple <alistair@popple.id.au> --- Makefile.am | 5 +- src/tests/optcmd_test.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 src/tests/optcmd_test.c