]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: test-rfc822-parser - Add tests for content-type full parsing
authorAki Tuomi <aki.tuomi@open-xchange.com>
Tue, 17 Nov 2020 07:29:30 +0000 (09:29 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Tue, 1 Dec 2020 14:33:32 +0000 (14:33 +0000)
src/lib-mail/test-rfc822-parser.c

index e5cf405f69a615229729a28144170aebbda39f16..a0e7ad04b8e868eb5e20cbbce26aab5cc339a7ea 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "str.h"
 #include "rfc822-parser.h"
 #include "test-common.h"
@@ -321,6 +322,112 @@ static void test_rfc822_parse_content_param(void)
        test_end();
 }
 
+struct param {
+       const char *key, *value;
+};
+
+static void parse_content_type_param(const void *input, size_t input_len,
+                                    const char *content_type,
+                                    const struct param *params, size_t param_count,
+                                    bool expect_content_type, int expect_ret,
+                                    int idx)
+{
+       struct rfc822_parser_context parser;
+       const char *key;
+       string_t *value = t_str_new(64);
+       unsigned int i = 0;
+       int ret;
+
+       i_assert(params != NULL || param_count == 0);
+
+       rfc822_parser_init(&parser, input, input_len, NULL);
+       ret = rfc822_parse_content_type(&parser, value);
+       test_assert_idx((expect_content_type && ret == 1) ||
+                       (!expect_content_type && ret == -1), idx);
+       test_assert_strcmp_idx(content_type, str_c(value), idx);
+
+       /* parse content type first */
+       while ((ret = rfc822_parse_content_param(&parser, &key, value)) > 0) {
+               if (i < param_count) {
+                       test_assert_strcmp_idx(params[i].key, key, idx);
+                       test_assert_strcmp_idx(params[i].value, str_c(value), idx);
+               }
+               i++;
+       }
+
+       test_assert_idx(expect_ret == ret, idx);
+       test_assert_idx(i == param_count, idx);
+       rfc822_parser_deinit(&parser);
+}
+
+#undef TEST_STRING
+#define TEST_STRING(a) (a), sizeof((a))-1
+
+#define X10(a) a a a a a a a a a a
+
+static void test_rfc822_parse_content_type_param(void)
+{
+        const char *input =
+               "(hello) text/plain ; (should we skip;comments=\"yes\")"
+               " param=value"
+               " ; param2=value2 (with comments (with comment) with;comment=\"yes\") "
+               " ; param3=\"value3 (with no comment ; or=value)\""
+               " ; param4=\"\xe7\xa8\xae\xe9\xa1\x9e\""
+               " ; \xe5\x90\xab\xe9\x87\x8f=\"\xe7\xa8\xae\xe9\xa1\x9e\""
+               " ; "X10(X10(X10("a")))"="X10(X10(X10("a")))
+               " ; "X10(X10(X10(X10("a"))))"="X10(X10(X10(X10("a"))))
+               " ; (comment) param7 (comment2) = (comment3) value7 (comment4) "
+       ;
+
+       const struct param output[] = {
+               { "param", "value" },
+               { "param2", "value2" },
+               { "param3", "value3 (with no comment ; or=value)" },
+               { "param4", "\xe7\xa8\xae\xe9\xa1\x9e" },
+               { "\xe5\x90\xab\xe9\x87\x8f", "\xe7\xa8\xae\xe9\xa1\x9e" },
+               { X10(X10(X10("a"))), X10(X10(X10("a"))) },
+               { X10(X10(X10(X10("a")))), X10(X10(X10(X10("a")))) },
+               { "param7", "value7" },
+       };
+       const struct param output5[] = {
+               { "charset", "" },
+       };
+
+       test_begin("rfc822 parse content type with params");
+
+       int idx = 0;
+       parse_content_type_param(input, strlen(input), "text/plain",
+                                output, N_ELEMENTS(output), TRUE, 0, idx++);
+       parse_content_type_param(TEST_STRING("text/"), "", NULL, 0, FALSE, 0, idx++);
+       parse_content_type_param(
+               TEST_STRING("text/\0plain ;"), "", NULL, 0, FALSE, -1, idx++);
+       parse_content_type_param(
+               TEST_STRING("text/plain\0;charset=us-ascii"), "", NULL, 0, FALSE, -1, idx++);
+       parse_content_type_param(
+               TEST_STRING("text/plain;charset\0=us-ascii"), "text/plain", NULL, 0, TRUE, -1, idx++);
+       parse_content_type_param(
+               TEST_STRING("text/plain;charset="), "text/plain",
+               output5, N_ELEMENTS(output5), TRUE, 0, idx++);
+       parse_content_type_param(
+               TEST_STRING("text/plain ; ; charset=us-ascii"), "text/plain", NULL, 0, TRUE, -1, idx++);
+       /* build a large one */
+       ARRAY(struct param) output2;
+       t_array_init(&output2, 1000);
+       string_t *large = t_str_new(10000);
+       str_append(large, "text/plain");
+       for (unsigned int i = 0; i < 1000; i++) {
+               str_printfa(large, " ; param%u=\"value%u\"", i, i);
+               struct param *param = array_append_space(&output2);
+               param->key = t_strdup_printf("param%u", i);
+               param->value = t_strdup_printf("value%u", i);
+       }
+       parse_content_type_param(large->data, large->used,
+                                "text/plain",
+                                array_idx(&output2, 0), array_count(&output2),
+                                TRUE, 0, idx++);
+       test_end();
+}
+
 int main(void)
 {
        static void (*const test_functions[])(void) = {
@@ -331,6 +438,7 @@ int main(void)
                test_rfc822_parse_domain_literal,
                test_rfc822_parse_content_type,
                test_rfc822_parse_content_param,
+               test_rfc822_parse_content_type_param,
                NULL
        };
        return test_run(test_functions);