diff options
| author | Neels Hofmeyr <neels@hofmeyr.de> | 2017-09-26 15:24:58 +0200 | 
|---|---|---|
| committer | Neels Hofmeyr <nhofmeyr@sysmocom.de> | 2017-09-27 14:04:23 +0000 | 
| commit | 505c965e3655b8ae94880a23baf8ecc2092163c4 (patch) | |
| tree | 65a8b27941e41f306d205fb2e5cace6d095966aa | |
| parent | f4f23bd6829f78741cfd586f0ca9a290f221242e (diff) | |
CTRL: add unit tests for CTRL command parsing
This uncovers some interesting behavior of the CTRL interface which we may want
to guard against in subsequent patches: trailing whitespace, ignored tokens,
special characters as cmd->id.
Change-Id: If7af06d50ca71fd528b08cd70310774d5a53f0f7
| -rw-r--r-- | tests/ctrl/ctrl_test.c | 251 | ||||
| -rw-r--r-- | tests/ctrl/ctrl_test.ok | 102 | 
2 files changed, 353 insertions, 0 deletions
diff --git a/tests/ctrl/ctrl_test.c b/tests/ctrl/ctrl_test.c index 08be15f6..b8425c7e 100644 --- a/tests/ctrl/ctrl_test.c +++ b/tests/ctrl/ctrl_test.c @@ -6,6 +6,9 @@  #include <osmocom/core/utils.h>  #include <osmocom/ctrl/control_cmd.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/application.h>  static void check_type(enum ctrl_type c)  { @@ -19,8 +22,254 @@ static void check_type(enum ctrl_type c)  		printf("-> %d %s\n", v, c != v ? "FAIL" : "OK");  } +struct msgb *msgb_from_string(const char *str) +{ +	char *rc; +	size_t len = strlen(str) + 1; +	/* ctrl_cmd_parse() appends a '\0' to the msgb, allow one more byte. */ +	struct msgb *msg = msgb_alloc(len + 1, str); +	msg->l2h = msg->head; +	rc = (char*)msgb_put(msg, len); +	OSMO_ASSERT(rc == (char*)msg->l2h); +	strcpy(rc, str); +	return msg; +} + +static void *ctx = NULL; + +void print_escaped(const char *str) +{ +	if (!str) { +		printf("NULL"); +		return; +	} + +	printf("'"); +	for (;*str; str++) { +		switch (*str) { +		case '\n': +			printf("\\n"); +			break; +		case '\r': +			printf("\\r"); +			break; +		case '\t': +			printf("\\t"); +			break; +		default: +			printf("%c", *str); +			break; +		} +	} +	printf("'"); +} + +void assert_same_str(const char *label, const char *expect, const char *got) +{ +	if ((expect == got) || (expect && got && (strcmp(expect, got) == 0))) { +		printf("%s = ", label); +		print_escaped(got); +		printf("\n"); +		return; +	} + +	printf("MISMATCH for '%s':\ngot:      ", label); print_escaped(got); +	printf("\nexpected: "); print_escaped(expect); +	printf("\n"); +	OSMO_ASSERT(expect == got); +} + +static void assert_parsing(const char *str, const struct ctrl_cmd *expect) +{ +	struct ctrl_cmd *cmd; +	struct msgb *msg = msgb_from_string(str); + +	printf("test parsing: "); +	print_escaped(str); +	printf("\n"); + +	cmd = ctrl_cmd_parse(ctx, msg); +	OSMO_ASSERT(cmd); + +	OSMO_ASSERT(expect->type == cmd->type); + +#define ASSERT_SAME_STR(field) \ +	assert_same_str(#field, expect->field, cmd->field) + +	ASSERT_SAME_STR(id); +	ASSERT_SAME_STR(variable); +	ASSERT_SAME_STR(value); +	ASSERT_SAME_STR(reply); + +	talloc_free(cmd); +	msgb_free(msg); + +	printf("ok\n"); +} + +struct one_parsing_test { +	const char *cmd_str; +	struct ctrl_cmd expect; +}; + +static const struct one_parsing_test test_parsing_list[] = { +	{ "GET 1 variable", +		{ +			.type = CTRL_TYPE_GET, +			.id = "1", +			.variable = "variable", +		} +	}, +	{ "GET 1 variable\n", +		{ +			.type = CTRL_TYPE_GET, +			.id = "1", +			.variable = "variable\n", /* current bug */ +		} +	}, +	{ "GET 1 var\ni\nable", +		{ +			.type = CTRL_TYPE_GET, +			.id = "1", +			.variable = "var\ni\nable", /* current bug */ +		} +	}, +	{ "GET 1 variable value", +		{ +			.type = CTRL_TYPE_GET, +			.id = "1", +			.variable = "variable", +			.value = NULL, +		} +	}, +	{ "GET 1 variable value\n", +		{ +			.type = CTRL_TYPE_GET, +			.id = "1", +			.variable = "variable", +			.value = NULL, +		} +	}, +	{ "GET 1 variable multiple value tokens", +		{ +			.type = CTRL_TYPE_GET, +			.id = "1", +			.variable = "variable", +			.value = NULL, +		} +	}, +	{ "GET 1 variable multiple value tokens\n", +		{ +			.type = CTRL_TYPE_GET, +			.id = "1", +			.variable = "variable", +			.value = NULL, +		} +	}, +	{ "SET 1 variable value", +		{ +			.type = CTRL_TYPE_SET, +			.id = "1", +			.variable = "variable", +			.value = "value", +		} +	}, +	{ "SET 1 variable value\n", +		{ +			.type = CTRL_TYPE_SET, +			.id = "1", +			.variable = "variable", +			.value = "value", +		} +	}, +	{ "SET weird_id variable value", +		{ +			.type = CTRL_TYPE_SET, +			.id = "weird_id", +			.variable = "variable", +			.value = "value", +		} +	}, +	{ "SET weird_id variable value\n", +		{ +			.type = CTRL_TYPE_SET, +			.id = "weird_id", +			.variable = "variable", +			.value = "value", +		} +	}, +	{ "SET 1 variable multiple value tokens", +		{ +			.type = CTRL_TYPE_SET, +			.id = "1", +			.variable = "variable", +			.value = "multiple value tokens", +		} +	}, +	{ "SET 1 variable multiple value tokens\n", +		{ +			.type = CTRL_TYPE_SET, +			.id = "1", +			.variable = "variable", +			.value = "multiple value tokens", +		} +	}, +	{ "SET 1 variable value_with_trailing_spaces  ", +		{ +			.type = CTRL_TYPE_SET, +			.id = "1", +			.variable = "variable", +			.value = "value_with_trailing_spaces  ", +		} +	}, +	{ "SET 1 variable value_with_trailing_spaces  \n", +		{ +			.type = CTRL_TYPE_SET, +			.id = "1", +			.variable = "variable", +			.value = "value_with_trailing_spaces  ", +		} +	}, +	{ "SET \n special_char_id value", +		{ +			.type = CTRL_TYPE_SET, +			.id = "\n", +			.variable = "special_char_id", +			.value = "value", +		} +	}, +	{ "SET \t special_char_id value", +		{ +			.type = CTRL_TYPE_SET, +			.id = "\t", +			.variable = "special_char_id", +			.value = "value", +		} +	}, +}; + +static void test_parsing() +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(test_parsing_list); i++) +		assert_parsing(test_parsing_list[i].cmd_str, +			       &test_parsing_list[i].expect); +} + +static struct log_info_cat test_categories[] = { +}; + +static struct log_info info = { +	.cat = test_categories, +	.num_cat = ARRAY_SIZE(test_categories), +}; +  int main(int argc, char **argv)  { +	ctx = talloc_named_const(NULL, 1, "ctrl_test"); +	osmo_init_logging(&info); +  	printf("Checking ctrl types...\n");  	check_type(CTRL_TYPE_UNKNOWN); @@ -32,5 +281,7 @@ int main(int argc, char **argv)  	check_type(CTRL_TYPE_ERROR);  	check_type(64); +	test_parsing(); +  	return 0;  } diff --git a/tests/ctrl/ctrl_test.ok b/tests/ctrl/ctrl_test.ok index 8f97a27f..9c8877b2 100644 --- a/tests/ctrl/ctrl_test.ok +++ b/tests/ctrl/ctrl_test.ok @@ -7,3 +7,105 @@ ctrl type 4 is SET_REPLY -> 4 OK  ctrl type 5 is TRAP -> 5 OK  ctrl type 6 is ERROR -> 6 OK  ctrl type 64 is unknown 0x40 [PARSE FAILED] +test parsing: 'GET 1 variable' +id = '1' +variable = 'variable' +value = NULL +reply = NULL +ok +test parsing: 'GET 1 variable\n' +id = '1' +variable = 'variable\n' +value = NULL +reply = NULL +ok +test parsing: 'GET 1 var\ni\nable' +id = '1' +variable = 'var\ni\nable' +value = NULL +reply = NULL +ok +test parsing: 'GET 1 variable value' +id = '1' +variable = 'variable' +value = NULL +reply = NULL +ok +test parsing: 'GET 1 variable value\n' +id = '1' +variable = 'variable' +value = NULL +reply = NULL +ok +test parsing: 'GET 1 variable multiple value tokens' +id = '1' +variable = 'variable' +value = NULL +reply = NULL +ok +test parsing: 'GET 1 variable multiple value tokens\n' +id = '1' +variable = 'variable' +value = NULL +reply = NULL +ok +test parsing: 'SET 1 variable value' +id = '1' +variable = 'variable' +value = 'value' +reply = NULL +ok +test parsing: 'SET 1 variable value\n' +id = '1' +variable = 'variable' +value = 'value' +reply = NULL +ok +test parsing: 'SET weird_id variable value' +id = 'weird_id' +variable = 'variable' +value = 'value' +reply = NULL +ok +test parsing: 'SET weird_id variable value\n' +id = 'weird_id' +variable = 'variable' +value = 'value' +reply = NULL +ok +test parsing: 'SET 1 variable multiple value tokens' +id = '1' +variable = 'variable' +value = 'multiple value tokens' +reply = NULL +ok +test parsing: 'SET 1 variable multiple value tokens\n' +id = '1' +variable = 'variable' +value = 'multiple value tokens' +reply = NULL +ok +test parsing: 'SET 1 variable value_with_trailing_spaces  ' +id = '1' +variable = 'variable' +value = 'value_with_trailing_spaces  ' +reply = NULL +ok +test parsing: 'SET 1 variable value_with_trailing_spaces  \n' +id = '1' +variable = 'variable' +value = 'value_with_trailing_spaces  ' +reply = NULL +ok +test parsing: 'SET \n special_char_id value' +id = '\n' +variable = 'special_char_id' +value = 'value' +reply = NULL +ok +test parsing: 'SET \t special_char_id value' +id = '\t' +variable = 'special_char_id' +value = 'value' +reply = NULL +ok  | 
