From: Karl Fleischmann Date: Wed, 26 Oct 2022 14:57:08 +0000 (+0200) Subject: lib, lib-settings: Move string-parse functions for bool/size/interval into lib X-Git-Tag: 2.4.0~3400 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=347ae75e46d84f64e76e3b5cf25581d144a82ba7;p=thirdparty%2Fdovecot%2Fcore.git lib, lib-settings: Move string-parse functions for bool/size/interval into lib Including the tests. Call the new functions from the existing settings-functions. These will be removed in a later commit. --- diff --git a/src/lib-settings/settings-parser.c b/src/lib-settings/settings-parser.c index a64ee66cb1..ab5f9008a2 100644 --- a/src/lib-settings/settings-parser.c +++ b/src/lib-settings/settings-parser.c @@ -9,12 +9,12 @@ #include "execv-const.h" #include "str.h" #include "strescape.h" +#include "str-parse.h" #include "var-expand.h" #include "settings-parser.h" #include #include -#include #include #include #include @@ -302,19 +302,7 @@ setting_define_find(const struct setting_parser_info *info, const char *key) int settings_get_bool(const char *value, bool *result_r, const char **error_r) { - /* FIXME: eventually we'd want to support only yes/no */ - if (strcasecmp(value, "yes") == 0 || - strcasecmp(value, "y") == 0 || strcmp(value, "1") == 0) - *result_r = TRUE; - else if (strcasecmp(value, "no") == 0) - *result_r = FALSE; - else { - *error_r = t_strdup_printf("Invalid boolean value: %s (use yes or no)", - value); - return -1; - } - - return 0; + return str_parse_get_bool(value, result_r, error_r); } static int @@ -357,146 +345,22 @@ get_octal(struct setting_parser_context *ctx, const char *value, return 0; } -static int settings_get_time_full(const char *str, unsigned int *interval_r, - bool milliseconds, const char **error_r) -{ - uintmax_t num, multiply = milliseconds ? 1000 : 1; - const char *p; - - if (str_parse_uintmax(str, &num, &p) < 0) { - *error_r = t_strconcat("Invalid time interval: ", str, NULL); - return -1; - } - while (*p == ' ') p++; - if (*p == '\0' && num != 0) { - *error_r = t_strdup_printf("Time interval '%s' is missing units " - "(add e.g. 's' for seconds)", str); - return -1; - } - switch (i_toupper(*p)) { - case 'S': - multiply *= 1; - if (str_begins_icase_with("secs", p) || - str_begins_icase_with("seconds", p)) - p = ""; - break; - case 'M': - multiply *= 60; - if (str_begins_icase_with("mins", p) || - str_begins_icase_with("minutes", p)) - p = ""; - else if (str_begins_icase_with("msecs", p) || - str_begins_icase_with("mseconds", p) || - str_begins_icase_with("millisecs", p) || - str_begins_icase_with("milliseconds", p)) { - if (milliseconds || (num % 1000) == 0) { - if (!milliseconds) { - /* allow ms also for seconds, as long - as it's divisible by seconds */ - num /= 1000; - } - multiply = 1; - p = ""; - break; - } - *error_r = t_strdup_printf( - "Milliseconds not supported for this setting: %s", str); - return -1; - } - break; - case 'H': - multiply *= 60*60; - if (str_begins_icase_with("hours", p)) - p = ""; - break; - case 'D': - multiply *= 60*60*24; - if (str_begins_icase_with("days", p)) - p = ""; - break; - case 'W': - multiply *= 60*60*24*7; - if (str_begins_icase_with("weeks", p)) - p = ""; - break; - } - - if (*p != '\0') { - *error_r = t_strconcat("Invalid time interval: ", str, NULL); - return -1; - } - if (num > UINT_MAX / multiply) { - *error_r = t_strconcat("Time interval is too large: ", - str, NULL); - return -1; - } - *interval_r = num * multiply; - return 0; -} - int settings_get_time(const char *str, unsigned int *secs_r, const char **error_r) { - return settings_get_time_full(str, secs_r, FALSE, error_r); + return str_parse_get_interval(str, secs_r, error_r); } int settings_get_time_msecs(const char *str, unsigned int *msecs_r, const char **error_r) { - return settings_get_time_full(str, msecs_r, TRUE, error_r); + return str_parse_get_interval_msecs(str, msecs_r, error_r); } int settings_get_size(const char *str, uoff_t *bytes_r, const char **error_r) { - uintmax_t num, multiply = 1; - const char *p; - - if (str_parse_uintmax(str, &num, &p) < 0) { - *error_r = t_strconcat("Invalid size: ", str, NULL); - return -1; - } - while (*p == ' ') p++; - switch (i_toupper(*p)) { - case 'B': - multiply = 1; - p += 1; - break; - case 'K': - multiply = 1024; - p += 1; - break; - case 'M': - multiply = 1024*1024; - p += 1; - break; - case 'G': - multiply = 1024*1024*1024; - p += 1; - break; - case 'T': - multiply = 1024ULL*1024*1024*1024; - p += 1; - break; - } - - if (multiply > 1) { - /* Allow: k, ki, kiB */ - if (i_toupper(*p) == 'I') - p++; - if (i_toupper(*p) == 'B') - p++; - } - if (*p != '\0') { - *error_r = t_strconcat("Invalid size: ", str, NULL); - return -1; - } - if (num > (UOFF_T_MAX) / multiply) { - *error_r = t_strconcat("Size is too large: ", str, NULL); - return -1; - } - *bytes_r = num * multiply; - return 0; + return str_parse_get_size(str, bytes_r, error_r); } static int get_enum(struct setting_parser_context *ctx, const char *value, diff --git a/src/lib-settings/settings-parser.h b/src/lib-settings/settings-parser.h index 81ce318aa1..24d21c9bc6 100644 --- a/src/lib-settings/settings-parser.h +++ b/src/lib-settings/settings-parser.h @@ -1,6 +1,8 @@ #ifndef SETTINGS_PARSER_H #define SETTINGS_PARSER_H +#include "str-parse.h" + struct var_expand_table; struct var_expand_func_table; diff --git a/src/lib-settings/test-settings-parser.c b/src/lib-settings/test-settings-parser.c index 83aefbafce..d16b263fe1 100644 --- a/src/lib-settings/test-settings-parser.c +++ b/src/lib-settings/test-settings-parser.c @@ -28,199 +28,6 @@ static const char *test_settings_blobs[] = "\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 { @@ -331,8 +138,6 @@ static void test_settings_parser_get(void) int main(void) { static void (*const test_functions[])(void) = { - test_settings_get_time, - test_settings_get_size, test_settings_parser_get, NULL }; diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index e7adbbc484..817a6dfffb 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -187,6 +187,7 @@ liblib_la_SOURCES = \ str.c \ str-find.c \ str-sanitize.c \ + str-parse.c \ str-table.c \ strescape.c \ strfuncs.c \ @@ -346,6 +347,7 @@ headers = \ str.h \ str-find.h \ str-sanitize.h \ + str-parse.h \ str-table.h \ strescape.h \ strfuncs.h \ @@ -462,6 +464,7 @@ test_lib_SOURCES = \ test-strnum.c \ test-str-find.c \ test-str-sanitize.c \ + test-str-parse.c \ test-str-table.c \ test-time-util.c \ test-unichar.c \ diff --git a/src/lib/str-parse.c b/src/lib/str-parse.c new file mode 100644 index 0000000000..34068c913a --- /dev/null +++ b/src/lib/str-parse.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2022 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str-parse.h" + +#include + +static int str_parse_get_interval_full( + const char *str, unsigned int *interval_r, bool milliseconds, + const char **error_r) +{ + uintmax_t num, multiply = milliseconds ? 1000 : 1; + const char *p; + + if (str_parse_uintmax(str, &num, &p) < 0) { + *error_r = t_strconcat("Invalid time interval: ", str, NULL); + return -1; + } + while (*p == ' ') p++; + if (*p == '\0' && num != 0) { + *error_r = t_strdup_printf("Time interval '%s' is missing units " + "(add e.g. 's' for seconds)", str); + return -1; + } + switch (i_toupper(*p)) { + case 'S': + multiply *= 1; + if (str_begins_icase_with("secs", p) || + str_begins_icase_with("seconds", p)) + p = ""; + break; + case 'M': + multiply *= 60; + if (str_begins_icase_with("mins", p) || + str_begins_icase_with("minutes", p)) + p = ""; + else if (str_begins_icase_with("msecs", p) || + str_begins_icase_with("mseconds", p) || + str_begins_icase_with("millisecs", p) || + str_begins_icase_with("milliseconds", p)) { + if (milliseconds || (num % 1000) == 0) { + if (!milliseconds) { + /* allow ms also for seconds, as long + as it's divisible by seconds */ + num /= 1000; + } + multiply = 1; + p = ""; + break; + } + *error_r = t_strdup_printf( + "Milliseconds not supported for this setting: %s", str); + return -1; + } + break; + case 'H': + multiply *= 60*60; + if (str_begins_icase_with("hours", p)) + p = ""; + break; + case 'D': + multiply *= 60*60*24; + if (str_begins_icase_with("days", p)) + p = ""; + break; + case 'W': + multiply *= 60*60*24*7; + if (str_begins_icase_with("weeks", p)) + p = ""; + break; + } + + if (*p != '\0') { + *error_r = t_strconcat("Invalid time interval: ", str, NULL); + return -1; + } + if (num > UINT_MAX / multiply) { + *error_r = t_strconcat("Time interval is too large: ", + str, NULL); + return -1; + } + *interval_r = num * multiply; + return 0; +} + +int str_parse_get_interval(const char *str, unsigned int *secs_r, + const char **error_r) +{ + return str_parse_get_interval_full(str, secs_r, FALSE, error_r); +} + +int str_parse_get_interval_msecs(const char *str, unsigned int *msecs_r, + const char **error_r) +{ + return str_parse_get_interval_full(str, msecs_r, TRUE, error_r); +} + +int str_parse_get_size(const char *str, uoff_t *bytes_r, + const char **error_r) +{ + uintmax_t num, multiply = 1; + const char *p; + + if (str_parse_uintmax(str, &num, &p) < 0) { + *error_r = t_strconcat("Invalid size: ", str, NULL); + return -1; + } + while (*p == ' ') p++; + switch (i_toupper(*p)) { + case 'B': + multiply = 1; + p += 1; + break; + case 'K': + multiply = 1024; + p += 1; + break; + case 'M': + multiply = 1024*1024; + p += 1; + break; + case 'G': + multiply = 1024*1024*1024; + p += 1; + break; + case 'T': + multiply = 1024ULL*1024*1024*1024; + p += 1; + break; + } + + if (multiply > 1) { + /* Allow: k, ki, kiB */ + if (i_toupper(*p) == 'I') + p++; + if (i_toupper(*p) == 'B') + p++; + } + if (*p != '\0') { + *error_r = t_strconcat("Invalid size: ", str, NULL); + return -1; + } + if (num > (UOFF_T_MAX) / multiply) { + *error_r = t_strconcat("Size is too large: ", str, NULL); + return -1; + } + *bytes_r = num * multiply; + return 0; +} + +int str_parse_get_bool(const char *value, bool *result_r, + const char **error_r) +{ + /* FIXME: eventually we'd want to support only yes/no */ + if (strcasecmp(value, "yes") == 0 || + strcasecmp(value, "y") == 0 || strcmp(value, "1") == 0) + *result_r = TRUE; + else if (strcasecmp(value, "no") == 0) + *result_r = FALSE; + else { + *error_r = t_strdup_printf("Invalid boolean value: %s (use yes or no)", + value); + return -1; + } + + return 0; +} diff --git a/src/lib/str-parse.h b/src/lib/str-parse.h new file mode 100644 index 0000000000..882504fd8c --- /dev/null +++ b/src/lib/str-parse.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2022 Dovecot authors, see the included COPYING file */ +#ifndef STR_PARSE_H +#define STR_PARSE_H + +/* Parse time interval string, return as seconds. */ +int str_parse_get_interval(const char *str, unsigned int *secs_r, + const char **error_r); +/* Parse time interval string, return as milliseconds. */ +int str_parse_get_interval_msecs(const char *str, unsigned int *msecs_r, + const char **error_r); +/* Parse size string, return as bytes. */ +int str_parse_get_size(const char *str, uoff_t *bytes_r, + const char **error_r); +/* Parse boolean string, return as boolean */ +int str_parse_get_bool(const char *value, bool *result_r, + const char **error_r); + +#endif // STR_PARSE_H diff --git a/src/lib/test-lib.inc b/src/lib/test-lib.inc index d9b9c794ac..557d753a43 100644 --- a/src/lib/test-lib.inc +++ b/src/lib/test-lib.inc @@ -103,6 +103,7 @@ TEST(test_strfuncs) FATAL(fatal_strfuncs) TEST(test_strnum) TEST(test_str_find) +TEST(test_str_parse) TEST(test_str_sanitize) TEST(test_str_table) TEST(test_time_util) diff --git a/src/lib/test-str-parse.c b/src/lib/test-str-parse.c new file mode 100644 index 0000000000..17e03bf3aa --- /dev/null +++ b/src/lib/test-str-parse.c @@ -0,0 +1,209 @@ +/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "str-parse.h" + +static void test_str_parse_get_interval(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("str_parse_get_interval()"); + for (i = 0; i < N_ELEMENTS(tests); i++) { + test_assert_idx(str_parse_get_interval(tests[i].input, &secs, + &error) == 0, i); + test_assert_idx(secs == tests[i].output, i); + + test_assert_idx(str_parse_get_interval_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(str_parse_get_interval_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(str_parse_get_interval(secs_errors[i], &secs, + &error) < 0, i); + for (i = 0; i < N_ELEMENTS(msecs_errors); i++) + test_assert_idx(str_parse_get_interval_msecs( + msecs_errors[i], &msecs, &error) < 0, i); + test_end(); +} + +static void test_str_parse_get_size(void) +{ + test_begin("str_parse_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(str_parse_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(str_parse_get_size(size_errors[i], &size, + &error) < 0, i); + test_assert(error != NULL); + }; + + test_end(); +} + +void test_str_parse(void) +{ + test_str_parse_get_interval(); + test_str_parse_get_size(); +}