diff --git a/Makefile.am b/Makefile.am index d20c6ae8a2a1df68b5a14a75d5840dcf1a83ba79..20d85a6df6e72ede71fec39cb3a78b9a4a0cc174 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,12 +42,12 @@ test_cases = \ tests/testsuite.svtest\ tests/control-structures.svtest \ tests/compile/compile.svtest \ - tests/compile/examples.svtest \ tests/compile/errors.svtest \ tests/execute/errors.svtest \ tests/execute/actions.svtest \ tests/execute/smtp.svtest \ tests/execute/mailstore.svtest \ + tests/execute/examples.svtest \ tests/exists.svtest \ tests/header.svtest \ tests/address.svtest \ diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am index 3d60b1216e925fb980ad90b00ba6c2cde3a8da73..be1fb1c6a6e9614a4bb03393af71584489b1f360 100644 --- a/src/testsuite/Makefile.am +++ b/src/testsuite/Makefile.am @@ -32,7 +32,9 @@ commands = \ cmd-test-result-reset.c \ cmd-test-result-print.c \ cmd-test-message.c \ - cmd-test-mailbox.c + cmd-test-mailbox.c \ + cmd-test-binary.c + tests = \ tst-test-script-compile.c \ @@ -52,6 +54,7 @@ testsuite_SOURCES = \ testsuite-result.c \ testsuite-smtp.c \ testsuite-mailstore.c \ + testsuite-binary.c \ $(commands) \ $(tests) \ ext-testsuite.c \ @@ -67,5 +70,6 @@ noinst_HEADERS = \ testsuite-script.h \ testsuite-result.h \ testsuite-smtp.h \ - testsuite-mailstore.h + testsuite-mailstore.h \ + testsuite-binary.h diff --git a/src/testsuite/cmd-test-binary.c b/src/testsuite/cmd-test-binary.c new file mode 100644 index 0000000000000000000000000000000000000000..b72c92388c70a7dada77a33876e41e2dfb3cdd0b --- /dev/null +++ b/src/testsuite/cmd-test-binary.c @@ -0,0 +1,269 @@ +/* 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-binary.h" +#include "testsuite-script.h" + +/* + * Test_binary command + * + * Syntax: + * test_binary ( :load / :save ) <mailbox: string> + */ + +static bool cmd_test_binary_registered + (struct sieve_validator *valdtr, + struct sieve_command_registration *cmd_reg); +static bool cmd_test_binary_validate + (struct sieve_validator *valdtr, struct sieve_command_context *cmd); +static bool cmd_test_binary_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx); + +const struct sieve_command cmd_test_binary = { + "test_binary", + SCT_COMMAND, + 1, 0, FALSE, FALSE, + cmd_test_binary_registered, + NULL, + cmd_test_binary_validate, + cmd_test_binary_generate, + NULL +}; + +/* + * Operations + */ + +static bool cmd_test_binary_operation_dump + (const struct sieve_operation *op, + const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int cmd_test_binary_operation_execute + (const struct sieve_operation *op, + const struct sieve_runtime_env *renv, sieve_size_t *address); + +/* test_binary_create operation */ + +const struct sieve_operation test_binary_load_operation = { + "TEST_BINARY_LOAD", + &testsuite_extension, + TESTSUITE_OPERATION_TEST_BINARY_LOAD, + cmd_test_binary_operation_dump, + cmd_test_binary_operation_execute +}; + +/* test_binary_delete operation */ + +const struct sieve_operation test_binary_save_operation = { + "TEST_BINARY_SAVE", + &testsuite_extension, + TESTSUITE_OPERATION_TEST_BINARY_SAVE, + cmd_test_binary_operation_dump, + cmd_test_binary_operation_execute +}; + +/* + * Compiler context data + */ + +enum test_binary_operation { + BINARY_OP_LOAD, + BINARY_OP_SAVE, + BINARY_OP_LAST +}; + +const struct sieve_operation *test_binary_operations[] = { + &test_binary_load_operation, + &test_binary_save_operation +}; + +struct cmd_test_binary_context_data { + enum test_binary_operation binary_op; + const char *folder; +}; + +/* + * Command tags + */ + +static bool cmd_test_binary_validate_tag + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd); + +static const struct sieve_argument test_binary_load_tag = { + "load", + NULL, NULL, + cmd_test_binary_validate_tag, + NULL, NULL +}; + +static const struct sieve_argument test_binary_save_tag = { + "save", + NULL, NULL, + cmd_test_binary_validate_tag, + NULL, NULL +}; + +static bool cmd_test_binary_registered +(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg) +{ + /* Register our tags */ + sieve_validator_register_tag(valdtr, cmd_reg, &test_binary_load_tag, 0); + sieve_validator_register_tag(valdtr, cmd_reg, &test_binary_save_tag, 0); + + return TRUE; +} + +static bool cmd_test_binary_validate_tag +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd) +{ + struct cmd_test_binary_context_data *ctx_data = + (struct cmd_test_binary_context_data *) cmd->data; + + if ( ctx_data != NULL ) { + sieve_argument_validate_error + (valdtr, *arg, "exactly one of the ':load' or ':save' tags must be " + "specified for the test_binary command, but more were found"); + return NULL; + } + + ctx_data = p_new + (sieve_command_pool(cmd), struct cmd_test_binary_context_data, 1); + cmd->data = ctx_data; + + if ( (*arg)->argument == &test_binary_load_tag ) + ctx_data->binary_op = BINARY_OP_LOAD; + else + ctx_data->binary_op = BINARY_OP_SAVE; + + /* Delete this tag */ + *arg = sieve_ast_arguments_detach(*arg, 1); + + return TRUE; +} + +/* + * Validation + */ + +static bool cmd_test_binary_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_binary command requires either the :load or the :save tag " + "to be specified"); + return FALSE; + } + + if ( !sieve_validate_positional_argument + (valdtr, cmd, arg, "binary-name", 1, SAAT_STRING) ) { + return FALSE; + } + + return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE); +} + +/* + * Code generation + */ + +static bool cmd_test_binary_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command_context *cmd) +{ + struct cmd_test_binary_context_data *ctx_data = + (struct cmd_test_binary_context_data *) cmd->data; + + i_assert( ctx_data->binary_op < BINARY_OP_LAST ); + + /* Emit operation */ + sieve_operation_emit_code(cgenv->sbin, + test_binary_operations[ctx_data->binary_op]); + + /* Generate arguments */ + if ( !sieve_generate_arguments(cgenv, cmd, NULL) ) + return FALSE; + + return TRUE; +} + +/* + * Code dump + */ + +static bool cmd_test_binary_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, "binary-name"); +} + + +/* + * Intepretation + */ + +static int cmd_test_binary_operation_execute +(const struct sieve_operation *op, + const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + string_t *binary_name = NULL; + + /* + * Read operands + */ + + /* Binary Name */ + + if ( !sieve_opr_string_read(renv, address, &binary_name) ) { + 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(binary_name)); + + if ( op == &test_binary_load_operation ) { + struct sieve_binary *sbin = testsuite_binary_load(str_c(binary_name)); + + if ( sbin != NULL ) { + testsuite_script_set_binary(sbin); + + sieve_binary_unref(&sbin); + } else { + sieve_sys_error("failed to load binary %s", str_c(binary_name)); + return SIEVE_EXEC_FAILURE; + } + + } else if ( op == &test_binary_save_operation ) { + struct sieve_binary *sbin = testsuite_script_get_binary(); + + if ( sbin != NULL ) + testsuite_binary_save(sbin, str_c(binary_name)); + else { + sieve_sys_error("no compiled binary to save as %s", str_c(binary_name)); + return SIEVE_EXEC_FAILURE; + } + } + + return SIEVE_EXEC_OK; +} diff --git a/src/testsuite/ext-testsuite.c b/src/testsuite/ext-testsuite.c index cc0ca39cda6de1f8f64ea6ccdd24085516c6e005..e6f07318f7eebcb9368f3faa0b67cc5f5720b4a0 100644 --- a/src/testsuite/ext-testsuite.c +++ b/src/testsuite/ext-testsuite.c @@ -66,7 +66,9 @@ const struct sieve_operation *testsuite_operations[] = { &test_message_smtp_operation, &test_message_mailbox_operation, &test_mailbox_create_operation, - &test_mailbox_delete_operation + &test_mailbox_delete_operation, + &test_binary_load_operation, + &test_binary_save_operation }; /* @@ -116,6 +118,7 @@ static bool ext_testsuite_validator_load(struct sieve_validator *valdtr) 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, &cmd_test_binary); sieve_validator_register_command(valdtr, &tst_test_script_compile); sieve_validator_register_command(valdtr, &tst_test_script_run); diff --git a/src/testsuite/testsuite-binary.c b/src/testsuite/testsuite-binary.c new file mode 100644 index 0000000000000000000000000000000000000000..6bf3ac20713c824b04f3b7348bb826a6bda89c64 --- /dev/null +++ b/src/testsuite/testsuite-binary.c @@ -0,0 +1,74 @@ +/* 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 "sieve.h" +#include "sieve-common.h" +#include "sieve-error.h" + +#include "testsuite-common.h" +#include "testsuite-binary.h" + +#include <sys/stat.h> +#include <sys/types.h> + +/* + * State + */ + +static char *testsuite_binary_tmp = NULL; + +/* + * Initialization + */ + +void testsuite_binary_init(void) +{ + testsuite_binary_tmp = i_strconcat + (testsuite_tmp_dir_get(), "/binaries", NULL); + + if ( mkdir(testsuite_binary_tmp, 0700) < 0 ) { + i_fatal("failed to create temporary directory '%s': %m.", + testsuite_binary_tmp); + } +} + +void testsuite_binary_deinit(void) +{ + if ( unlink_directory(testsuite_binary_tmp, TRUE) < 0 ) { + i_warning("failed to remove temporary directory '%s': %m.", + testsuite_binary_tmp); + } + + i_free(testsuite_binary_tmp); +} + +void testsuite_binary_reset(void) +{ + testsuite_binary_init(); + testsuite_binary_deinit(); +} + +/* + * Binary Access + */ + +bool testsuite_binary_save(struct sieve_binary *sbin, const char *name) +{ + return sieve_save + (sbin, t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name)); +} + +struct sieve_binary *testsuite_binary_load(const char *name) +{ + return sieve_load(t_strdup_printf("%s/%s.svbin", testsuite_binary_tmp, name)); +} + + + diff --git a/src/testsuite/testsuite-binary.h b/src/testsuite/testsuite-binary.h new file mode 100644 index 0000000000000000000000000000000000000000..5a508416ab4f2f9eb496444106a8a8195d74a32e --- /dev/null +++ b/src/testsuite/testsuite-binary.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file + */ + +#ifndef __TESTSUITE_BINARY_H +#define __TESTSUITE_BINARY_H + +#include "sieve-common.h" + +void testsuite_binary_init(void); +void testsuite_binary_deinit(void); +void testsuite_binary_reset(void); + +/* + * Binary Access + */ + +bool testsuite_binary_save(struct sieve_binary *sbin, const char *name); +struct sieve_binary *testsuite_binary_load(const char *name); + +#endif /* __TESTSUITE_BINARY_H */ diff --git a/src/testsuite/testsuite-common.c b/src/testsuite/testsuite-common.c index 03ac3da1fbbd9a74150be8bf449503f0b5b8dd38..1f55aeadbed401e04f67dd6b920566de46f48e73 100644 --- a/src/testsuite/testsuite-common.c +++ b/src/testsuite/testsuite-common.c @@ -232,12 +232,14 @@ void testsuite_init(void) testsuite_tmp_dir_init(); testsuite_script_init(); + testsuite_binary_init(); testsuite_smtp_init(); } void testsuite_deinit(void) { testsuite_smtp_deinit(); + testsuite_binary_deinit(); testsuite_script_deinit(); testsuite_tmp_dir_deinit(); diff --git a/src/testsuite/testsuite-common.h b/src/testsuite/testsuite-common.h index 6351318b551ee20b9362b5ea25a9a8f76fae8aea..2d5022be035b65e511b05d5a042dbbbbaa7ad041 100644 --- a/src/testsuite/testsuite-common.h +++ b/src/testsuite/testsuite-common.h @@ -47,6 +47,7 @@ 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; +extern const struct sieve_command cmd_test_binary; /* * Tests @@ -77,7 +78,9 @@ enum testsuite_operation_code { TESTSUITE_OPERATION_TEST_MESSAGE_SMTP, TESTSUITE_OPERATION_TEST_MESSAGE_MAILBOX, TESTSUITE_OPERATION_TEST_MAILBOX_CREATE, - TESTSUITE_OPERATION_TEST_MAILBOX_DELETE + TESTSUITE_OPERATION_TEST_MAILBOX_DELETE, + TESTSUITE_OPERATION_TEST_BINARY_LOAD, + TESTSUITE_OPERATION_TEST_BINARY_SAVE, }; extern const struct sieve_operation test_operation; @@ -95,6 +98,8 @@ 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; +extern const struct sieve_operation test_binary_load_operation; +extern const struct sieve_operation test_binary_save_operation; /* * Operands diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c index 342807d69ece837772b8efe88eac4dd381b76d0f..49456a5030d64f8dd89146d689e87d3bf4d81b94 100644 --- a/src/testsuite/testsuite-script.c +++ b/src/testsuite/testsuite-script.c @@ -30,7 +30,7 @@ void testsuite_script_init(void) void testsuite_script_deinit(void) { if ( _testsuite_compiled_script != NULL ) { - sieve_close(&_testsuite_compiled_script); + sieve_binary_unref(&_testsuite_compiled_script); } } @@ -56,7 +56,7 @@ bool testsuite_script_compile(const char *script_path) return FALSE; if ( _testsuite_compiled_script != NULL ) { - sieve_close(&_testsuite_compiled_script); + sieve_binary_unref(&_testsuite_compiled_script); } _testsuite_compiled_script = sbin; @@ -108,3 +108,18 @@ bool testsuite_script_run(const struct sieve_runtime_env *renv) return ( ret > 0 ); } +struct sieve_binary *testsuite_script_get_binary(void) +{ + return _testsuite_compiled_script; +} + +void testsuite_script_set_binary(struct sieve_binary *sbin) +{ + if ( _testsuite_compiled_script != NULL ) { + sieve_binary_unref(&_testsuite_compiled_script); + } + + _testsuite_compiled_script = sbin; + sieve_binary_ref(sbin); +} + diff --git a/src/testsuite/testsuite-script.h b/src/testsuite/testsuite-script.h index d26781bf5cd92fbd167d7e3e75762362fa227e54..7ce8992d0005e6677d163048b551adea6b5240b3 100644 --- a/src/testsuite/testsuite-script.h +++ b/src/testsuite/testsuite-script.h @@ -12,4 +12,7 @@ void testsuite_script_deinit(void); bool testsuite_script_compile(const char *script_path); bool testsuite_script_run(const struct sieve_runtime_env *renv); +struct sieve_binary *testsuite_script_get_binary(void); +void testsuite_script_set_binary(struct sieve_binary *sbin); + #endif /* __TESTSUITE_SCRIPT_H */ diff --git a/tests/compile/examples.svtest b/tests/execute/examples.svtest similarity index 56% rename from tests/compile/examples.svtest rename to tests/execute/examples.svtest index 2de85425e3237a2b0393a28d3e5b739972d2f90b..3f0416ab4098b5797fe267e4787afdeae4aa83cb 100644 --- a/tests/compile/examples.svtest +++ b/tests/execute/examples.svtest @@ -1,63 +1,115 @@ require "vnd.dovecot.testsuite"; -# Compile all example scripts +/* Compile and execute all example scripts to trigger + * any Segfaults. No message is set and no results are checked. + */ test "Elvey example" { if not test_script_compile "../../examples/elvey.sieve" { test_fail "could not compile"; } + + test_binary :save "elvey"; + test_binary :load "elvey"; + + if not test_script_run { } } test "M. Johnson example" { if not test_script_compile "../../examples/mjohnson.sieve" { test_fail "could not compile"; } + + test_binary :save "mjohnson"; + test_binary :load "mjohnson"; + + if not test_script_run { } } test "RFC 3028 example" { if not test_script_compile "../../examples/rfc3028.sieve" { test_fail "could not compile"; } + + test_binary :save "rfc3028"; + test_binary :load "rfc3028"; + + if not test_script_run { } } test "Sieve examples" { if not test_script_compile "../../examples/sieve_examples.sieve" { test_fail "could not compile"; } + + test_binary :save "sieve_examples"; + test_binary :load "sieve_examples"; + + if not test_script_run { } } test "Vivil example" { if not test_script_compile "../../examples/vivil.sieve" { test_fail "could not compile"; } + + test_binary :save "vivil"; + test_binary :load "vivil"; + + if not test_script_run { } } test "Jerry example" { if not test_script_compile "../../examples/jerry.sieve" { test_fail "could not compile"; } + + test_binary :save "jerry"; + test_binary :load "jerry"; + + if not test_script_run { } } test "M. Klose example" { if not test_script_compile "../../examples/mklose.sieve" { test_fail "could not compile"; } + + test_binary :save "mklose"; + test_binary :load "mklose"; + + if not test_script_run { } } test "Sanjay example" { if not test_script_compile "../../examples/sanjay.sieve" { test_fail "could not compile"; } + + test_binary :save "sanjay"; + test_binary :load "sanjay"; + + if not test_script_run { } } test "Relational (RFC5231) example" { if not test_script_compile "../../examples/relational.rfc5231.sieve" { test_fail "could not compile"; } + + test_binary :save "relational"; + test_binary :load "relational"; + + if not test_script_run { } } test "Subaddress (RFC5233) example" { if not test_script_compile "../../examples/subaddress.rfc5233.sieve" { test_fail "could not compile"; } + + test_binary :save "subaddress"; + test_binary :load "subaddress"; + + if not test_script_run { } }