diff options
Diffstat (limited to 'src/lib-imap/test-imap-utf7.c')
-rw-r--r-- | src/lib-imap/test-imap-utf7.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/lib-imap/test-imap-utf7.c b/src/lib-imap/test-imap-utf7.c new file mode 100644 index 0000000..216eebf --- /dev/null +++ b/src/lib-imap/test-imap-utf7.c @@ -0,0 +1,216 @@ +/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "unichar.h" +#include "imap-utf7.h" +#include "test-common.h" + +static void test_imap_utf7_by_example(void) +{ + static const struct test { + const char *utf8; + const char *mutf7; + } tests[] = { + { "&&x&&", "&-&-x&-&-" }, + { "~peter/mail/\xe5\x8f\xb0\xe5\x8c\x97/\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e", + "~peter/mail/&U,BTFw-/&ZeVnLIqe-" }, + { "tiet\xc3\xa4&j\xc3\xa4&", "tiet&AOQ-&-j&AOQ-&-" }, /* & is always encoded as &- */ + { "p\xe4\xe4", NULL }, + { NULL, "&" }, + { NULL, "&Jjo" }, + { NULL, "&Jjo!" }, + { NULL, "&U,BTFw-&ZeVnLIqe-" } /* unnecessary shift */ + }; + string_t *dest, *dest2; + unsigned int i; + + dest = t_str_new(256); + dest2 = t_str_new(256); + + test_begin("imap mutf7 examples"); + for (i = 0; i < N_ELEMENTS(tests); i++) { + str_truncate(dest, 0); + if (tests[i].utf8 != NULL) { + if (imap_utf8_to_utf7(tests[i].utf8, dest) < 0) + test_assert_idx(tests[i].mutf7 == NULL, i); + else + test_assert_idx(null_strcmp(tests[i].mutf7, str_c(dest)) == 0, i); + } else { + /* invalid mUTF-7 - test that escaping works */ + str_truncate(dest2, 0); + imap_utf7_to_utf8_escaped(tests[i].mutf7, "%", dest); + imap_escaped_utf8_to_utf7(str_c(dest), '%', dest2); + test_assert_idx(strcmp(tests[i].mutf7, str_c(dest2)) == 0, i); + } + if (tests[i].mutf7 != NULL) { + str_truncate(dest, 0); + if (imap_utf7_to_utf8(tests[i].mutf7, dest) < 0) + test_assert_idx(tests[i].utf8 == NULL, i); + else + test_assert_idx(null_strcmp(tests[i].utf8, str_c(dest)) == 0, i); + test_assert_idx(imap_utf7_is_valid(tests[i].mutf7) != (tests[i].utf8 == NULL), i); + } + } + + str_truncate(dest, 0); + imap_utf7_to_utf8_escaped(".foo%", "%.", dest); + test_assert_strcmp(str_c(dest), "%2efoo%25"); + + str_truncate(dest, 0); + test_assert(imap_escaped_utf8_to_utf7("%foo%2ebar", '%', dest) == 0); + test_assert_strcmp(str_c(dest), "%foo.bar"); + + test_end(); +} + +static void test_imap_utf7_ucs4_cases(void) +{ + string_t *src, *dest; + const char *orig_src; + unsigned int i, j; + unichar_t chr; + + src = t_str_new(256); + dest = t_str_new(256); + + test_begin("imap mutf7 ucs4 cases"); + for (chr = 0xffff; chr <= 0x10010; chr++) T_BEGIN { + for (i = 1; i <= 10; i++) { + str_truncate(src, 0); + str_truncate(dest, 0); + for (j = 0; j < i; j++) { + if (j % 3 == 0) + str_append_c(src, 'x'); + if (j % 5 == 0) + str_append_c(src, '&'); + uni_ucs4_to_utf8_c(chr, src); + } + + orig_src = t_strdup(str_c(src)); + str_truncate(src, 0); + + test_assert_idx(imap_utf8_to_utf7(orig_src, dest) == 0, chr*100+i); + test_assert_idx(imap_utf7_to_utf8(str_c(dest), src) == 0, chr*100+i); + test_assert_idx(strcmp(str_c(src), orig_src) == 0, chr+100+i); + } + } T_END; + test_end(); +} + +static const char mb64[64]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; +static void test_imap_utf7_non_utf16(void) +{ + string_t *dest, *dest2; + unsigned int i; + + test_begin("imap mutf7 non-utf16"); + dest = t_str_new(32); + dest2 = t_str_new(32); + for (i = 0; i <= 255; ++i) { + /* Invalid, code a single 8-bit octet */ + const char csrc[] = { + '&', + mb64[i >> 2], + mb64[(i & 3) << 4], + '-', + '\0' + }; + test_assert_idx(!imap_utf7_is_valid(csrc), i); + + /* escaping can reverse the original string */ + str_truncate(dest, 0); + str_truncate(dest2, 0); + imap_utf7_to_utf8_escaped(csrc, "%", dest); + imap_escaped_utf8_to_utf7(str_c(dest), '%', dest2); + test_assert_idx(strcmp(csrc, str_c(dest2)) == 0, i); + } + for (i = 0; i <= 255; ++i) { + /* Invalid, U+00E4 followed by a single octet */ + const char csrc[] = { + '&', + mb64[ (0x00 >> 2)], + mb64[((0x00 & 0x03) << 4) | (0xe4 >> 4)], + mb64[((0xe4 & 0x0f) << 2) | ( i >> 6)], + mb64[ i & 0x3f ], + '-', + '\0' + }; + test_assert_idx(!imap_utf7_is_valid(csrc), i); + + /* escaping can reverse the original string */ + str_truncate(dest, 0); + str_truncate(dest2, 0); + imap_utf7_to_utf8_escaped(csrc, "%", dest); + imap_escaped_utf8_to_utf7(str_c(dest), '%', dest2); + test_assert_idx(strcmp(csrc, str_c(dest2)) == 0, i); + } + test_end(); +} + +static void test_imap_utf7_bad_ascii(void) +{ + string_t *dest; + char csrc[1+1]; + unsigned int i; + + dest = t_str_new(256); + + test_begin("imap mutf7 bad ascii"); + for (i = 1; i <= 0x7f; ++i) { + if (i == ' ') + i = 0x7f; + csrc[0] = i; + csrc[1] = '\0'; + test_assert_idx(!imap_utf7_is_valid(csrc), i); + str_truncate(dest, 0); + test_assert_idx(imap_utf7_to_utf8(csrc, dest) < 0, i); + } + test_end(); +} + +static void test_imap_utf7_unnecessary(void) +{ + string_t *dest; + char csrc[1+3+1+1]; + unsigned int i; + + dest = t_str_new(256); + + test_begin("imap mutf7 unnecessary"); + for (i = 0x20; i < 0x7f; ++i) { + /* Create an invalid escaped encoding of a simple char or '&' */ + csrc[0] = '&'; + csrc[1] = mb64[ (0x00 >> 2)]; + csrc[2] = mb64[((0x00 & 0x03) << 4) | ( i >> 4)]; + csrc[3] = mb64[(( i & 0x0f) << 2) | 0 ]; + csrc[4] = '-'; + csrc[5] = '\0'; + test_assert_idx(!imap_utf7_is_valid(csrc), i); + str_truncate(dest, 0); + test_assert_idx(imap_utf7_to_utf8(csrc, dest) < 0, i); + + /* All self-coding characters must self-code */ + if (i == '&') + continue; + csrc[0] = i; + csrc[1] = '\0'; + str_truncate(dest, 0); + test_assert_idx(imap_utf8_to_utf7(csrc, dest) >= 0, i); + test_assert_idx(strcmp(csrc, str_c(dest)) == 0, i); + } + test_end(); +} + +int main(void) +{ + static void (*const test_functions[])(void) = { + test_imap_utf7_by_example, + test_imap_utf7_ucs4_cases, + test_imap_utf7_non_utf16, + test_imap_utf7_bad_ascii, + test_imap_utf7_unnecessary, + NULL + }; + return test_run(test_functions); +} |