summaryrefslogtreecommitdiffstats
path: root/src/lib-settings/test-settings-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-settings/test-settings-parser.c')
-rw-r--r--src/lib-settings/test-settings-parser.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/src/lib-settings/test-settings-parser.c b/src/lib-settings/test-settings-parser.c
new file mode 100644
index 0000000..83aefba
--- /dev/null
+++ b/src/lib-settings/test-settings-parser.c
@@ -0,0 +1,340 @@
+/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "net.h"
+#include "var-expand.h"
+#include "settings-parser.h"
+#include "istream.h"
+#include "test-common.h"
+
+static const char *test_settings_blobs[] =
+{
+/* Blob 0 */
+ "bool_true=yes\n"
+ "bool_false=no\n"
+ "uint=15\n"
+ "uint_oct=0700\n"
+ "secs=5s\n"
+ "msecs=5ms\n"
+ "size=1k\n"
+ "port=2205\n"
+ "str=test string\n"
+ "expand_str=test %{string}\n"
+ "strlist=\n"
+ "strlist/x=a\n"
+ "strlist/y=b\n"
+ "strlist/z=c\n"
+ "\n",
+};
+
+
+static void test_settings_get_time(void)
+{
+ static const struct {
+ const char *input;
+ unsigned int output;
+ } tests[] = {
+ { "0", 0 },
+
+ { "59s", 59 },
+ { "59 s", 59 },
+ { "59se", 59 },
+ { "59sec", 59 },
+ { "59secs", 59 },
+ { "59seco", 59 },
+ { "59secon", 59 },
+ { "59second", 59 },
+ { "59seconds", 59 },
+ { "123456 seconds", 123456 },
+
+ { "123m", 123*60 },
+ { "123 m", 123*60 },
+ { "123 mi", 123*60 },
+ { "123 min", 123*60 },
+ { "123 mins", 123*60 },
+ { "123 minu", 123*60 },
+ { "123 minut", 123*60 },
+ { "123 minute", 123*60 },
+ { "123 minutes", 123*60 },
+
+ { "123h", 123*60*60 },
+ { "123 h", 123*60*60 },
+ { "123 ho", 123*60*60 },
+ { "123 hou", 123*60*60 },
+ { "123 hour", 123*60*60 },
+ { "123 hours", 123*60*60 },
+
+ { "12d", 12*60*60*24 },
+ { "12 d", 12*60*60*24 },
+ { "12 da", 12*60*60*24 },
+ { "12 day", 12*60*60*24 },
+ { "12 days", 12*60*60*24 },
+
+ { "3w", 3*60*60*24*7 },
+ { "3 w", 3*60*60*24*7 },
+ { "3 we", 3*60*60*24*7 },
+ { "3 wee", 3*60*60*24*7 },
+ { "3 week", 3*60*60*24*7 },
+ { "3 weeks", 3*60*60*24*7 },
+
+ { "1000ms", 1 },
+ { "50000ms", 50 },
+ };
+ struct {
+ const char *input;
+ unsigned int output;
+ } msecs_tests[] = {
+ { "0ms", 0 },
+ { "1ms", 1 },
+ { "123456ms", 123456 },
+ { "123456 ms", 123456 },
+ { "123456mse", 123456 },
+ { "123456msec", 123456 },
+ { "123456msecs", 123456 },
+ { "123456mseco", 123456 },
+ { "123456msecon", 123456 },
+ { "123456msecond", 123456 },
+ { "123456mseconds", 123456 },
+ { "123456mil", 123456 },
+ { "123456mill", 123456 },
+ { "123456milli", 123456 },
+ { "123456millis", 123456 },
+ { "123456millisec", 123456 },
+ { "123456millisecs", 123456 },
+ { "123456milliseco", 123456 },
+ { "123456millisecon", 123456 },
+ { "123456millisecond", 123456 },
+ { "123456milliseconds", 123456 },
+ { "4294967295 ms", 4294967295 },
+ };
+ const char *secs_errors[] = {
+ "-1",
+ "1",
+ /* wrong spellings: */
+ "1ss",
+ "1secss",
+ "1secondss",
+ "1ma",
+ "1minsa",
+ "1hu",
+ "1hoursa",
+ "1dd",
+ "1days?",
+ "1wa",
+ "1weeksb",
+
+ /* milliseconds: */
+ "1ms",
+ "999ms",
+ "1001ms",
+ /* overflows: */
+ "7102 w",
+ "4294967296 s",
+ };
+ const char *msecs_errors[] = {
+ "-1",
+ "1",
+ /* wrong spellings: */
+ "1mis",
+ "1mss",
+ /* overflows: */
+ "8 w",
+ "4294967296 ms",
+ };
+ unsigned int i, secs, msecs;
+ const char *error;
+
+ test_begin("settings_get_time()");
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ test_assert_idx(settings_get_time(tests[i].input, &secs, &error) == 0, i);
+ test_assert_idx(secs == tests[i].output, i);
+
+ test_assert_idx(settings_get_time_msecs(tests[i].input, &msecs, &error) == 0, i);
+ test_assert_idx(msecs == tests[i].output*1000, i);
+ }
+ for (i = 0; i < N_ELEMENTS(msecs_tests); i++) {
+ test_assert_idx(settings_get_time_msecs(msecs_tests[i].input, &msecs, &error) == 0, i);
+ test_assert_idx(msecs == msecs_tests[i].output, i);
+ }
+ for (i = 0; i < N_ELEMENTS(secs_errors); i++)
+ test_assert_idx(settings_get_time(secs_errors[i], &secs, &error) < 0, i);
+ for (i = 0; i < N_ELEMENTS(msecs_errors); i++)
+ test_assert_idx(settings_get_time_msecs(msecs_errors[i], &msecs, &error) < 0, i);
+ test_end();
+}
+
+static void test_settings_get_size(void)
+{
+ test_begin("settings_get_size()");
+
+ static const struct {
+ const char *input;
+ uoff_t output;
+ } tests[] = {
+ { "0", 0 },
+ { "0000", 0 },
+ { "1b", 1 },
+ { "1B", 1 },
+ { "1 b", 1 },
+ { "1k", 1024 },
+ { "1K", 1024 },
+ { "1 k", 1024 },
+ { "1m", 1024*1024 },
+ { "1M", 1024*1024 },
+ { "1 m", 1024*1024 },
+ { "1g", 1024*1024*1024ULL },
+ { "1G", 1024*1024*1024ULL },
+ { "1 g", 1024*1024*1024ULL },
+ { "1t", 1024*1024*1024*1024ULL },
+ { "1T", 1024*1024*1024*1024ULL },
+ { "1 t", 1024*1024*1024*1024ULL },
+ };
+
+ const char *size_errors[] = {
+ "-1",
+ "one",
+ "",
+ "340282366920938463463374607431768211456",
+ "2^32",
+ "2**32",
+ "1e10",
+ "1 byte",
+ };
+
+ size_t i;
+ uoff_t size;
+ const char *error;
+
+ for (i = 0; i < N_ELEMENTS(tests); i++) {
+ error = NULL;
+ test_assert_idx(settings_get_size(tests[i].input, &size, &error) == 0, i);
+ test_assert_idx(size == tests[i].output, i);
+ test_assert(error == NULL);
+ }
+ for (i = 0; i < N_ELEMENTS(size_errors); i++) {
+ error = NULL;
+ test_assert_idx(settings_get_size(size_errors[i], &size, &error) < 0, i);
+ test_assert(error != NULL);
+ };
+
+ test_end();
+}
+
+static void test_settings_parser_get(void)
+{
+ struct test_settings {
+ bool bool_true;
+ bool bool_false;
+ unsigned int uint;
+ unsigned int uint_oct;
+ unsigned int secs;
+ unsigned int msecs;
+ uoff_t size;
+ in_port_t port;
+ const char *str;
+ const char *expand_str;
+ ARRAY_TYPE(const_string) strlist;
+ } test_defaults = {
+ FALSE, /* for negation test */
+ TRUE,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "",
+ "",
+ ARRAY_INIT,
+ };
+ const struct setting_define defs[] = {
+ SETTING_DEFINE_STRUCT_BOOL("bool_true", bool_true, struct test_settings),
+ SETTING_DEFINE_STRUCT_BOOL("bool_false", bool_false, struct test_settings),
+ SETTING_DEFINE_STRUCT_UINT("uint", uint, struct test_settings),
+ { .type = SET_UINT_OCT, .key = "uint_oct",
+ offsetof(struct test_settings, uint_oct), NULL },
+ SETTING_DEFINE_STRUCT_TIME("secs", secs, struct test_settings),
+ SETTING_DEFINE_STRUCT_TIME_MSECS("msecs", msecs, struct test_settings),
+ SETTING_DEFINE_STRUCT_SIZE("size", size, struct test_settings),
+ SETTING_DEFINE_STRUCT_IN_PORT("port", port, struct test_settings),
+ SETTING_DEFINE_STRUCT_STR("str", str, struct test_settings),
+ { .type = SET_STR_VARS, .key = "expand_str",
+ offsetof(struct test_settings, expand_str), NULL },
+ { .type = SET_STRLIST, .key = "strlist",
+ offsetof(struct test_settings, strlist), NULL },
+ SETTING_DEFINE_LIST_END
+ };
+ const struct setting_parser_info root = {
+ .module_name = "test",
+ .defines = defs,
+ .defaults = &test_defaults,
+
+ .type_offset = SIZE_MAX,
+ .struct_size = sizeof(struct test_settings),
+
+ .parent_offset = SIZE_MAX,
+ };
+
+ test_begin("settings_parser_get");
+
+ pool_t pool = pool_alloconly_create("settings parser", 1024);
+ struct setting_parser_context *ctx =
+ settings_parser_init(pool, &root, 0);
+ struct istream *is = test_istream_create(test_settings_blobs[0]);
+ const char *error = NULL;
+ int ret;
+ while((ret = settings_parse_stream_read(ctx, is)) > 0);
+ test_assert(ret == 0);
+ if (ret < 0)
+ i_error("settings_parse_stream failed: %s",
+ settings_parser_get_error(ctx));
+ i_stream_unref(&is);
+ test_assert(settings_parser_check(ctx, pool, NULL));
+
+ /* check what we got */
+ struct test_settings *settings = settings_parser_get(ctx);
+ test_assert(settings != NULL);
+
+ test_assert(settings->bool_true == TRUE);
+ test_assert(settings->bool_false == FALSE);
+ test_assert(settings->uint == 15);
+ test_assert(settings->uint_oct == 0700);
+ test_assert(settings->secs == 5);
+ test_assert(settings->msecs == 5);
+ test_assert(settings->size == 1024);
+ test_assert(settings->port == 2205);
+ test_assert_strcmp(settings->str, "test string");
+ test_assert_strcmp(settings->expand_str, "0test %{string}");
+
+ test_assert(array_count(&settings->strlist) == 6);
+ test_assert_strcmp(t_array_const_string_join(&settings->strlist, ";"),
+ "x;a;y;b;z;c");
+
+ const struct var_expand_table table[] = {
+ {'\0', "value", "string"},
+ {'\0', NULL, NULL}
+ };
+
+ /* expand settings */
+ test_assert(settings_var_expand(&root, settings, pool, table, &error) == 1 &&
+ error == NULL);
+
+ /* check that the setting got expanded */
+ test_assert_strcmp(settings->expand_str, "test value");
+
+ settings_parser_deinit(&ctx);
+ pool_unref(&pool);
+ test_end();
+}
+
+int main(void)
+{
+ static void (*const test_functions[])(void) = {
+ test_settings_get_time,
+ test_settings_get_size,
+ test_settings_parser_get,
+ NULL
+ };
+ return test_run(test_functions);
+}