diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am index c8bd6f5007d3057a9dbdc4a5d9c49c225f098fe4..73d75e818c9416ca9467498e4837e140c22615fc 100644 --- a/src/testsuite/Makefile.am +++ b/src/testsuite/Makefile.am @@ -31,7 +31,8 @@ commands = \ cmd-test-set.c \ cmd-test-result-reset.c \ cmd-test-result-print.c \ - cmd-test-message.c + cmd-test-message.c \ + cmd-test-mailbox.c tests = \ tst-test-script-compile.c \ @@ -50,6 +51,7 @@ testsuite_SOURCES = \ testsuite-script.c \ testsuite-result.c \ testsuite-smtp.c \ + testsuite-mailstore.c \ $(commands) \ $(tests) \ ext-testsuite.c \ diff --git a/src/testsuite/cmd-test-mailbox.c b/src/testsuite/cmd-test-mailbox.c new file mode 100644 index 0000000000000000000000000000000000000000..f1ad7e12d0c9118773b989ef9d94a026a9ab523d --- /dev/null +++ b/src/testsuite/cmd-test-mailbox.c @@ -0,0 +1,248 @@ +/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file + */ + +#include "sieve-common.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-code.h" +#include "sieve-binary.h" +#include "sieve-dump.h" + +#include "testsuite-common.h" +#include "testsuite-mailstore.h" + +/* + * Test_mailbox command + * + * Syntax: + * test_mailbox ( :create / :delete ) <mailbox: string> + */ + +static bool cmd_test_mailbox_registered + (struct sieve_validator *valdtr, + struct sieve_command_registration *cmd_reg); +static bool cmd_test_mailbox_validate + (struct sieve_validator *valdtr, struct sieve_command_context *cmd); +static bool cmd_test_mailbox_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx); + +const struct sieve_command cmd_test_mailbox = { + "test_mailbox", + SCT_COMMAND, + 1, 0, FALSE, FALSE, + cmd_test_mailbox_registered, + NULL, + cmd_test_mailbox_validate, + cmd_test_mailbox_generate, + NULL +}; + +/* + * Operations + */ + +static bool cmd_test_mailbox_operation_dump + (const struct sieve_operation *op, + const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int cmd_test_mailbox_operation_execute + (const struct sieve_operation *op, + const struct sieve_runtime_env *renv, sieve_size_t *address); + +/* Test_mailbox_create operation */ + +const struct sieve_operation test_mailbox_create_operation = { + "TEST_MAILBOX_CREATE", + &testsuite_extension, + TESTSUITE_OPERATION_TEST_MAILBOX_CREATE, + cmd_test_mailbox_operation_dump, + cmd_test_mailbox_operation_execute +}; + +/* Test_mailbox_delete operation */ + +const struct sieve_operation test_mailbox_delete_operation = { + "TEST_MAILBOX_DELETE", + &testsuite_extension, + TESTSUITE_OPERATION_TEST_MAILBOX_DELETE, + cmd_test_mailbox_operation_dump, + cmd_test_mailbox_operation_execute +}; + +/* + * Compiler context data + */ + +enum test_mailbox_operation { + MAILBOX_OP_CREATE, + MAILBOX_OP_DELETE, + MAILBOX_OP_LAST +}; + +const struct sieve_operation *test_mailbox_operations[] = { + &test_mailbox_create_operation, + &test_mailbox_delete_operation +}; + +struct cmd_test_mailbox_context_data { + enum test_mailbox_operation mailbox_op; + const char *folder; +}; + +/* + * Command tags + */ + +static bool cmd_test_mailbox_validate_tag + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd); + +static const struct sieve_argument test_mailbox_create_tag = { + "create", + NULL, NULL, + cmd_test_mailbox_validate_tag, + NULL, NULL +}; + +static const struct sieve_argument test_mailbox_delete_tag = { + "delete", + NULL, NULL, + cmd_test_mailbox_validate_tag, + NULL, NULL +}; + +static bool cmd_test_mailbox_registered +(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg) +{ + /* Register our tags */ + sieve_validator_register_tag(valdtr, cmd_reg, &test_mailbox_create_tag, 0); + sieve_validator_register_tag(valdtr, cmd_reg, &test_mailbox_delete_tag, 0); + + return TRUE; +} + +static bool cmd_test_mailbox_validate_tag +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd) +{ + struct cmd_test_mailbox_context_data *ctx_data = + (struct cmd_test_mailbox_context_data *) cmd->data; + + if ( ctx_data != NULL ) { + sieve_argument_validate_error + (valdtr, *arg, "exactly one of the ':create' or ':delete' tags must be " + "specified for the test_mailbox command, but more were found"); + return NULL; + } + + ctx_data = p_new + (sieve_command_pool(cmd), struct cmd_test_mailbox_context_data, 1); + cmd->data = ctx_data; + + if ( (*arg)->argument == &test_mailbox_create_tag ) + ctx_data->mailbox_op = MAILBOX_OP_CREATE; + else + ctx_data->mailbox_op = MAILBOX_OP_DELETE; + + /* Delete this tag */ + *arg = sieve_ast_arguments_detach(*arg, 1); + + return TRUE; +} + +/* + * Validation + */ + +static bool cmd_test_mailbox_validate +(struct sieve_validator *valdtr, struct sieve_command_context *cmd) +{ + struct sieve_ast_argument *arg = cmd->first_positional; + + if ( cmd->data == NULL ) { + sieve_command_validate_error(valdtr, cmd, + "the test_mailbox command requires either the :create or the :delete tag " + "to be specified"); + return FALSE; + } + + if ( !sieve_validate_positional_argument + (valdtr, cmd, arg, "mailbox", 1, SAAT_STRING) ) { + return FALSE; + } + + return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE); +} + +/* + * Code generation + */ + +static bool cmd_test_mailbox_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command_context *cmd) +{ + struct cmd_test_mailbox_context_data *ctx_data = + (struct cmd_test_mailbox_context_data *) cmd->data; + + i_assert( ctx_data->mailbox_op < MAILBOX_OP_LAST ); + + /* Emit operation */ + sieve_operation_emit_code(cgenv->sbin, + test_mailbox_operations[ctx_data->mailbox_op]); + + /* Generate arguments */ + if ( !sieve_generate_arguments(cgenv, cmd, NULL) ) + return FALSE; + + return TRUE; +} + +/* + * Code dump + */ + +static bool cmd_test_mailbox_operation_dump +(const struct sieve_operation *op, + const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + sieve_code_dumpf(denv, "%s:", op->mnemonic); + + sieve_code_descend(denv); + + return sieve_opr_string_dump(denv, address, "mailbox"); +} + + +/* + * Intepretation + */ + +static int cmd_test_mailbox_operation_execute +(const struct sieve_operation *op, + const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + string_t *mailbox = NULL; + + /* + * Read operands + */ + + /* Index */ + + if ( !sieve_opr_string_read(renv, address, &mailbox) ) { + sieve_runtime_trace_error(renv, "invalid mailbox operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + /* + * Perform operation + */ + + sieve_runtime_trace(renv, "%s %s:", op->mnemonic, str_c(mailbox)); + + if ( op == &test_mailbox_create_operation ) + testsuite_mailstore_mailbox_create(renv, str_c(mailbox)); + + return SIEVE_EXEC_OK; +} diff --git a/src/testsuite/ext-testsuite.c b/src/testsuite/ext-testsuite.c index 26baec85c81f5b6eb80cad4ba85899272e206bec..cc0ca39cda6de1f8f64ea6ccdd24085516c6e005 100644 --- a/src/testsuite/ext-testsuite.c +++ b/src/testsuite/ext-testsuite.c @@ -64,7 +64,9 @@ const struct sieve_operation *testsuite_operations[] = { &test_result_reset_operation, &test_result_print_operation, &test_message_smtp_operation, - &test_message_mailbox_operation + &test_message_mailbox_operation, + &test_mailbox_create_operation, + &test_mailbox_delete_operation }; /* @@ -113,6 +115,7 @@ static bool ext_testsuite_validator_load(struct sieve_validator *valdtr) sieve_validator_register_command(valdtr, &cmd_test_result_print); sieve_validator_register_command(valdtr, &cmd_test_result_reset); sieve_validator_register_command(valdtr, &cmd_test_message); + sieve_validator_register_command(valdtr, &cmd_test_mailbox); sieve_validator_register_command(valdtr, &tst_test_script_compile); sieve_validator_register_command(valdtr, &tst_test_script_run); diff --git a/src/testsuite/testsuite-common.h b/src/testsuite/testsuite-common.h index f9caed1744ae7b6c0dfc2052ac01b0f97afa041e..6351318b551ee20b9362b5ea25a9a8f76fae8aea 100644 --- a/src/testsuite/testsuite-common.h +++ b/src/testsuite/testsuite-common.h @@ -46,6 +46,7 @@ extern const struct sieve_command cmd_test_set; extern const struct sieve_command cmd_test_result_reset; extern const struct sieve_command cmd_test_result_print; extern const struct sieve_command cmd_test_message; +extern const struct sieve_command cmd_test_mailbox; /* * Tests @@ -74,7 +75,9 @@ enum testsuite_operation_code { TESTSUITE_OPERATION_TEST_RESULT_RESET, TESTSUITE_OPERATION_TEST_RESULT_PRINT, TESTSUITE_OPERATION_TEST_MESSAGE_SMTP, - TESTSUITE_OPERATION_TEST_MESSAGE_MAILBOX + TESTSUITE_OPERATION_TEST_MESSAGE_MAILBOX, + TESTSUITE_OPERATION_TEST_MAILBOX_CREATE, + TESTSUITE_OPERATION_TEST_MAILBOX_DELETE }; extern const struct sieve_operation test_operation; @@ -90,6 +93,8 @@ extern const struct sieve_operation test_result_reset_operation; extern const struct sieve_operation test_result_print_operation; extern const struct sieve_operation test_message_smtp_operation; extern const struct sieve_operation test_message_mailbox_operation; +extern const struct sieve_operation test_mailbox_create_operation; +extern const struct sieve_operation test_mailbox_delete_operation; /* * Operands diff --git a/src/testsuite/testsuite-mailstore.c b/src/testsuite/testsuite-mailstore.c new file mode 100644 index 0000000000000000000000000000000000000000..4882a9f8808e88bb818439f3fc0c86ec44a7a9ad --- /dev/null +++ b/src/testsuite/testsuite-mailstore.c @@ -0,0 +1,201 @@ +/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file + */ + +#include "lib.h" +#include "mempool.h" +#include "imem.h" +#include "array.h" +#include "strfuncs.h" +#include "unlink-directory.h" +#include "env-util.h" +#include "mail-namespace.h" +#include "mail-storage.h" + +#include "sieve-common.h" +#include "sieve-error.h" +#include "sieve-interpreter.h" + +#include "testsuite-message.h" +#include "testsuite-common.h" +#include "testsuite-smtp.h" + +#include "testsuite-mailstore.h" + +#include <sys/stat.h> +#include <sys/types.h> + +/* + * Forward declarations + */ + +static void testsuite_mailstore_close(void); + +/* + * State + */ + +static char *testsuite_mailstore_tmp = NULL; +static struct mail_user *testsuite_mailstore_user = NULL; + +static char *testsuite_mailstore_folder = NULL; +static struct mailbox *testsuite_mailstore_box = NULL; +static struct mailbox_transaction_context *testsuite_mailstore_trans = NULL; +static struct mail *testsuite_mailstore_mail = NULL; + +/* + * Initialization + */ + +void testsuite_mailstore_init +(const char *user, const char *home, struct mail_user *service_user) +{ + struct mail_namespace_settings ns_set; + struct mail_namespace *ns = NULL; + struct mail_user *mail_user; + const char *errstr; + + testsuite_mailstore_tmp = i_strconcat + (testsuite_tmp_dir_get(), "/mailstore", NULL); + + if ( mkdir(testsuite_mailstore_tmp, 0700) < 0 ) { + i_fatal("failed to create temporary directory '%s': %m.", + testsuite_mailstore_tmp); + } + + mail_user = mail_user_alloc(user, service_user->unexpanded_set); + mail_user_set_home(mail_user, home); + + if (mail_user_init(mail_user, &errstr) < 0) + i_fatal("Test user initialization failed: %s", errstr); + + memset(&ns_set, 0, sizeof(ns_set)); + ns_set.location = t_strconcat("maildir:", testsuite_mailstore_tmp, NULL); + //ns_set.inbox = TRUE; + //ns_set.separator = "."; + //ns_set.subscriptions = TRUE; + + ns = mail_namespaces_init_empty(mail_user); + ns->flags |= NAMESPACE_FLAG_NOQUOTA | NAMESPACE_FLAG_NOACL; + ns->set = &ns_set; + + testsuite_mailstore_user = mail_user; +} + +void testsuite_mailstore_deinit(void) +{ + testsuite_mailstore_close(); + + /* De-initialize mail user object */ + if ( testsuite_mailstore_user != NULL ) + mail_user_unref(&testsuite_mailstore_user); + + if ( unlink_directory(testsuite_mailstore_tmp, TRUE) < 0 ) { + i_warning("failed to remove temporary directory '%s': %m.", + testsuite_mailstore_tmp); + } + + i_free(testsuite_mailstore_tmp); +} + +void testsuite_mailstore_reset(void) +{ +} + +/* + * Mailbox Access + */ + +struct mail_namespace *testsuite_mailstore_get_namespace(void) +{ + return testsuite_mailstore_user->namespaces; +} + +bool testsuite_mailstore_mailbox_create +(const struct sieve_runtime_env *renv ATTR_UNUSED, const char *folder) +{ + struct mail_namespace *ns = testsuite_mailstore_user->namespaces; + struct mailbox *box; + + box = mailbox_alloc(ns->list, folder, NULL, 0); + + if ( mailbox_create(box, NULL, FALSE) < 0 ) { + mailbox_close(&box); + return FALSE; + } + + mailbox_close(&box); + + return TRUE; +} + +static void testsuite_mailstore_close(void) +{ + if ( testsuite_mailstore_mail != NULL ) + mail_free(&testsuite_mailstore_mail); + + if ( testsuite_mailstore_trans != NULL ) + mailbox_transaction_rollback(&testsuite_mailstore_trans); + + if ( testsuite_mailstore_box != NULL ) + mailbox_close(&testsuite_mailstore_box); + + if ( testsuite_mailstore_folder != NULL ) + i_free(testsuite_mailstore_folder); +} + +static struct mail *testsuite_mailstore_open(const char *folder) +{ + enum mailbox_flags flags = + MAILBOX_FLAG_KEEP_RECENT | MAILBOX_FLAG_SAVEONLY | + MAILBOX_FLAG_POST_SESSION; + struct mail_namespace *ns = testsuite_mailstore_user->namespaces; + struct mailbox *box; + struct mailbox_transaction_context *t; + + if ( testsuite_mailstore_mail == NULL ) { + testsuite_mailstore_close(); + } else if ( testsuite_mailstore_folder != NULL + && strcmp(folder, testsuite_mailstore_folder) != 0 ) { + testsuite_mailstore_close(); + } else { + return testsuite_mailstore_mail; + } + + box = mailbox_alloc(ns->list, folder, NULL, flags); + if ( mailbox_open(box) < 0 ) { + sieve_sys_error("testsuite: failed to open mailbox '%s'", folder); + return NULL; + } + + /* Sync mailbox */ + + if ( mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ, 0, NULL) < 0 ) { + sieve_sys_error("testsuite: failed to sync mailbox '%s'", folder); + return NULL; + } + + /* Start transaction */ + + t = mailbox_transaction_begin(box, 0); + + testsuite_mailstore_folder = i_strdup(folder); + testsuite_mailstore_box = box; + testsuite_mailstore_trans = t; + testsuite_mailstore_mail = mail_alloc(t, 0, NULL); + + return testsuite_mailstore_mail; +} + +bool testsuite_mailstore_mail_index +(const struct sieve_runtime_env *renv, const char *folder, unsigned int index) +{ + struct mail *mail = testsuite_mailstore_open(folder); + + if ( mail == NULL ) + return FALSE; + + mail_set_seq(mail, index); + testsuite_message_set_mail(renv, mail); + + return TRUE; +} diff --git a/src/testsuite/testsuite-mailstore.h b/src/testsuite/testsuite-mailstore.h new file mode 100644 index 0000000000000000000000000000000000000000..d1036acc1ca7397959dfb6edc277c9443e94fb31 --- /dev/null +++ b/src/testsuite/testsuite-mailstore.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file + */ + +#ifndef __TESTSUITE_MAILSTORE_H +#define __TESTSUITE_MAILSTORE_H + +#include "lib.h" +#include "mail-storage.h" + +#include "sieve-common.h" + +/* + * Initialization + */ + +void testsuite_mailstore_init + (const char *user, const char *home, struct mail_user *service_user); +void testsuite_mailstore_deinit(void); +void testsuite_mailstore_reset(void); + +/* + * Namespace + */ + +struct mail_namespace *testsuite_mailstore_get_namespace(void); + +/* + * Mailbox Access + */ + +bool testsuite_mailstore_mailbox_create + (const struct sieve_runtime_env *renv ATTR_UNUSED, const char *folder); + +bool testsuite_mailstore_mail_index + (const struct sieve_runtime_env *renv, const char *folder, + unsigned int index); + +#endif /* __TESTSUITE_MAILSTORE */ diff --git a/src/testsuite/testsuite-message.c b/src/testsuite/testsuite-message.c index 4fd4b0bcea63db0258a130a49ec74ee7a5c3a86c..e704c59d642f4944ca3e65ae194234fcd1e928d4 100644 --- a/src/testsuite/testsuite-message.c +++ b/src/testsuite/testsuite-message.c @@ -111,6 +111,14 @@ void testsuite_message_set_file sieve_message_context_flush(renv->msgctx); } + +void testsuite_message_set_mail +(const struct sieve_runtime_env *renv, struct mail *mail) +{ + _testsuite_message_set_data(mail); + + sieve_message_context_flush(renv->msgctx); +} void testsuite_message_deinit(void) { diff --git a/src/testsuite/testsuite-message.h b/src/testsuite/testsuite-message.h index bb89a93b95f79c82336ffcd889ef1ebd7e64cfc7..8862bda095ea937a37247f508dfea27da4dc2660 100644 --- a/src/testsuite/testsuite-message.h +++ b/src/testsuite/testsuite-message.h @@ -19,6 +19,8 @@ void testsuite_message_set_string (const struct sieve_runtime_env *renv, string_t *message); void testsuite_message_set_file (const struct sieve_runtime_env *renv, const char *file_path); +void testsuite_message_set_mail + (const struct sieve_runtime_env *renv, struct mail *mail); void testsuite_envelope_set_sender (const struct sieve_runtime_env *renv, const char *value); diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c index edc08bb4c92cb8e6f9161244d8801d5a1a83f45c..869dfff0c35a10b4bcac02d92166a064868234ee 100644 --- a/src/testsuite/testsuite.c +++ b/src/testsuite/testsuite.c @@ -27,6 +27,7 @@ #include "testsuite-result.h" #include "testsuite-message.h" #include "testsuite-smtp.h" +#include "testsuite-mailstore.h" #include <stdio.h> #include <stdlib.h> @@ -129,17 +130,15 @@ int main(int argc, char **argv) bool trace = FALSE; int ret; - service = master_service_init("testsuite", - MASTER_SERVICE_FLAG_STANDALONE, - argc, argv); + service = master_service_init + ("testsuite", MASTER_SERVICE_FLAG_STANDALONE, argc, argv); - user = getenv("USER"); + user = getenv("USER"); /* Parse arguments */ scriptfile = dumpfile = extensions = NULL; - getopt_str = t_strconcat("d:x:t", - master_service_getopt_string(), NULL); + getopt_str = t_strconcat("d:x:t", master_service_getopt_string(), NULL); while ((c = getopt(argc, argv, getopt_str)) > 0) { switch (c) { case 'd': @@ -171,9 +170,9 @@ int main(int argc, char **argv) } if (optind != argc) { - print_help(); - i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]); - } + print_help(); + i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]); + } /* Initialize testsuite */ testsuite_tool_init(extensions); @@ -194,30 +193,35 @@ int main(int argc, char **argv) /* Compile sieve script */ if ( (sbin = sieve_tool_script_compile(scriptfile, NULL)) != NULL ) { struct sieve_error_handler *ehandler; - struct mail_storage_service_input input; + struct mail_storage_service_input input; struct sieve_script_env scriptenv; - struct mail_user *mail_user; + struct mail_user *mail_user_dovecot; + const char *home; /* Dump script */ sieve_tool_dump_binary_to(sbin, dumpfile); /* Initialize mail user */ + home = _get_cwd(); user = sieve_tool_get_user(); env_put("DOVECONF_ENV=1"); - env_put(t_strdup_printf("HOME=%s", _get_cwd())); + env_put(t_strdup_printf("HOME=%s", home)); env_put(t_strdup_printf("MAIL=maildir:/tmp/dovecot-test-%s", user)); - memset(&input, 0, sizeof(input)); - input.username = user; - mail_user = mail_storage_service_init_user + memset(&input, 0, sizeof(input)); + input.username = user; + mail_user_dovecot = mail_storage_service_init_user (service, &input, NULL, service_flags); + testsuite_mailstore_init(user, home, mail_user_dovecot); + if (master_service_set(service, "mail_full_filesystem_access=yes") < 0) i_unreached(); - testsuite_message_init(service, user, mail_user); + testsuite_message_init(service, user, mail_user_dovecot); memset(&scriptenv, 0, sizeof(scriptenv)); + scriptenv.namespaces = testsuite_mailstore_get_namespace(); scriptenv.default_mailbox = "INBOX"; scriptenv.hostname = "testsuite.example.com"; scriptenv.postmaster_address = "postmaster@example.com"; @@ -256,13 +260,14 @@ int main(int argc, char **argv) /* De-initialize message environment */ testsuite_message_deinit(); + testsuite_mailstore_deinit(); testsuite_result_deinit(); /* De-initialize mail user */ - if ( mail_user != NULL ) - mail_user_unref(&mail_user); + if ( mail_user_dovecot != NULL ) + mail_user_unref(&mail_user_dovecot); - mail_storage_service_deinit_user(); + mail_storage_service_deinit_user(); } else { testsuite_testcase_fail("failed to compile testcase script"); } diff --git a/tests/execute/actions.svtest b/tests/execute/actions.svtest index 51c7df173da3e924ce3cede29e22b4fcdca803de..576ffb456d12e6b5f413af872114adacd1b0c3e7 100644 --- a/tests/execute/actions.svtest +++ b/tests/execute/actions.svtest @@ -11,6 +11,9 @@ Test. . ; +test_mailbox :create "INBOX.VB"; +test_mailbox :create "INBOX.backup"; + test "Fileinto" { if not test_script_compile "actions/fileinto.sieve" { test_fail "script compile failed"; diff --git a/tests/extensions/imap4flags/execute.svtest b/tests/extensions/imap4flags/execute.svtest index dac5c763bbfcd79edeea51ccf99dbcbbd93d77fe..ca065ce45ead1d133f98e0920b9fa0375f5cfdcb 100644 --- a/tests/extensions/imap4flags/execute.svtest +++ b/tests/extensions/imap4flags/execute.svtest @@ -4,6 +4,9 @@ require "vnd.dovecot.testsuite"; * Execution testing (currently just meant to trigger any segfaults) */ +test_mailbox :create "INBOX.Junk"; +test_mailbox :create "INBOX.Nonsense"; + test "Flags Side Effect" { if not test_script_compile "execute/flags-side-effect.sieve" { test_fail "script compile failed";