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
This commit is contained in:
Neels Hofmeyr 2017-09-26 15:24:58 +02:00 committed by Neels Hofmeyr
parent f4f23bd682
commit 505c965e36
2 changed files with 353 additions and 0 deletions

View File

@ -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;
}

View File

@ -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