diff options
Diffstat (limited to 'src/starter/tests/suites/test_parser.c')
-rw-r--r-- | src/starter/tests/suites/test_parser.c | 575 |
1 files changed, 575 insertions, 0 deletions
diff --git a/src/starter/tests/suites/test_parser.c b/src/starter/tests/suites/test_parser.c new file mode 100644 index 000000000..26a41ba55 --- /dev/null +++ b/src/starter/tests/suites/test_parser.c @@ -0,0 +1,575 @@ +/* + * Copyright (C) 2014 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <unistd.h> + +#include <test_suite.h> + +#include "../../parser/conf_parser.h" + +static char *path = "/tmp/strongswan-starter-parser-test"; +static conf_parser_t *parser; + +static void create_parser(chunk_t contents) +{ + ck_assert(chunk_write(contents, path, 0022, TRUE)); + parser = conf_parser_create(path); +} + +START_TEARDOWN(teardown_parser) +{ + parser->destroy(parser); + unlink(path); +} +END_TEARDOWN + +START_TEST(test_get_sections_config_setup) +{ + enumerator_t *enumerator; + + create_parser(chunk_from_str("")); + ck_assert(parser->parse(parser)); + enumerator = parser->get_sections(parser, CONF_PARSER_CONFIG_SETUP); + ck_assert(enumerator); + ck_assert(!enumerator->enumerate(enumerator, NULL)); + enumerator->destroy(enumerator); + parser->destroy(parser); + + create_parser(chunk_from_str("config setup\n\tfoo=bar")); + ck_assert(parser->parse(parser)); + enumerator = parser->get_sections(parser, CONF_PARSER_CONFIG_SETUP); + ck_assert(enumerator); + ck_assert(!enumerator->enumerate(enumerator, NULL)); + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_get_sections_conn) +{ + enumerator_t *enumerator; + char *name; + + create_parser(chunk_from_str("")); + ck_assert(parser->parse(parser)); + enumerator = parser->get_sections(parser, CONF_PARSER_CONN); + ck_assert(enumerator); + ck_assert(!enumerator->enumerate(enumerator, NULL)); + enumerator->destroy(enumerator); + parser->destroy(parser); + + create_parser(chunk_from_str( + "conn foo\n" + "conn bar\n" + "conn foo\n")); + ck_assert(parser->parse(parser)); + enumerator = parser->get_sections(parser, CONF_PARSER_CONN); + ck_assert(enumerator); + ck_assert(enumerator->enumerate(enumerator, &name)); + ck_assert_str_eq("foo", name); + ck_assert(enumerator->enumerate(enumerator, &name)); + ck_assert_str_eq("bar", name); + ck_assert(!enumerator->enumerate(enumerator, &name)); + enumerator->destroy(enumerator); +} +END_TEST + +START_TEST(test_get_section_config_setup) +{ + dictionary_t *dict; + + create_parser(chunk_from_str("")); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONFIG_SETUP, "foo"); + ck_assert(dict); + dict->destroy(dict); + parser->destroy(parser); + + create_parser(chunk_from_str("config setup\n\tfoo=bar")); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONFIG_SETUP, NULL); + ck_assert(dict); + dict->destroy(dict); + parser->destroy(parser); + + create_parser(chunk_from_str("config setup\n\tfoo=bar")); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONFIG_SETUP, "foo"); + ck_assert(dict); + dict->destroy(dict); +} +END_TEST + +START_TEST(test_get_section_conn) +{ + dictionary_t *dict; + + create_parser(chunk_from_str("")); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "foo"); + ck_assert(!dict); + parser->destroy(parser); + + create_parser(chunk_from_str("conn foo\n")); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "foo"); + ck_assert(!parser->get_section(parser, CONF_PARSER_CONN, "bar")); + ck_assert(dict); + dict->destroy(dict); + parser->destroy(parser); + + create_parser(chunk_from_str("conn foo\n\tfoo=bar")); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "foo"); + ck_assert(dict); + dict->destroy(dict); +} +END_TEST + +START_TEST(test_enumerate_values) +{ + enumerator_t *enumerator; + dictionary_t *dict; + char *key, *value; + int i; + + create_parser(chunk_from_str( + "conn foo\n" + " foo=bar\n" + " bar=baz")); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "foo"); + ck_assert(dict); + ck_assert_str_eq("bar", dict->get(dict, "foo")); + ck_assert_str_eq("baz", dict->get(dict, "bar")); + enumerator = dict->create_enumerator(dict); + for (i = 0; enumerator->enumerate(enumerator, &key, &value); i++) + { + if ((streq(key, "foo") && !streq(value, "bar")) || + (streq(key, "bar") && !streq(value, "baz"))) + { + fail("unexpected setting %s=%s", key, value); + } + } + enumerator->destroy(enumerator); + ck_assert_int_eq(i, 2); + dict->destroy(dict); +} +END_TEST + +#define extensibility_config(section) \ + section "\n" \ + " foo=bar\n" \ + " dup=one\n" \ + " dup=two\n" \ + "\n" \ + " nope=val\n" \ + "\n" \ + section "\n" \ + " foo=baz\n" \ + section "\n" \ + " answer=42\n" \ + " nope=\n" + +static struct { + char *conf; + conf_parser_section_t type; + char *name; +} extensibility_data[] = { + { extensibility_config("config setup"), CONF_PARSER_CONFIG_SETUP, NULL }, + { extensibility_config("ca ca-foo"), CONF_PARSER_CA, "ca-foo" }, + { extensibility_config("conn conn-foo"), CONF_PARSER_CONN, "conn-foo" }, +}; + +START_TEST(test_extensibility) +{ + dictionary_t *dict; + + create_parser(chunk_from_str(extensibility_data[_i].conf)); + ck_assert(parser->parse(parser)); + + dict = parser->get_section(parser, extensibility_data[_i].type, + extensibility_data[_i].name); + ck_assert(dict); + ck_assert_str_eq("baz", dict->get(dict, "foo")); + ck_assert_str_eq("two", dict->get(dict, "dup")); + ck_assert_str_eq("42", dict->get(dict, "answer")); + ck_assert(!dict->get(dict, "nope")); + ck_assert(!dict->get(dict, "anything")); + dict->destroy(dict); +} +END_TEST + +static struct { + char *conf; + bool check_section; + char *value; +} comments_data[] = { + { "# conn foo", FALSE, NULL }, + { "# conn foo\n", FALSE, NULL }, + { "conn foo # asdf", TRUE, NULL }, + { "conn foo # asdf", TRUE, NULL }, + { "conn foo# asdf\n", TRUE, NULL }, + { "conn foo # asdf\n\tkey=val", TRUE, "val" }, + { "conn foo # asdf\n#\tkey=val", TRUE, NULL }, + { "conn foo # asdf\n\t#key=val", TRUE, NULL }, + { "conn foo # asdf\n\tkey=@#keyid", TRUE, "@#keyid" }, + { "conn foo # asdf\n\tkey=\"@#keyid\"", TRUE, "@#keyid" }, + { "conn foo # asdf\n\tkey=asdf@#keyid", TRUE, "asdf@" }, + { "conn foo # asdf\n\tkey=#val", TRUE, NULL }, + { "conn foo # asdf\n\tkey=val#asdf", TRUE, "val" }, + { "conn foo # asdf\n\tkey=\"val#asdf\"", TRUE, "val#asdf" }, + { "conn foo # asdf\n\tkey=val # asdf\n", TRUE, "val" }, + { "conn foo # asdf\n# asdf\n\tkey=val\n", TRUE, "val" }, + { "conn foo # asdf\n\t# asdf\n\tkey=val\n", TRUE, "val" }, +}; + +START_TEST(test_comments) +{ + dictionary_t *dict; + + create_parser(chunk_from_str(comments_data[_i].conf)); + ck_assert(parser->parse(parser)); + if (comments_data[_i].check_section) + { + dict = parser->get_section(parser, CONF_PARSER_CONN, "foo"); + ck_assert(dict); + if (comments_data[_i].value) + { + ck_assert_str_eq(comments_data[_i].value, dict->get(dict, "key")); + } + else + { + ck_assert(!dict->get(dict, "key")); + } + dict->destroy(dict); + } + else + { + ck_assert(!parser->get_section(parser, CONF_PARSER_CONN, "foo")); + } +} +END_TEST + +static struct { + char *conf; + bool check_section; + char *value; +} whitespace_data[] = { + { "conn foo ", FALSE, NULL }, + { "conn foo", FALSE, NULL }, + { "conn foo\n", FALSE, NULL }, + { "conn foo \n", FALSE, NULL }, + { "conn foo\n ", FALSE, NULL }, + { "conn foo\n \n", FALSE, NULL }, + { "conn foo\nconn bar", TRUE, NULL }, + { "conn foo\n \nconn bar", TRUE, NULL }, + { "conn foo\n key=val", FALSE, "val" }, + { "conn foo\n\tkey=val", FALSE, "val" }, + { "conn foo\n\t \tkey=val", FALSE, "val" }, + { "conn foo\n\tkey = val ", FALSE, "val" }, +}; + +START_TEST(test_whitespace) +{ + dictionary_t *dict; + + create_parser(chunk_from_str(whitespace_data[_i].conf)); + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "foo"); + ck_assert(dict); + if (whitespace_data[_i].value) + { + ck_assert_str_eq(whitespace_data[_i].value, dict->get(dict, "key")); + } + else + { + ck_assert(!dict->get(dict, "key")); + } + dict->destroy(dict); + if (whitespace_data[_i].check_section) + { + dict = parser->get_section(parser, CONF_PARSER_CONN, "bar"); + ck_assert(dict); + dict->destroy(dict); + } + else + { + ck_assert(!parser->get_section(parser, CONF_PARSER_CONN, "bar")); + } +} +END_TEST + +static struct { + bool valid; + char *conf; + char *section; + char *value; +} strings_data[] = { + { FALSE, "\"conn foo\"", NULL, NULL }, + { TRUE, "conn \"foo\"", "foo", NULL }, + { FALSE, "conn foo bar", NULL, NULL }, + { TRUE, "conn \"foo bar\"", "foo bar", NULL }, + { TRUE, "conn \"#foo\"", "#foo", NULL }, + { FALSE, "conn foo\n\t\"key=val\"", "foo", NULL }, + { TRUE, "conn foo\n\t\"key\"=val", "foo", "val" }, + { TRUE, "conn foo\n\tkey=val ue", "foo", "val ue" }, + { TRUE, "conn foo\n\tkey=val ue", "foo", "val ue" }, + { TRUE, "conn foo\n\tkey=\"val ue\"", "foo", "val ue" }, + { TRUE, "conn foo\n\tkey=\"val\\nue\"", "foo", "val\nue" }, +}; + +START_TEST(test_strings) +{ + dictionary_t *dict; + + create_parser(chunk_from_str(strings_data[_i].conf)); + ck_assert(parser->parse(parser) == strings_data[_i].valid); + if (strings_data[_i].section) + { + dict = parser->get_section(parser, CONF_PARSER_CONN, + strings_data[_i].section); + ck_assert(dict); + if (strings_data[_i].value) + { + ck_assert_str_eq(strings_data[_i].value, dict->get(dict, "key")); + } + else + { + ck_assert(!dict->get(dict, "key")); + } + dict->destroy(dict); + } +} +END_TEST + +START_TEST(test_refcounting) +{ + dictionary_t *dict; + + create_parser(chunk_from_str( + "conn foo\n" + " key=val")); + + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "foo"); + ck_assert(dict); + ck_assert_str_eq("val", dict->get(dict, "key")); + parser->destroy(parser); + ck_assert_str_eq("val", dict->get(dict, "key")); + dict->destroy(dict); +} +END_TEST + +START_TEST(test_default) +{ + enumerator_t *enumerator; + dictionary_t *dict; + char *name; + + create_parser(chunk_from_str( + "conn %default\n" + " key=valdef\n" + " unset=set\n" + "conn A\n" + " key=vala\n" + " unset=\n" + "conn B\n" + " keyb=valb\n" + "")); + + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "%default"); + ck_assert(!dict); + enumerator = parser->get_sections(parser, CONF_PARSER_CONN); + ck_assert(enumerator); + ck_assert(enumerator->enumerate(enumerator, &name)); + ck_assert_str_eq("A", name); + ck_assert(enumerator->enumerate(enumerator, &name)); + ck_assert_str_eq("B", name); + ck_assert(!enumerator->enumerate(enumerator, &name)); + enumerator->destroy(enumerator); + + dict = parser->get_section(parser, CONF_PARSER_CONN, "A"); + ck_assert(dict); + ck_assert_str_eq("vala", dict->get(dict, "key")); + ck_assert(!dict->get(dict, "unset")); + dict->destroy(dict); + dict = parser->get_section(parser, CONF_PARSER_CONN, "B"); + ck_assert(dict); + ck_assert_str_eq("valdef", dict->get(dict, "key")); + ck_assert_str_eq("valb", dict->get(dict, "keyb")); + ck_assert_str_eq("set", dict->get(dict, "unset")); + dict->destroy(dict); +} +END_TEST + +START_TEST(test_also) +{ + dictionary_t *dict; + + create_parser(chunk_from_str( + "conn A\n" + " key=vala\n" + " keya=val1\n" + " unset=set\n" + "conn B\n" + " also=A\n" + " key=valb\n" + " keyb=val2\n" + " unset=\n" + "conn C\n" + " keyc=val3\n" + " unset=set again\n" + " also=B\n" + "conn D\n" + " keyd=val4\n" + " also=A\n" + " also=B\n" + "conn E\n" + " keye=val5\n" + " also=B\n" + " also=A\n" + "")); + + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "B"); + ck_assert(dict); + ck_assert_str_eq("valb", dict->get(dict, "key")); + ck_assert_str_eq("val1", dict->get(dict, "keya")); + ck_assert_str_eq("val2", dict->get(dict, "keyb")); + ck_assert(!dict->get(dict, "unset")); + dict->destroy(dict); + dict = parser->get_section(parser, CONF_PARSER_CONN, "C"); + ck_assert(dict); + ck_assert_str_eq("valb", dict->get(dict, "key")); + ck_assert_str_eq("val1", dict->get(dict, "keya")); + ck_assert_str_eq("val2", dict->get(dict, "keyb")); + ck_assert_str_eq("val3", dict->get(dict, "keyc")); + ck_assert_str_eq("set again", dict->get(dict, "unset")); + dict->destroy(dict); + /* since B includes A too the inclusion in D and E has no effect */ + dict = parser->get_section(parser, CONF_PARSER_CONN, "D"); + ck_assert(dict); + ck_assert_str_eq("valb", dict->get(dict, "key")); + ck_assert_str_eq("val1", dict->get(dict, "keya")); + ck_assert_str_eq("val2", dict->get(dict, "keyb")); + ck_assert(!dict->get(dict, "keyc")); + ck_assert_str_eq("val4", dict->get(dict, "keyd")); + ck_assert(!dict->get(dict, "unset")); + dict->destroy(dict); + dict = parser->get_section(parser, CONF_PARSER_CONN, "E"); + ck_assert(dict); + ck_assert_str_eq("valb", dict->get(dict, "key")); + ck_assert_str_eq("val1", dict->get(dict, "keya")); + ck_assert_str_eq("val2", dict->get(dict, "keyb")); + ck_assert(!dict->get(dict, "keyc")); + ck_assert(!dict->get(dict, "keyd")); + ck_assert_str_eq("val5", dict->get(dict, "keye")); + ck_assert(!dict->get(dict, "unset")); + dict->destroy(dict); +} +END_TEST + +START_TEST(test_ambiguous) +{ + dictionary_t *dict; + + create_parser(chunk_from_str( + "conn A\n" + " key=vala\n" + "conn B\n" + " key=valb\n" + "conn C\n" + " also=A\n" + " also=B\n" + "conn D\n" + " also=B\n" + " also=A\n" + "conn E\n" + " also=C\n" + " also=D\n" + "conn F\n" + " also=D\n" + " also=C\n")); + + ck_assert(parser->parse(parser)); + dict = parser->get_section(parser, CONF_PARSER_CONN, "E"); + ck_assert(dict); + ck_assert_str_eq("valb", dict->get(dict, "key")); + dict->destroy(dict); + dict = parser->get_section(parser, CONF_PARSER_CONN, "F"); + ck_assert(dict); + ck_assert_str_eq("vala", dict->get(dict, "key")); + dict->destroy(dict); +} +END_TEST + +Suite *parser_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("ipsec.conf parser"); + + tc = tcase_create("get_section(s)"); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_test(tc, test_get_sections_config_setup); + tcase_add_test(tc, test_get_sections_conn); + tcase_add_test(tc, test_get_section_config_setup); + tcase_add_test(tc, test_get_section_conn); + suite_add_tcase(s, tc); + + tc = tcase_create("enumerate settings"); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_test(tc, test_enumerate_values); + suite_add_tcase(s, tc); + + tc = tcase_create("extensibility"); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_loop_test(tc, test_extensibility, 0, countof(extensibility_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("comments"); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_loop_test(tc, test_comments, 0, countof(comments_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("whitespace"); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_loop_test(tc, test_whitespace, 0, countof(whitespace_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("strings"); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_loop_test(tc, test_strings, 0, countof(strings_data)); + suite_add_tcase(s, tc); + + tc = tcase_create("refcounting"); + tcase_add_test(tc, test_refcounting); + suite_add_tcase(s, tc); + + tc = tcase_create("%default"); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_test(tc, test_default); + suite_add_tcase(s, tc); + + tc = tcase_create("also="); + tcase_add_checked_fixture(tc, NULL, teardown_parser); + tcase_add_test(tc, test_also); + tcase_add_test(tc, test_ambiguous); + suite_add_tcase(s, tc); + + return s; +} |