]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Moved mail_search_args_simplify() to its own file and added unit tests.
authorTimo Sirainen <tss@iki.fi>
Thu, 23 Apr 2015 16:29:43 +0000 (19:29 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 23 Apr 2015 16:29:43 +0000 (19:29 +0300)
No functional changes.

src/lib-storage/Makefile.am
src/lib-storage/mail-search-args-simplify.c [new file with mode: 0644]
src/lib-storage/mail-search.c
src/lib-storage/test-mail-search-args-simplify.c [new file with mode: 0644]

index 9652d2215d5921d517559d396185c431ddef4738..d9295f1150ffde55e4068d1b1eb81f5912de657a 100644 (file)
@@ -29,6 +29,7 @@ libstorage_la_SOURCES = \
        mail-namespace.c \
        mail-search.c \
        mail-search-args-imap.c \
+       mail-search-args-simplify.c \
        mail-search-build.c \
        mail-search-parser.c \
        mail-search-parser-imap.c \
@@ -98,6 +99,7 @@ libdovecot_storage_la_LDFLAGS = -export-dynamic
 
 test_programs = \
        test-mail-search-args-imap \
+       test-mail-search-args-simplify \
        test-mailbox-get
 
 noinst_PROGRAMS = $(test_programs)
@@ -114,6 +116,14 @@ test_mail_search_args_imap_DEPENDENCIES = \
        libstorage.la \
        $(LIBDOVECOT_DEPS)
 
+test_mail_search_args_simplify_SOURCES = test-mail-search-args-simplify.c
+test_mail_search_args_simplify_LDADD = \
+       $(LIBDOVECOT_STORAGE) \
+       $(LIBDOVECOT)
+test_mail_search_args_simplify_DEPENDENCIES = \
+       libstorage.la \
+       $(LIBDOVECOT_DEPS)
+
 test_mailbox_get_SOURCES = test-mailbox-get.c
 test_mailbox_get_LDADD = mailbox-get.lo $(test_libs)
 test_mailbox_get_DEPENDENCIES = $(noinst_LTLIBRARIES) $(test_libs)
diff --git a/src/lib-storage/mail-search-args-simplify.c b/src/lib-storage/mail-search-args-simplify.c
new file mode 100644 (file)
index 0000000..3bea99e
--- /dev/null
@@ -0,0 +1,156 @@
+/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "mail-search.h"
+
+static void
+mail_search_args_simplify_sub(struct mailbox *box,
+                             struct mail_search_arg *args, bool parent_and)
+{
+       struct mail_search_arg *sub, *prev = NULL;
+       struct mail_search_arg *prev_flags_arg, *prev_not_flags_arg;
+
+       prev_flags_arg = prev_not_flags_arg = NULL;
+       while (args != NULL) {
+               if (args->match_not && (args->type == SEARCH_SUB ||
+                                       args->type == SEARCH_OR)) {
+                       /* neg(p and q and ..) == neg(p) or neg(q) or ..
+                          neg(p or q or ..) == neg(p) and neg(q) and .. */
+                       args->type = args->type == SEARCH_SUB ?
+                               SEARCH_OR : SEARCH_SUB;
+                       args->match_not = FALSE;
+                       sub = args->value.subargs;
+                       do {
+                               sub->match_not = !sub->match_not;
+                               sub = sub->next;
+                       } while (sub != NULL);
+               }
+
+               if ((args->type == SEARCH_SUB && parent_and) ||
+                   (args->type == SEARCH_OR && !parent_and) ||
+                   ((args->type == SEARCH_SUB || args->type == SEARCH_OR) &&
+                    args->value.subargs->next == NULL)) {
+                       /* p and (q and ..) == p and q and ..
+                          p or (q or ..) == p or q or ..
+                          (p) = p */
+                       sub = args->value.subargs;
+                       for (; sub->next != NULL; sub = sub->next) ;
+                       sub->next = args->next;
+                       *args = *args->value.subargs;
+                       continue;
+               }
+
+               if (args->type == SEARCH_SUB ||
+                   args->type == SEARCH_OR ||
+                   args->type == SEARCH_INTHREAD) {
+                       mail_search_args_simplify_sub(box, args->value.subargs,
+                                                     args->type != SEARCH_OR);
+               }
+
+               /* merge all flags arguments */
+               if (args->type == SEARCH_FLAGS &&
+                   !args->match_not && parent_and) {
+                       if (prev_flags_arg == NULL)
+                               prev_flags_arg = args;
+                       else {
+                               prev_flags_arg->value.flags |=
+                                       args->value.flags;
+                               prev->next = args->next;
+                               args = args->next;
+                               continue;
+                       }
+               } else if (args->type == SEARCH_FLAGS && args->match_not &&
+                          !parent_and) {
+                       if (prev_not_flags_arg == NULL)
+                               prev_not_flags_arg = args;
+                       else {
+                               prev_not_flags_arg->value.flags |=
+                                       args->value.flags;
+                               prev->next = args->next;
+                               args = args->next;
+                               continue;
+                       }
+               }
+
+               prev = args;
+               args = args->next;
+       }
+}
+
+static bool
+mail_search_args_unnest_inthreads(struct mail_search_args *args,
+                                 struct mail_search_arg **argp,
+                                 bool parent_inthreads, bool parent_and)
+{
+       struct mail_search_arg *arg, *thread_arg, *or_arg;
+       bool child_inthreads = FALSE, non_inthreads = FALSE;
+
+       for (arg = *argp; arg != NULL; arg = arg->next) {
+               switch (arg->type) {
+               case SEARCH_SUB:
+               case SEARCH_OR:
+                       if (!mail_search_args_unnest_inthreads(args,
+                                       &arg->value.subargs, parent_inthreads,
+                                       arg->type != SEARCH_OR)) {
+                               arg->result = 1;
+                               child_inthreads = TRUE;
+                       } else {
+                               arg->result = 0;
+                               non_inthreads = TRUE;
+                       }
+                       break;
+               case SEARCH_INTHREAD:
+                       if (mail_search_args_unnest_inthreads(args,
+                                       &arg->value.subargs, TRUE, TRUE)) {
+                               /* children converted to SEARCH_INTHREADs */
+                               arg->type = SEARCH_SUB;
+                       }
+                       args->have_inthreads = TRUE;
+                       arg->result = 1;
+                       child_inthreads = TRUE;
+                       break;
+               default:
+                       arg->result = 0;
+                       non_inthreads = TRUE;
+                       break;
+               }
+       }
+
+       if (!parent_inthreads || !child_inthreads || !non_inthreads)
+               return FALSE;
+
+       /* put all non-INTHREADs under a single INTHREAD */
+       thread_arg = p_new(args->pool, struct mail_search_arg, 1);
+       thread_arg->type = SEARCH_INTHREAD;
+
+       while (*argp != NULL) {
+               arg = *argp;
+               argp = &(*argp)->next;
+
+               if (arg->result == 0) {
+                       /* not an INTHREAD or a SUB/OR with only INTHREADs */
+                       arg->next = thread_arg->value.subargs;
+                       thread_arg->value.subargs = arg;
+               }
+       }
+       if (!parent_and) {
+               /* We want to OR the args */
+               or_arg = p_new(args->pool, struct mail_search_arg, 1);
+               or_arg->type = SEARCH_OR;
+               or_arg->value.subargs = thread_arg->value.subargs;
+               thread_arg->value.subargs = or_arg;
+       }
+       return TRUE;
+}
+
+void mail_search_args_simplify(struct mail_search_args *args)
+{
+       args->simplified = TRUE;
+
+       mail_search_args_simplify_sub(args->box, args->args, TRUE);
+       if (mail_search_args_unnest_inthreads(args, &args->args,
+                                             FALSE, TRUE)) {
+               /* we may have added some extra SUBs that could be dropped */
+               mail_search_args_simplify_sub(args->box, args->args, TRUE);
+       }
+}
index be63a0cd35d66533052f79b05f2f625860a77817..571c344f5c80462e859721dcaf70057f8b523e87 100644 (file)
@@ -587,158 +587,6 @@ bool mail_search_args_match_mailbox(struct mail_search_args *args,
        return TRUE;
 }
 
-static void
-mail_search_args_simplify_sub(struct mailbox *box,
-                             struct mail_search_arg *args, bool parent_and)
-{
-       struct mail_search_arg *sub, *prev = NULL;
-       struct mail_search_arg *prev_flags_arg, *prev_not_flags_arg;
-
-       prev_flags_arg = prev_not_flags_arg = NULL;
-       while (args != NULL) {
-               if (args->match_not && (args->type == SEARCH_SUB ||
-                                       args->type == SEARCH_OR)) {
-                       /* neg(p and q and ..) == neg(p) or neg(q) or ..
-                          neg(p or q or ..) == neg(p) and neg(q) and .. */
-                       args->type = args->type == SEARCH_SUB ?
-                               SEARCH_OR : SEARCH_SUB;
-                       args->match_not = FALSE;
-                       sub = args->value.subargs;
-                       do {
-                               sub->match_not = !sub->match_not;
-                               sub = sub->next;
-                       } while (sub != NULL);
-               }
-
-               if ((args->type == SEARCH_SUB && parent_and) ||
-                   (args->type == SEARCH_OR && !parent_and) ||
-                   ((args->type == SEARCH_SUB || args->type == SEARCH_OR) &&
-                    args->value.subargs->next == NULL)) {
-                       /* p and (q and ..) == p and q and ..
-                          p or (q or ..) == p or q or ..
-                          (p) = p */
-                       sub = args->value.subargs;
-                       for (; sub->next != NULL; sub = sub->next) ;
-                       sub->next = args->next;
-                       *args = *args->value.subargs;
-                       continue;
-               }
-
-               if (args->type == SEARCH_SUB ||
-                   args->type == SEARCH_OR ||
-                   args->type == SEARCH_INTHREAD) {
-                       mail_search_args_simplify_sub(box, args->value.subargs,
-                                                     args->type != SEARCH_OR);
-               }
-
-               /* merge all flags arguments */
-               if (args->type == SEARCH_FLAGS &&
-                   !args->match_not && parent_and) {
-                       if (prev_flags_arg == NULL)
-                               prev_flags_arg = args;
-                       else {
-                               prev_flags_arg->value.flags |=
-                                       args->value.flags;
-                               prev->next = args->next;
-                               args = args->next;
-                               continue;
-                       }
-               } else if (args->type == SEARCH_FLAGS && args->match_not &&
-                          !parent_and) {
-                       if (prev_not_flags_arg == NULL)
-                               prev_not_flags_arg = args;
-                       else {
-                               prev_not_flags_arg->value.flags |=
-                                       args->value.flags;
-                               prev->next = args->next;
-                               args = args->next;
-                               continue;
-                       }
-               }
-
-               prev = args;
-               args = args->next;
-       }
-}
-
-static bool
-mail_search_args_unnest_inthreads(struct mail_search_args *args,
-                                 struct mail_search_arg **argp,
-                                 bool parent_inthreads, bool parent_and)
-{
-       struct mail_search_arg *arg, *thread_arg, *or_arg;
-       bool child_inthreads = FALSE, non_inthreads = FALSE;
-
-       for (arg = *argp; arg != NULL; arg = arg->next) {
-               switch (arg->type) {
-               case SEARCH_SUB:
-               case SEARCH_OR:
-                       if (!mail_search_args_unnest_inthreads(args,
-                                       &arg->value.subargs, parent_inthreads,
-                                       arg->type != SEARCH_OR)) {
-                               arg->result = 1;
-                               child_inthreads = TRUE;
-                       } else {
-                               arg->result = 0;
-                               non_inthreads = TRUE;
-                       }
-                       break;
-               case SEARCH_INTHREAD:
-                       if (mail_search_args_unnest_inthreads(args,
-                                       &arg->value.subargs, TRUE, TRUE)) {
-                               /* children converted to SEARCH_INTHREADs */
-                               arg->type = SEARCH_SUB;
-                       }
-                       args->have_inthreads = TRUE;
-                       arg->result = 1;
-                       child_inthreads = TRUE;
-                       break;
-               default:
-                       arg->result = 0;
-                       non_inthreads = TRUE;
-                       break;
-               }
-       }
-
-       if (!parent_inthreads || !child_inthreads || !non_inthreads)
-               return FALSE;
-
-       /* put all non-INTHREADs under a single INTHREAD */
-       thread_arg = p_new(args->pool, struct mail_search_arg, 1);
-       thread_arg->type = SEARCH_INTHREAD;
-
-       while (*argp != NULL) {
-               arg = *argp;
-               argp = &(*argp)->next;
-
-               if (arg->result == 0) {
-                       /* not an INTHREAD or a SUB/OR with only INTHREADs */
-                       arg->next = thread_arg->value.subargs;
-                       thread_arg->value.subargs = arg;
-               }
-       }
-       if (!parent_and) {
-               /* We want to OR the args */
-               or_arg = p_new(args->pool, struct mail_search_arg, 1);
-               or_arg->type = SEARCH_OR;
-               or_arg->value.subargs = thread_arg->value.subargs;
-               thread_arg->value.subargs = or_arg;
-       }
-       return TRUE;
-}
-
-void mail_search_args_simplify(struct mail_search_args *args)
-{
-       args->simplified = TRUE;
-
-       mail_search_args_simplify_sub(args->box, args->args, TRUE);
-       if (mail_search_args_unnest_inthreads(args, &args->args,
-                                             FALSE, TRUE)) {
-               /* we may have added some extra SUBs that could be dropped */
-               mail_search_args_simplify_sub(args->box, args->args, TRUE);
-       }
-}
-
 static bool mail_search_arg_one_equals(const struct mail_search_arg *arg1,
                                       const struct mail_search_arg *arg2)
 {
diff --git a/src/lib-storage/test-mail-search-args-simplify.c b/src/lib-storage/test-mail-search-args-simplify.c
new file mode 100644 (file)
index 0000000..f148d42
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "test-common.h"
+#include "mail-search-build.h"
+#include "mail-search-parser.h"
+#include "mail-search.h"
+
+struct {
+       const char *input;
+       const char *output;
+} tests[] = {
+       { "TEXT foo", "TEXT foo" },
+       { "( TEXT foo )", "TEXT foo" },
+       { "( ( TEXT foo ) )", "TEXT foo" },
+       { "( ( TEXT foo ) ( TEXT bar ) )", "TEXT foo TEXT bar" },
+
+       { "OR ( TEXT foo ) ( TEXT bar )", "(OR TEXT foo TEXT bar)" },
+       { "OR ( TEXT foo ) OR ( TEXT bar ) ( TEXT baz )",
+         "(OR TEXT foo OR TEXT bar TEXT baz)" },
+       { "OR ( ( TEXT foo TEXT foo2 ) ) ( ( TEXT bar ( TEXT baz ) ) )",
+         "(OR (TEXT foo TEXT foo2) (TEXT bar TEXT baz))" },
+
+       { "NOT ( TEXT foo )", "NOT TEXT foo" },
+       { "NOT ( NOT ( TEXT foo ) )", "TEXT foo" },
+       { "NOT OR ( TEXT foo ) ( TEXT bar )", "NOT TEXT foo NOT TEXT bar" },
+       { "NOT ( OR ( TEXT foo ) ( TEXT bar ) )", "NOT TEXT foo NOT TEXT bar" },
+       { "NOT ( TEXT foo TEXT bar )", "(OR NOT TEXT foo NOT TEXT bar)" },
+
+       { "ANSWERED FLAGGED SEEN", "(ANSWERED FLAGGED SEEN)" },
+       { "ANSWERED TEXT foo FLAGGED SEEN", "(ANSWERED FLAGGED SEEN) TEXT foo" },
+       { "NOT ( ANSWERED FLAGGED SEEN )", "(NOT (ANSWERED FLAGGED SEEN))" },
+       { "OR NOT ANSWERED OR NOT FLAGGED NOT SEEN", "(NOT (ANSWERED FLAGGED SEEN))" }
+};
+
+static struct mail_search_args *
+test_build_search_args(const char *args)
+{
+       struct mail_search_parser *parser;
+       struct mail_search_args *sargs;
+       const char *error, *charset = "UTF-8";
+
+       parser = mail_search_parser_init_cmdline(t_strsplit(args, " "));
+       if (mail_search_build(mail_search_register_get_imap(),
+                             parser, &charset, &sargs, &error) < 0)
+               i_panic("%s", error);
+       mail_search_parser_deinit(&parser);
+       return sargs;
+}
+
+static void test_mail_search_args_simplify(void)
+{
+       struct mail_search_args *args;
+       string_t *str = t_str_new(256);
+       const char *error;
+       unsigned int i;
+
+       test_begin("mail search args simplify");
+       for (i = 0; i < N_ELEMENTS(tests); i++) {
+               args = test_build_search_args(tests[i].input);
+               mail_search_args_simplify(args);
+
+               str_truncate(str, 0);
+               test_assert(mail_search_args_to_imap(str, args->args, &error));
+               test_assert_idx(strcmp(str_c(str), tests[i].output) == 0, i);
+               mail_search_args_unref(&args);
+       }
+       test_end();
+}
+
+int main(void)
+{
+       static void (*test_functions[])(void) = {
+               test_mail_search_args_simplify,
+               NULL
+       };
+
+       return test_run(test_functions);
+}