Merge branch 'tor-github/pr/980'

Signed-off-by: David Goulet <dgoulet@torproject.org>
This commit is contained in:
David Goulet
2019-04-30 11:50:36 -04:00
27 changed files with 1484 additions and 868 deletions
+12
View File
@@ -235,6 +235,18 @@ fuzz_main(const uint8_t *stdin_buf, size_t data_size)
kv_flags = 0;
ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
break;
case 7:
kv_flags = KV_OMIT_VALS;
ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
break;
case 8:
kv_flags = KV_QUOTED;
ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
break;
case 9:
kv_flags = KV_QUOTED|KV_OMIT_VALS;
ENCODE_ROUNDTRIP(kv_enc, kv_dec, config_free_lines_);
break;
}
return 0;
+55
View File
@@ -5886,6 +5886,61 @@ test_config_kvline_parse(void *arg)
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "AB");
tt_str_op(lines->value, OP_EQ, "");
config_free_lines(lines);
lines = kvline_parse("AB=", KV_OMIT_VALS);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "AB");
tt_str_op(lines->value, OP_EQ, "");
config_free_lines(lines);
lines = kvline_parse(" AB ", KV_OMIT_VALS);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "AB");
tt_str_op(lines->value, OP_EQ, "");
config_free_lines(lines);
lines = kvline_parse("AB", KV_OMIT_VALS);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "AB");
tt_str_op(lines->value, OP_EQ, "");
enc = kvline_encode(lines, KV_OMIT_VALS);
tt_str_op(enc, OP_EQ, "AB");
tor_free(enc);
config_free_lines(lines);
lines = kvline_parse("AB=CD", KV_OMIT_VALS);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "AB");
tt_str_op(lines->value, OP_EQ, "CD");
enc = kvline_encode(lines, KV_OMIT_VALS);
tt_str_op(enc, OP_EQ, "AB=CD");
tor_free(enc);
config_free_lines(lines);
lines = kvline_parse("AB=CD DE FGH=I", KV_OMIT_VALS);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "AB");
tt_str_op(lines->value, OP_EQ, "CD");
tt_str_op(lines->next->key, OP_EQ, "DE");
tt_str_op(lines->next->value, OP_EQ, "");
tt_str_op(lines->next->next->key, OP_EQ, "FGH");
tt_str_op(lines->next->next->value, OP_EQ, "I");
enc = kvline_encode(lines, KV_OMIT_VALS);
tt_str_op(enc, OP_EQ, "AB=CD DE FGH=I");
tor_free(enc);
config_free_lines(lines);
lines = kvline_parse("AB=\"CD E\" DE FGH=\"I\"", KV_OMIT_VALS|KV_QUOTED);
tt_assert(lines);
tt_str_op(lines->key, OP_EQ, "AB");
tt_str_op(lines->value, OP_EQ, "CD E");
tt_str_op(lines->next->key, OP_EQ, "DE");
tt_str_op(lines->next->value, OP_EQ, "");
tt_str_op(lines->next->next->key, OP_EQ, "FGH");
tt_str_op(lines->next->next->value, OP_EQ, "I");
enc = kvline_encode(lines, KV_OMIT_VALS|KV_QUOTED);
tt_str_op(enc, OP_EQ, "AB=\"CD E\" DE FGH=I");
done:
config_free_lines(lines);
+185
View File
@@ -18,12 +18,189 @@
#include "test/test.h"
#include "test/test_helpers.h"
#include "lib/net/resolve.h"
#include "lib/encoding/confline.h"
#include "lib/encoding/kvline.h"
#include "feature/control/control_connection_st.h"
#include "feature/control/control_cmd_args_st.h"
#include "feature/dirclient/download_status_st.h"
#include "feature/nodelist/microdesc_st.h"
#include "feature/nodelist/node_st.h"
typedef struct {
const char *input;
const char *expected_parse;
const char *expected_error;
} parser_testcase_t;
typedef struct {
const control_cmd_syntax_t *syntax;
size_t n_testcases;
const parser_testcase_t *testcases;
} parse_test_params_t;
static char *
control_cmd_dump_args(const control_cmd_args_t *result)
{
buf_t *buf = buf_new();
buf_add_string(buf, "{ args=[");
if (result->args) {
if (smartlist_len(result->args)) {
buf_add_string(buf, " ");
}
SMARTLIST_FOREACH_BEGIN(result->args, const char *, s) {
const bool last = (s_sl_idx == smartlist_len(result->args)-1);
buf_add_printf(buf, "%s%s ",
escaped(s),
last ? "" : ",");
} SMARTLIST_FOREACH_END(s);
}
buf_add_string(buf, "]");
if (result->cmddata) {
buf_add_string(buf, ", obj=");
buf_add_string(buf, escaped(result->cmddata));
}
if (result->kwargs) {
buf_add_string(buf, ", { ");
const config_line_t *line;
for (line = result->kwargs; line; line = line->next) {
const bool last = (line->next == NULL);
buf_add_printf(buf, "%s=%s%s ", line->key, escaped(line->value),
last ? "" : ",");
}
buf_add_string(buf, "}");
}
buf_add_string(buf, " }");
char *encoded = buf_extract(buf, NULL);
buf_free(buf);
return encoded;
}
static void
test_controller_parse_cmd(void *arg)
{
const parse_test_params_t *params = arg;
control_cmd_args_t *result = NULL;
char *error = NULL;
char *encoded = NULL;
for (size_t i = 0; i < params->n_testcases; ++i) {
const parser_testcase_t *t = &params->testcases[i];
result = control_cmd_parse_args("EXAMPLE",
params->syntax,
strlen(t->input),
t->input,
&error);
// A valid test should expect exactly one parse or error.
tt_int_op((t->expected_parse == NULL), OP_NE,
(t->expected_error == NULL));
// We get a result or an error, not both.
tt_int_op((result == NULL), OP_EQ, (error != NULL));
// We got the one we expected.
tt_int_op((result == NULL), OP_EQ, (t->expected_parse == NULL));
if (result) {
encoded = control_cmd_dump_args(result);
tt_str_op(encoded, OP_EQ, t->expected_parse);
} else {
tt_str_op(error, OP_EQ, t->expected_error);
}
tor_free(error);
tor_free(encoded);
control_cmd_args_free(result);
}
done:
tor_free(error);
tor_free(encoded);
control_cmd_args_free(result);
}
#define OK(inp, out) \
{ inp "\r\n", out, NULL }
#define ERR(inp, err) \
{ inp "\r\n", NULL, err }
#define TESTPARAMS(syntax, array) \
{ &syntax, \
ARRAY_LENGTH(array), \
array }
static const parser_testcase_t one_to_three_tests[] = {
ERR("", "Need at least 1 argument(s)"),
ERR(" \t", "Need at least 1 argument(s)"),
OK("hello", "{ args=[ \"hello\" ] }"),
OK("hello world", "{ args=[ \"hello\", \"world\" ] }"),
OK("hello world", "{ args=[ \"hello\", \"world\" ] }"),
OK(" hello world", "{ args=[ \"hello\", \"world\" ] }"),
OK(" hello world ", "{ args=[ \"hello\", \"world\" ] }"),
OK("hello there world", "{ args=[ \"hello\", \"there\", \"world\" ] }"),
ERR("why hello there world", "Cannot accept more than 3 argument(s)"),
ERR("hello\r\nworld.\r\n.", "Unexpected body"),
};
static const control_cmd_syntax_t one_to_three_syntax = {
.min_args=1, .max_args=3
};
static const parse_test_params_t parse_one_to_three_params =
TESTPARAMS( one_to_three_syntax, one_to_three_tests );
// =
static const parser_testcase_t no_args_one_obj_tests[] = {
ERR("Hi there!\r\n.", "Cannot accept more than 0 argument(s)"),
ERR("", "Empty body"),
OK("\r\n", "{ args=[], obj=\"\\n\" }"),
OK("\r\nHello world\r\n", "{ args=[], obj=\"Hello world\\n\\n\" }"),
OK("\r\nHello\r\nworld\r\n", "{ args=[], obj=\"Hello\\nworld\\n\\n\" }"),
OK("\r\nHello\r\n..\r\nworld\r\n",
"{ args=[], obj=\"Hello\\n.\\nworld\\n\\n\" }"),
};
static const control_cmd_syntax_t no_args_one_obj_syntax = {
.min_args=0, .max_args=0,
.want_cmddata=true,
};
static const parse_test_params_t parse_no_args_one_obj_params =
TESTPARAMS( no_args_one_obj_syntax, no_args_one_obj_tests );
static const parser_testcase_t no_args_kwargs_tests[] = {
OK("", "{ args=[] }"),
OK(" ", "{ args=[] }"),
OK("hello there=world", "{ args=[], { hello=\"\", there=\"world\" } }"),
OK("hello there=world today",
"{ args=[], { hello=\"\", there=\"world\", today=\"\" } }"),
ERR("=Foo", "Cannot parse keyword argument(s)"),
};
static const control_cmd_syntax_t no_args_kwargs_syntax = {
.min_args=0, .max_args=0,
.accept_keywords=true,
.kvline_flags=KV_OMIT_VALS
};
static const parse_test_params_t parse_no_args_kwargs_params =
TESTPARAMS( no_args_kwargs_syntax, no_args_kwargs_tests );
static const char *one_arg_kwargs_allow_keywords[] = {
"Hello", "world", NULL
};
static const parser_testcase_t one_arg_kwargs_tests[] = {
ERR("", "Need at least 1 argument(s)"),
OK("Hi", "{ args=[ \"Hi\" ] }"),
ERR("hello there=world", "Unrecognized keyword argument \"there\""),
OK("Hi HELLO=foo", "{ args=[ \"Hi\" ], { HELLO=\"foo\" } }"),
OK("Hi world=\"bar baz\" hello ",
"{ args=[ \"Hi\" ], { world=\"bar baz\", hello=\"\" } }"),
};
static const control_cmd_syntax_t one_arg_kwargs_syntax = {
.min_args=1, .max_args=1,
.accept_keywords=true,
.allowed_keywords=one_arg_kwargs_allow_keywords,
.kvline_flags=KV_OMIT_VALS|KV_QUOTED,
};
static const parse_test_params_t parse_one_arg_kwargs_params =
TESTPARAMS( one_arg_kwargs_syntax, one_arg_kwargs_tests );
static void
test_add_onion_helper_keyarg_v3(void *arg)
{
@@ -1617,7 +1794,15 @@ test_getinfo_md_all(void *arg)
return;
}
#define PARSER_TEST(type) \
{ "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \
(void*)&parse_ ## type ## _params }
struct testcase_t controller_tests[] = {
PARSER_TEST(one_to_three),
PARSER_TEST(no_args_one_obj),
PARSER_TEST(no_args_kwargs),
PARSER_TEST(one_arg_kwargs),
{ "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0,
NULL, NULL },
{ "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0,