aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Craig Tiller <ctiller@google.com>2015-12-10 09:22:55 -0800
committerGravatar Craig Tiller <ctiller@google.com>2015-12-10 09:22:55 -0800
commit1fa1ab84c9ffc8d05b365165485c79cbf0496e33 (patch)
tree8f7b413cfa217e29fc57c91cd4339eefa411a932
parent81e4e8dd0b47ddf805741cc4e0e24313a273cd5e (diff)
Add cmdline tests
-rw-r--r--include/grpc/support/cmdline.h8
-rw-r--r--src/core/support/cmdline.c62
-rw-r--r--test/core/support/cmdline_test.c187
3 files changed, 232 insertions, 25 deletions
diff --git a/include/grpc/support/cmdline.h b/include/grpc/support/cmdline.h
index 028dac2955..3058cf905a 100644
--- a/include/grpc/support/cmdline.h
+++ b/include/grpc/support/cmdline.h
@@ -83,8 +83,12 @@ void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
void gpr_cmdline_on_extra_arg(
gpr_cmdline *cl, const char *name, const char *help,
void (*on_extra_arg)(void *user_data, const char *arg), void *user_data);
-/* Parse the command line */
-void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv);
+/* Enable surviving failure: default behavior is to exit the process */
+void gpr_cmdline_set_survive_failure(gpr_cmdline *cl);
+/* Parse the command line; returns 1 on success, on failure either dies
+ (by default) or returns 0 if gpr_cmdline_set_survive_failure() has been
+ called */
+int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv);
/* Destroy the parser */
void gpr_cmdline_destroy(gpr_cmdline *cl);
/* Get a string describing usage */
diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c
index 87f60bca2e..b517f30b2d 100644
--- a/src/core/support/cmdline.c
+++ b/src/core/support/cmdline.c
@@ -62,11 +62,13 @@ struct gpr_cmdline {
void (*extra_arg)(void *user_data, const char *arg);
void *extra_arg_user_data;
- void (*state)(gpr_cmdline *cl, char *arg);
+ int (*state)(gpr_cmdline *cl, char *arg);
arg *cur_arg;
+
+ int survive_failure;
};
-static void normal_state(gpr_cmdline *cl, char *arg);
+static int normal_state(gpr_cmdline *cl, char *arg);
gpr_cmdline *gpr_cmdline_create(const char *description) {
gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline));
@@ -78,6 +80,10 @@ gpr_cmdline *gpr_cmdline_create(const char *description) {
return cl;
}
+void gpr_cmdline_set_survive_failure(gpr_cmdline *cl) {
+ cl->survive_failure = 1;
+}
+
void gpr_cmdline_destroy(gpr_cmdline *cl) {
while (cl->args) {
arg *a = cl->args;
@@ -185,16 +191,22 @@ char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0) {
return tmp;
}
-static void print_usage_and_die(gpr_cmdline *cl) {
+static int print_usage_and_die(gpr_cmdline *cl) {
char *usage = gpr_cmdline_usage_string(cl, cl->argv0);
fprintf(stderr, "%s", usage);
gpr_free(usage);
- exit(1);
+ if (!cl->survive_failure) {
+ exit(1);
+ }
+ return 0;
}
-static void extra_state(gpr_cmdline *cl, char *str) {
- if (!cl->extra_arg) print_usage_and_die(cl);
+static int extra_state(gpr_cmdline *cl, char *str) {
+ if (!cl->extra_arg) {
+ return print_usage_and_die(cl);
+ }
cl->extra_arg(cl->extra_arg_user_data, str);
+ return 1;
}
static arg *find_arg(gpr_cmdline *cl, char *name) {
@@ -208,13 +220,13 @@ static arg *find_arg(gpr_cmdline *cl, char *name) {
if (!a) {
fprintf(stderr, "Unknown argument: %s\n", name);
- print_usage_and_die(cl);
+ return NULL;
}
return a;
}
-static void value_state(gpr_cmdline *cl, char *str) {
+static int value_state(gpr_cmdline *cl, char *str) {
long intval;
char *end;
@@ -226,7 +238,7 @@ static void value_state(gpr_cmdline *cl, char *str) {
if (*end || intval < INT_MIN || intval > INT_MAX) {
fprintf(stderr, "expected integer, got '%s' for %s\n", str,
cl->cur_arg->name);
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
*(int *)cl->cur_arg->value = (int)intval;
break;
@@ -238,7 +250,7 @@ static void value_state(gpr_cmdline *cl, char *str) {
} else {
fprintf(stderr, "expected boolean, got '%s' for %s\n", str,
cl->cur_arg->name);
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
break;
case ARGTYPE_STRING:
@@ -247,16 +259,18 @@ static void value_state(gpr_cmdline *cl, char *str) {
}
cl->state = normal_state;
+ return 1;
}
-static void normal_state(gpr_cmdline *cl, char *str) {
+static int normal_state(gpr_cmdline *cl, char *str) {
char *eq = NULL;
char *tmp = NULL;
char *arg_name = NULL;
+ int r = 1;
if (0 == strcmp(str, "-help") || 0 == strcmp(str, "--help") ||
0 == strcmp(str, "-h")) {
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
cl->cur_arg = NULL;
@@ -266,7 +280,7 @@ static void normal_state(gpr_cmdline *cl, char *str) {
if (str[2] == 0) {
/* handle '--' to move to just extra args */
cl->state = extra_state;
- return;
+ return 1;
}
str += 2;
} else {
@@ -277,12 +291,15 @@ static void normal_state(gpr_cmdline *cl, char *str) {
/* str is of the form '--no-foo' - it's a flag disable */
str += 3;
cl->cur_arg = find_arg(cl, str);
+ if (cl->cur_arg == NULL) {
+ return print_usage_and_die(cl);
+ }
if (cl->cur_arg->type != ARGTYPE_BOOL) {
fprintf(stderr, "%s is not a flag argument\n", str);
- print_usage_and_die(cl);
+ return print_usage_and_die(cl);
}
*(int *)cl->cur_arg->value = 0;
- return; /* early out */
+ return 1; /* early out */
}
eq = strchr(str, '=');
if (eq != NULL) {
@@ -294,9 +311,12 @@ static void normal_state(gpr_cmdline *cl, char *str) {
arg_name = str;
}
cl->cur_arg = find_arg(cl, arg_name);
+ if (cl->cur_arg == NULL) {
+ return print_usage_and_die(cl);
+ }
if (eq != NULL) {
/* str was of the type --foo=value, parse the value */
- value_state(cl, eq + 1);
+ r = value_state(cl, eq + 1);
} else if (cl->cur_arg->type != ARGTYPE_BOOL) {
/* flag types don't have a '--foo value' variant, other types do */
cl->state = value_state;
@@ -305,19 +325,23 @@ static void normal_state(gpr_cmdline *cl, char *str) {
*(int *)cl->cur_arg->value = 1;
}
} else {
- extra_state(cl, str);
+ r = extra_state(cl, str);
}
gpr_free(tmp);
+ return r;
}
-void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
+int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) {
int i;
GPR_ASSERT(argc >= 1);
cl->argv0 = argv[0];
for (i = 1; i < argc; i++) {
- cl->state(cl, argv[i]);
+ if (!cl->state(cl, argv[i])) {
+ return 0;
+ }
}
+ return 1;
}
diff --git a/test/core/support/cmdline_test.c b/test/core/support/cmdline_test.c
index 1c77c15233..4730fcc1b5 100644
--- a/test/core/support/cmdline_test.c
+++ b/test/core/support/cmdline_test.c
@@ -40,7 +40,7 @@
#include <grpc/support/useful.h>
#include "test/core/util/test_config.h"
-#define LOG_TEST() gpr_log(GPR_INFO, "%s", __FILE__)
+#define LOG_TEST() gpr_log(GPR_INFO, "test at %s:%d", __FILE__, __LINE__)
static void test_simple_int(void) {
int x = 1;
@@ -273,6 +273,44 @@ static void test_many(void) {
gpr_cmdline_destroy(cl);
}
+static void extra_arg_cb(void *user_data, const char *arg) {
+ int *count = user_data;
+ GPR_ASSERT(arg != NULL);
+ GPR_ASSERT(strlen(arg) == 1);
+ GPR_ASSERT(arg[0] == 'a' + *count);
+ ++*count;
+}
+
+static void test_extra(void) {
+ gpr_cmdline *cl;
+ int count = 0;
+ char *args[] = {(char *)__FILE__, "a", "b", "c"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ &count);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(count == 3);
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_extra_dashdash(void) {
+ gpr_cmdline *cl;
+ int count = 0;
+ char *args[] = {(char *)__FILE__, "--", "a", "b", "c"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ &count);
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(args), args);
+ GPR_ASSERT(count == 3);
+ gpr_cmdline_destroy(cl);
+}
+
static void test_usage(void) {
gpr_cmdline *cl;
char *usage;
@@ -281,20 +319,154 @@ static void test_usage(void) {
int x = 0;
int flag = 2;
+ LOG_TEST();
+
cl = gpr_cmdline_create(NULL);
gpr_cmdline_add_string(cl, "str", NULL, &str);
gpr_cmdline_add_int(cl, "x", NULL, &x);
gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ NULL);
usage = gpr_cmdline_usage_string(cl, "test");
- GPR_ASSERT(
- 0 == strcmp(usage,
- "Usage: test [--str=string] [--x=int] [--flag|--no-flag]\n"));
+ GPR_ASSERT(0 == strcmp(usage,
+ "Usage: test [--str=string] [--x=int] "
+ "[--flag|--no-flag] [file...]\n"));
+ gpr_free(usage);
+
+ usage = gpr_cmdline_usage_string(cl, "/foo/test");
+ GPR_ASSERT(0 == strcmp(usage,
+ "Usage: test [--str=string] [--x=int] "
+ "[--flag|--no-flag] [file...]\n"));
gpr_free(usage);
gpr_cmdline_destroy(cl);
}
+static void test_help(void) {
+ gpr_cmdline *cl;
+
+ char *str = NULL;
+ int x = 0;
+ int flag = 2;
+
+ char *help[] = {(char *)__FILE__, "-h"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_set_survive_failure(cl);
+ gpr_cmdline_add_string(cl, "str", NULL, &str);
+ gpr_cmdline_add_int(cl, "x", NULL, &x);
+ gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ NULL);
+
+ GPR_ASSERT(0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(help), help));
+
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_badargs1(void) {
+ gpr_cmdline *cl;
+
+ char *str = NULL;
+ int x = 0;
+ int flag = 2;
+
+ char *bad_arg_name[] = {(char *)__FILE__, "--y"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_set_survive_failure(cl);
+ gpr_cmdline_add_string(cl, "str", NULL, &str);
+ gpr_cmdline_add_int(cl, "x", NULL, &x);
+ gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ NULL);
+
+ GPR_ASSERT(0 ==
+ gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_arg_name), bad_arg_name));
+
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_badargs2(void) {
+ gpr_cmdline *cl;
+
+ char *str = NULL;
+ int x = 0;
+ int flag = 2;
+
+ char *bad_int_value[] = {(char *)__FILE__, "--x", "henry"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_set_survive_failure(cl);
+ gpr_cmdline_add_string(cl, "str", NULL, &str);
+ gpr_cmdline_add_int(cl, "x", NULL, &x);
+ gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ NULL);
+
+ GPR_ASSERT(
+ 0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_int_value), bad_int_value));
+
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_badargs3(void) {
+ gpr_cmdline *cl;
+
+ char *str = NULL;
+ int x = 0;
+ int flag = 2;
+
+ char *bad_bool_value[] = {(char *)__FILE__, "--flag=henry"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_set_survive_failure(cl);
+ gpr_cmdline_add_string(cl, "str", NULL, &str);
+ gpr_cmdline_add_int(cl, "x", NULL, &x);
+ gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ NULL);
+
+ GPR_ASSERT(0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_bool_value),
+ bad_bool_value));
+
+ gpr_cmdline_destroy(cl);
+}
+
+static void test_badargs4(void) {
+ gpr_cmdline *cl;
+
+ char *str = NULL;
+ int x = 0;
+ int flag = 2;
+
+ char *bad_bool_value[] = {(char *)__FILE__, "--no-str"};
+
+ LOG_TEST();
+
+ cl = gpr_cmdline_create(NULL);
+ gpr_cmdline_set_survive_failure(cl);
+ gpr_cmdline_add_string(cl, "str", NULL, &str);
+ gpr_cmdline_add_int(cl, "x", NULL, &x);
+ gpr_cmdline_add_flag(cl, "flag", NULL, &flag);
+ gpr_cmdline_on_extra_arg(cl, "file", "filenames to process", extra_arg_cb,
+ NULL);
+
+ GPR_ASSERT(0 == gpr_cmdline_parse(cl, GPR_ARRAY_SIZE(bad_bool_value),
+ bad_bool_value));
+
+ gpr_cmdline_destroy(cl);
+}
+
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_simple_int();
@@ -312,6 +484,13 @@ int main(int argc, char **argv) {
test_flag_val_true();
test_flag_val_false();
test_many();
+ test_extra();
+ test_extra_dashdash();
test_usage();
+ test_help();
+ test_badargs1();
+ test_badargs2();
+ test_badargs3();
+ test_badargs4();
return 0;
}