]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap: Add test-imap-seqset
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 2 Dec 2025 22:44:31 +0000 (00:44 +0200)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 3 Dec 2025 20:02:34 +0000 (22:02 +0200)
src/lib-imap/Makefile.am
src/lib-imap/test-imap-seqset.c [new file with mode: 0644]

index 24d337b1a10ed9a00c52ee107aa557376178ff8d..5504d553af6c7e8933a93551438485e1169ffce7 100644 (file)
@@ -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 (file)
index 0000000..5d5b55a
--- /dev/null
@@ -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);
+}