From: Timo Sirainen Date: Tue, 2 Dec 2025 22:44:31 +0000 (+0200) Subject: lib-imap: Add test-imap-seqset X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4a0bddac33270d7b119689d6b58ab198e78273ad;p=thirdparty%2Fdovecot%2Fcore.git lib-imap: Add test-imap-seqset --- diff --git a/src/lib-imap/Makefile.am b/src/lib-imap/Makefile.am index 24d337b1a1..5504d553af 100644 --- a/src/lib-imap/Makefile.am +++ b/src/lib-imap/Makefile.am @@ -52,6 +52,7 @@ test_programs = \ test-imap-match \ test-imap-parser \ test-imap-quote \ + test-imap-seqset \ test-imap-url \ test-imap-utf7 \ test-imap-util @@ -88,6 +89,10 @@ test_imap_quote_SOURCES = test-imap-quote.c test_imap_quote_LDADD = imap-quote.lo $(test_libs) test_imap_quote_DEPENDENCIES = $(test_deps) +test_imap_seqset_SOURCES = test-imap-seqset.c +test_imap_seqset_LDADD = libimap.la $(test_libs) +test_imap_seqset_DEPENDENCIES = $(test_deps) + test_imap_url_SOURCES = test-imap-url.c test_imap_url_LDADD = imap-url.lo $(test_libs) test_imap_url_DEPENDENCIES = $(test_deps) diff --git a/src/lib-imap/test-imap-seqset.c b/src/lib-imap/test-imap-seqset.c new file mode 100644 index 0000000000..5d5b55a51c --- /dev/null +++ b/src/lib-imap/test-imap-seqset.c @@ -0,0 +1,167 @@ +/* Copyright (c) 2025 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "imap-seqset.h" +#include "imap-util.h" +#include "seq-range-array.h" +#include "test-common.h" + +static void imap_write_seq_range_star_one(string_t *dest, uint32_t seq) +{ + if (seq == UINT32_MAX) + str_append_c(dest, '*'); + else + str_printfa(dest, "%u", seq); +} + +static void +imap_write_seq_range_star(string_t *dest, const ARRAY_TYPE(seq_range) *array) +{ + const struct seq_range *range; + unsigned int i, count; + + range = array_get(array, &count); + for (i = 0; i < count; i++) { + if (i > 0) + str_append_c(dest, ','); + imap_write_seq_range_star_one(dest, range[i].seq1); + if (range[i].seq1 != range[i].seq2) { + str_append_c(dest, ':'); + imap_write_seq_range_star_one(dest, range[i].seq2); + } + } +} + +static void test_imap_seq_set_parse(void) +{ + static const struct { + const char *input; + const char *output; + int ret; + } tests[] = { + { "0", "", -1 }, + { "1", "1", 0 }, + { "2:4", "2:4", 0 }, + { "5:*", "5:*", 0 }, + { "1,3,5", "1,3,5", 0 }, + { "1,3:5,7:*", "1,3:5,7:*", 0 }, + { "1,2,3,4,5", "1:5", 0 }, + { "1,2,4,5", "1:2,4:5", 0 }, + { "1,3,2,5,4", "1:5", 0 }, + /* Comma at the end is not actually valid, but for now at least + we allow it. At least imapc used to send UID STORE commands + with uidsets ending with comma. */ + { "1,2,", "1:2", 0 }, + { "4294967296", "", -1 }, + { "4294967295", "4294967294", 0 }, + { "4294967294:4294967295", "4294967294", 0 }, + { "4294967293:4294967295", "4294967293:4294967294", 0 }, + { ",", "", -1 }, + { "1,,5", "", -1 }, + { "1:2,3,,5", "", -1 }, + { "a", "", -1 }, + { "1:a", "", -1 }, + { "1:2a", "", -1 }, + }; + ARRAY_TYPE(seq_range) ranges; + + test_begin("imap_seq_set_parse()"); + t_array_init(&ranges, 4); + + for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) { + array_clear(&ranges); + int ret = imap_seq_set_parse(tests[i].input, &ranges); + test_assert_idx(ret == tests[i].ret, i); + if (ret == 0) { + string_t *str = t_str_new(128); + imap_write_seq_range_star(str, &ranges); + test_assert_strcmp_idx(str_c(str), tests[i].output, i); + } + } + test_end(); +} + +static void test_imap_seq_set_nostar_parse(void) +{ + static const struct { + const char *input; + const char *output; + int ret; + } tests[] = { + { "1", "1", 0 }, + { "2:4", "2:4", 0 }, + { "1,3,5", "1,3,5", 0 }, + { "1,3:5", "1,3:5", 0 }, + { "1,2,3,4,5", "1:5", 0 }, + { "1,2,4,5", "1:2,4:5", 0 }, + { "1,3,2,5,4", "1:5", 0 }, + { "5:*", "", -1 }, + { "1,3:5,7:*", "", -1 }, + { "*", "", -1 }, + }; + ARRAY_TYPE(seq_range) ranges; + + test_begin("imap_seq_set_nostar_parse()"); + t_array_init(&ranges, 4); + + for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) { + array_clear(&ranges); + int ret = imap_seq_set_nostar_parse(tests[i].input, &ranges); + test_assert_idx(ret == tests[i].ret, i); + if (ret == 0) { + string_t *str = t_str_new(128); + imap_write_seq_range_star(str, &ranges); + test_assert_strcmp_idx(str_c(str), tests[i].output, i); + } + } + test_end(); +} + +static void test_imap_seq_range_parse(void) +{ + static const struct { + const char *input; + uint32_t seq1, seq2; + int ret; + } tests[] = { + { "1", 1, 1, 0 }, + { "2:4", 2, 4, 0 }, + { "5:*", 5, (uint32_t)-1, 0 }, + { "*", (uint32_t)-1, (uint32_t)-1, 0 }, + { "0", 0, 0, -1 }, + { "1:0", 0, 0, -1 }, + { "", 0, 0, -1 }, + { ":", 0, 0, -1 }, + { "1:", 0, 0, -1 }, + { ":5", 0, 0, -1 }, + { "a", 0, 0, -1 }, + { "1a", 0, 0, -1 }, + { "1:a", 0, 0, -1 }, + }; + uint32_t seq1, seq2; + + test_begin("imap_seq_range_parse()"); + + for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) { + int ret = imap_seq_range_parse(tests[i].input, &seq1, &seq2); + test_assert_idx(ret == tests[i].ret, i); + if (ret == 0) { + test_assert_idx(seq1 == tests[i].seq1 && + seq2 == tests[i].seq2, i); + } + } + test_end(); +} + +int main(void) +{ + static void (*const test_functions[])(void) = { + test_imap_seq_set_parse, + test_imap_seq_set_nostar_parse, + test_imap_seq_range_parse, + NULL + }; + return test_run(test_functions); +}