From 3285d7b9f820093473c72c6497e34291fa335191 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 2 Jan 2009 14:51:03 +0100
Subject: [PATCH] Testsuite: added multiscript tests and required support.

---
 Makefile.am                                   |   3 +-
 src/lib-sieve/ext-reject.c                    |   4 +-
 src/lib-sieve/plugins/vacation/cmd-vacation.c |   2 +-
 src/testsuite/Makefile.am                     |   3 +-
 src/testsuite/cmd-test-result-print.c         |  82 +++++++++++++
 src/testsuite/ext-testsuite.c                 |   4 +-
 src/testsuite/testsuite-common.h              |   3 +
 src/testsuite/testsuite-log.c                 |   2 +-
 src/testsuite/testsuite-result.c              |  26 +++-
 src/testsuite/testsuite-result.h              |   7 +-
 src/testsuite/tst-test-result-execute.c       |   2 +-
 src/testsuite/tst-test-script-compile.c       |   4 +-
 src/testsuite/tst-test-script-run.c           | 114 +++++++++++++++++-
 tests/multiscript/basic.svtest                |  91 ++++++++++++++
 tests/multiscript/conflicts.svtest            |  51 ++++++++
 tests/multiscript/fileinto-inbox.sieve        |   4 +
 tests/multiscript/notify.sieve                |   3 +
 tests/multiscript/reject-1.sieve              |   3 +
 tests/multiscript/reject-2.sieve              |   3 +
 tests/multiscript/vacation.sieve              |   3 +
 20 files changed, 396 insertions(+), 18 deletions(-)
 create mode 100644 src/testsuite/cmd-test-result-print.c
 create mode 100644 tests/multiscript/basic.svtest
 create mode 100644 tests/multiscript/conflicts.svtest
 create mode 100644 tests/multiscript/fileinto-inbox.sieve
 create mode 100644 tests/multiscript/notify.sieve
 create mode 100644 tests/multiscript/reject-1.sieve
 create mode 100644 tests/multiscript/reject-2.sieve
 create mode 100644 tests/multiscript/vacation.sieve

diff --git a/Makefile.am b/Makefile.am
index f969e5fab..c9638a16a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -76,7 +76,8 @@ test_cases = \
 	tests/extensions/enotify/valid_notify_method.svtest \
 	tests/extensions/enotify/notify_method_capability.svtest \
 	tests/extensions/enotify/errors.svtest \
-	tests/extensions/enotify/execute.svtest
+	tests/extensions/enotify/execute.svtest \
+	tests/multiscript/basic.svtest
 
 if HAVE_DOVECOT_LIBS
 
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 8f05591ab..ce8305b8a 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -271,7 +271,7 @@ int act_reject_check_conflict
 	if ( (act_other->action->flags & SIEVE_ACTFLAG_TRIES_DELIVER) > 0 ) {
 		if ( !act_other->executed ) {
 			sieve_runtime_error(renv, act->location, 
-			"reject action conflicts with earlier triggered action: "
+			"reject action conflicts with other action: "
 			"the %s action (%s) tries to deliver the message",
 			act_other->action->name, act_other->location);	
 			return -1;
@@ -283,7 +283,7 @@ int act_reject_check_conflict
 	if ( (act_other->action->flags & SIEVE_ACTFLAG_SENDS_RESPONSE) > 0 ) {
 		if ( !act_other->executed ) {
 			sieve_runtime_error(renv, act->location, 
-				"reject action conflicts with earlier triggered action: "
+				"reject action conflicts with other action: "
 				"the %s action (%s) also sends a response to the sender",
 				act_other->action->name, act_other->location);	
 			return -1;
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index 85e271a49..a1d23da55 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -704,7 +704,7 @@ int act_vacation_check_conflict
 	if ( (act_other->action->flags & SIEVE_ACTFLAG_SENDS_RESPONSE) > 0 ) {
 		if ( !act_other->executed ) {
 			sieve_runtime_error(renv, act->location, 
-				"vacation action conflicts with earlier triggered action: "
+				"vacation action conflicts with other action: "
 				"the %s action (%s) also sends a response back to the sender",	
 				act_other->action->name, act_other->location);
 			return -1;
diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am
index 284efb282..dbb872765 100644
--- a/src/testsuite/Makefile.am
+++ b/src/testsuite/Makefile.am
@@ -36,7 +36,8 @@ testsuite_DEPENDENCIES = $(libs)
 commands = \
 	cmd-test.c \
 	cmd-test-fail.c \
-	cmd-test-set.c
+	cmd-test-set.c \
+	cmd-test-result-print.c
 
 tests = \
 	tst-test-script-compile.c \
diff --git a/src/testsuite/cmd-test-result-print.c b/src/testsuite/cmd-test-result-print.c
new file mode 100644
index 000000000..c05a82db8
--- /dev/null
+++ b/src/testsuite/cmd-test-result-print.c
@@ -0,0 +1,82 @@
+/* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-script.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 "sieve.h"
+
+#include "testsuite-common.h"
+#include "testsuite-result.h"
+
+/*
+ * Test_result_execute command
+ *
+ * Syntax:   
+ *   test_result_execute
+ */
+
+static bool cmd_test_result_print_generate
+	(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx);
+
+const struct sieve_command cmd_test_result_print = { 
+	"test_result_print", 
+	SCT_COMMAND, 
+	0, 0, FALSE, FALSE,
+	NULL, NULL, NULL,
+	cmd_test_result_print_generate, 
+	NULL 
+};
+
+/* 
+ * Operation 
+ */
+
+static int cmd_test_result_print_operation_execute
+	(const struct sieve_operation *op, 
+		const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+const struct sieve_operation test_result_print_operation = { 
+	"TEST_RESULT_PRINT",
+	&testsuite_extension, 
+	TESTSUITE_OPERATION_TEST_RESULT_PRINT,
+	NULL, 
+	cmd_test_result_print_operation_execute 
+};
+
+/* 
+ * Code generation 
+ */
+
+static bool cmd_test_result_print_generate
+(const struct sieve_codegen_env *cgenv, 
+	struct sieve_command_context *tst ATTR_UNUSED)
+{
+	sieve_operation_emit_code(cgenv->sbin, &test_result_print_operation);
+
+	return TRUE;
+}
+
+/*
+ * Intepretation
+ */
+
+static int cmd_test_result_print_operation_execute
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_runtime_env *renv, 
+	sieve_size_t *address ATTR_UNUSED)
+{
+	testsuite_result_print(renv);
+
+	return SIEVE_EXEC_OK;
+}
+
+
+
+
diff --git a/src/testsuite/ext-testsuite.c b/src/testsuite/ext-testsuite.c
index 47b5f2140..ea4006aa1 100644
--- a/src/testsuite/ext-testsuite.c
+++ b/src/testsuite/ext-testsuite.c
@@ -60,7 +60,8 @@ const struct sieve_operation *testsuite_operations[] = {
 	&test_script_run_operation,
 	&test_error_operation,
 	&test_result_operation,
-	&test_result_execute_operation
+	&test_result_execute_operation,
+	&test_result_print_operation
 };
 
 /* 
@@ -106,6 +107,7 @@ static bool ext_testsuite_validator_load(struct sieve_validator *valdtr)
 	sieve_validator_register_command(valdtr, &cmd_test);
 	sieve_validator_register_command(valdtr, &cmd_test_fail);
 	sieve_validator_register_command(valdtr, &cmd_test_set);
+	sieve_validator_register_command(valdtr, &cmd_test_result_print);
 
 	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 0ee51adbd..2c5beb0df 100644
--- a/src/testsuite/testsuite-common.h
+++ b/src/testsuite/testsuite-common.h
@@ -55,6 +55,7 @@ bool testsuite_generator_context_initialize(struct sieve_generator *gentr);
 extern const struct sieve_command cmd_test;
 extern const struct sieve_command cmd_test_fail;
 extern const struct sieve_command cmd_test_set;
+extern const struct sieve_command cmd_test_result_print;
 
 /*
  * Tests
@@ -80,6 +81,7 @@ enum testsuite_operation_code {
 	TESTSUITE_OPERATION_TEST_ERROR,
 	TESTSUITE_OPERATION_TEST_RESULT,
 	TESTSUITE_OPERATION_TEST_RESULT_EXECUTE,
+	TESTSUITE_OPERATION_TEST_RESULT_PRINT,
 };
 
 extern const struct sieve_operation test_operation;
@@ -91,6 +93,7 @@ extern const struct sieve_operation test_script_run_operation;
 extern const struct sieve_operation test_error_operation;
 extern const struct sieve_operation test_result_operation;
 extern const struct sieve_operation test_result_execute_operation;
+extern const struct sieve_operation test_result_print_operation;
 
 /* 
  * Operands 
diff --git a/src/testsuite/testsuite-log.c b/src/testsuite/testsuite-log.c
index 92c9b4a81..e36e6e63a 100644
--- a/src/testsuite/testsuite-log.c
+++ b/src/testsuite/testsuite-log.c
@@ -17,7 +17,7 @@ struct _testsuite_log_message {
 	const char *message;
 };
 
-bool _testsuite_log_stdout = TRUE;
+bool _testsuite_log_stdout = FALSE;
 
 unsigned int _testsuite_log_error_index = 0;
 
diff --git a/src/testsuite/testsuite-result.c b/src/testsuite/testsuite-result.c
index b9873b5eb..5fb8a433d 100644
--- a/src/testsuite/testsuite-result.c
+++ b/src/testsuite/testsuite-result.c
@@ -1,6 +1,9 @@
 /* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file
  */
 
+#include "lib.h"
+#include "ostream.h"
+
 #include "sieve-common.h"
 #include "sieve-error.h"
 #include "sieve-actions.h"
@@ -15,7 +18,7 @@ static struct sieve_result *_testsuite_result;
 
 void testsuite_result_init(void)
 {
-	_testsuite_result = NULL;
+	_testsuite_result = sieve_result_create(testsuite_log_ehandler);
 }
 
 void testsuite_result_deinit(void)
@@ -25,13 +28,18 @@ void testsuite_result_deinit(void)
 	}
 }
 
-void testsuite_result_assign(struct sieve_result *result)
+void testsuite_result_reset(void)
 {
 	if ( _testsuite_result != NULL ) {
 		sieve_result_unref(&_testsuite_result);
 	}
 
-	_testsuite_result = result;
+	_testsuite_result = sieve_result_create(testsuite_log_ehandler);;
+}
+
+struct sieve_result *testsuite_result_get(void)
+{
+	return _testsuite_result;
 }
 
 struct sieve_result_iterate_context *testsuite_result_iterate_init(void)
@@ -75,4 +83,16 @@ bool testsuite_result_execute(const struct sieve_runtime_env *renv)
 	return ( ret > 0 );
 }
 
+void testsuite_result_print
+(const struct sieve_runtime_env *renv ATTR_UNUSED)
+{
+	struct ostream *out;
+	
+	out = o_stream_create_fd(1, 0, FALSE);	
+
+	sieve_result_print(_testsuite_result, out);
+
+	o_stream_destroy(&out);	
+}
+
 
diff --git a/src/testsuite/testsuite-result.h b/src/testsuite/testsuite-result.h
index ab21d0f34..b9b146523 100644
--- a/src/testsuite/testsuite-result.h
+++ b/src/testsuite/testsuite-result.h
@@ -7,10 +7,15 @@
 void testsuite_result_init(void);
 void testsuite_result_deinit(void);
 
-void testsuite_result_assign(struct sieve_result *result);
+void testsuite_result_reset(void);
+
+struct sieve_result *testsuite_result_get(void);
 
 struct sieve_result_iterate_context *testsuite_result_iterate_init(void);
 
 bool testsuite_result_execute(const struct sieve_runtime_env *renv);
 
+void testsuite_result_print
+	(const struct sieve_runtime_env *renv ATTR_UNUSED);
+
 #endif /* __TESTSUITE_RESULT_H */
diff --git a/src/testsuite/tst-test-result-execute.c b/src/testsuite/tst-test-result-execute.c
index 1ccd9b238..bf28203cd 100644
--- a/src/testsuite/tst-test-result-execute.c
+++ b/src/testsuite/tst-test-result-execute.c
@@ -43,7 +43,7 @@ static int tst_test_result_execute_operation_execute
 		const struct sieve_runtime_env *renv, sieve_size_t *address);
 
 const struct sieve_operation test_result_execute_operation = { 
-	"test_result_execute",
+	"TEST_RESULT_EXECUTE",
 	&testsuite_extension, 
 	TESTSUITE_OPERATION_TEST_RESULT_EXECUTE,
 	NULL, 
diff --git a/src/testsuite/tst-test-script-compile.c b/src/testsuite/tst-test-script-compile.c
index a2dc4e67f..8ce4fe7b0 100644
--- a/src/testsuite/tst-test-script-compile.c
+++ b/src/testsuite/tst-test-script-compile.c
@@ -48,7 +48,7 @@ static int tst_test_script_compile_operation_execute
 		const struct sieve_runtime_env *renv, sieve_size_t *address);
 
 const struct sieve_operation test_script_compile_operation = { 
-	"test_script_compile",
+	"TEST_SCRIPT_COMPILE",
 	&testsuite_extension, 
 	TESTSUITE_OPERATION_TEST_SCRIPT_COMPILE,
 	tst_test_script_compile_operation_dump, 
@@ -100,7 +100,7 @@ static bool tst_test_script_compile_operation_dump
 (const struct sieve_operation *op ATTR_UNUSED,
 	const struct sieve_dumptime_env *denv, sieve_size_t *address)
 {
-	sieve_code_dumpf(denv, "test_script_compile:");
+	sieve_code_dumpf(denv, "TEST_SCRIPT_COMPILE:");
 	sieve_code_descend(denv);
 
 	if ( !sieve_opr_string_dump(denv, address, "script") ) 
diff --git a/src/testsuite/tst-test-script-run.c b/src/testsuite/tst-test-script-run.c
index f132a419d..2ba17b855 100644
--- a/src/testsuite/tst-test-script-run.c
+++ b/src/testsuite/tst-test-script-run.c
@@ -13,6 +13,7 @@
 #include "sieve.h"
 
 #include "testsuite-common.h"
+#include "testsuite-result.h"
 
 /*
  * Test_script_run command
@@ -21,6 +22,8 @@
  *   test_script_run
  */
 
+static bool tst_test_script_run_registered
+(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
 static bool tst_test_script_run_generate
 	(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx);
 
@@ -28,7 +31,8 @@ const struct sieve_command tst_test_script_run = {
 	"test_script_run", 
 	SCT_TEST, 
 	0, 0, FALSE, FALSE,
-	NULL, NULL, NULL,
+	tst_test_script_run_registered, 
+	NULL, NULL,
 	tst_test_script_run_generate, 
 	NULL 
 };
@@ -37,6 +41,9 @@ const struct sieve_command tst_test_script_run = {
  * Operation 
  */
 
+static bool tst_test_script_run_operation_dump
+	(const struct sieve_operation *op,
+		const struct sieve_dumptime_env *denv, sieve_size_t *address);
 static int tst_test_script_run_operation_execute
 	(const struct sieve_operation *op, 
 		const struct sieve_runtime_env *renv, sieve_size_t *address);
@@ -45,23 +52,89 @@ const struct sieve_operation test_script_run_operation = {
 	"test_script_run",
 	&testsuite_extension, 
 	TESTSUITE_OPERATION_TEST_SCRIPT_RUN,
-	NULL, 
+	tst_test_script_run_operation_dump, 
 	tst_test_script_run_operation_execute 
 };
 
+/*
+ * Tagged arguments
+ */
+
+/* Codes for optional arguments */
+
+enum cmd_vacation_optional {
+	OPT_END,
+	OPT_APPEND_RESULT
+};
+
+/* Tags */
+
+static const struct sieve_argument append_result_tag = { 
+	"append_result",	
+	NULL, NULL, NULL, NULL, NULL
+};
+
+static bool tst_test_script_run_registered
+(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) 
+{
+	sieve_validator_register_tag
+		(validator, cmd_reg, &append_result_tag, OPT_APPEND_RESULT); 	
+
+	return TRUE;
+}
+
+
 /* 
  * Code generation 
  */
 
 static bool tst_test_script_run_generate
 (const struct sieve_codegen_env *cgenv, 
-	struct sieve_command_context *tst ATTR_UNUSED)
+	struct sieve_command_context *tst)
 {
 	sieve_operation_emit_code(cgenv->sbin, &test_script_run_operation);
 
+	return sieve_generate_arguments(cgenv, tst, NULL);
+}
+
+/*
+ * Code dump
+ */
+
+static bool tst_test_script_run_operation_dump
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{	
+	int opt_code = 1;
+	
+	sieve_code_dumpf(denv, "TEST_SCRIPT_RUN");
+	sieve_code_descend(denv);	
+
+	/* Dump optional operands */
+	if ( sieve_operand_optional_present(denv->sbin, address) ) {
+		while ( opt_code != 0 ) {
+			sieve_code_mark(denv);
+			
+			if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) 
+				return FALSE;
+
+			switch ( opt_code ) {
+			case 0:
+				break;
+			case OPT_APPEND_RESULT:
+				sieve_code_dumpf(denv, "append_result");	
+				break;
+			
+			default:
+				return FALSE;
+			}
+		}
+	}
+	
 	return TRUE;
 }
 
+
 /*
  * Intepretation
  */
@@ -71,15 +144,48 @@ static int tst_test_script_run_operation_execute
 	const struct sieve_runtime_env *renv, 
 	sieve_size_t *address ATTR_UNUSED)
 {
+	bool append_result = FALSE;
+	int opt_code = 1;
 	bool result = TRUE;
 
+	/*
+	 * Read operands
+	 */
+
+	/* Optional operands */	
+	if ( sieve_operand_optional_present(renv->sbin, address) ) {
+		while ( opt_code != 0 ) {
+			if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) {
+				sieve_runtime_trace_error(renv, "invalid optional operand");
+				return SIEVE_EXEC_BIN_CORRUPT;
+			}
+
+			switch ( opt_code ) {
+			case 0:
+				break;
+			case OPT_APPEND_RESULT:
+				append_result = TRUE;
+				break;
+			default:
+				sieve_runtime_trace_error(renv, 
+					"unknown optional operand");
+				return SIEVE_EXEC_BIN_CORRUPT;
+			}
+		}
+	}
+
 	/*
 	 * Perform operation
 	 */
 
+	/* Reset result object */
+	if ( !append_result ) 
+		testsuite_result_reset();
+
+	/* Run script */
 	result = testsuite_script_run(renv);
 
-	/* Set result */
+	/* Indicate test status */
 	sieve_interpreter_set_test_result(renv->interp, result);
 
 	return SIEVE_EXEC_OK;
diff --git a/tests/multiscript/basic.svtest b/tests/multiscript/basic.svtest
new file mode 100644
index 000000000..54fb26b1c
--- /dev/null
+++ b/tests/multiscript/basic.svtest
@@ -0,0 +1,91 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan@rename-it.nl
+Message-ID: <frop33333333333333333@frutsens.nl>
+To: nico@vestingbar.nl
+Subject: Frop.
+
+Friep.
+.
+;
+
+test "Append" {
+	if not allof (
+		test_script_compile "fileinto-inbox.sieve",
+		test_script_run ){
+		test_fail "failed to compile and run first script";
+	}
+
+	if not allof ( 
+		test_script_compile "vacation.sieve",
+		test_script_run :append_result ) {
+		test_fail "failed to compile and run second script";
+	}
+
+	if not allof ( 
+		test_script_compile "notify.sieve",
+		test_script_run :append_result ) {
+		test_fail "failed to compile and run third script";
+	}
+
+	if not test_result :index 1 "store" {
+		test_fail "first action is not 'store'";
+	}
+
+	if not test_result :index 2 "vacation" {
+		test_fail "second action is not 'vacation'";
+	}
+
+	if not test_result :index 3 "notify" {
+		test_fail "third action is not 'notify'";
+	}
+
+	if not test_result_execute {
+		test_fail "result execute failed";
+	}
+}
+
+test "Sequential Execute" {
+	if not allof (
+		test_script_compile "fileinto-inbox.sieve",
+		test_script_run ) {
+		test_fail "failed to compile and run first script";
+	}
+
+	if not test_result_execute {
+		test_fail "result execute failed after first script";
+	}
+
+	if not allof (
+		test_script_compile "vacation.sieve",
+		test_script_run :append_result ) {
+		test_fail "failed to compile and run second script";
+	}
+
+	if not test_result_execute {
+		test_fail "result execute failed after second script";
+	}
+
+	if not allof (
+		test_script_compile "notify.sieve",
+		test_script_run :append_result ) {
+		test_fail "failed to compile and run third script";
+	}
+
+	if not test_result_execute {
+		test_fail "result execute failed after third script";
+	}
+
+	if not test_result :index 1 "store" {
+		test_fail "first action is not 'store'";
+	}
+
+	if not test_result :index 2 "vacation" {
+		test_fail "second action is not 'vacation'";
+	}
+
+	if not test_result :index 3 "notify" {
+		test_fail "third action is not 'notify'";
+	}
+}
diff --git a/tests/multiscript/conflicts.svtest b/tests/multiscript/conflicts.svtest
new file mode 100644
index 000000000..be9a58edc
--- /dev/null
+++ b/tests/multiscript/conflicts.svtest
@@ -0,0 +1,51 @@
+require "vnd.dovecot.testsuite";
+
+test_set "message" text:
+From: stephan@rename-it.nl
+Message-ID: <frop33333333333333333@frutsens.nl>
+To: nico@vestingbar.nl
+Subject: Frop.
+
+Friep.
+.
+;
+
+test "Graceful Conflicts" {
+	if not allof (
+		test_script_compile "fileinto-inbox.sieve",
+		test_script_run ){
+		test_fail "failed to compile and run first script";
+	}
+
+	if not test_result_execute {
+		test_fail "result execute failed after first script";
+	}
+
+	if not allof ( 
+		test_script_compile "reject-1.sieve",
+		test_script_run :append_result ) {
+		test_fail "failed to compile and run second script";
+	}
+
+	if not test_result_execute {
+		test_fail "result execute failed after second script";
+	}
+
+	if not allof ( 
+		test_script_compile "reject-2.sieve",
+		test_script_run :append_result ) {
+		test_fail "failed to compile and run third script";
+	}
+
+	if not test_result_execute {
+		test_fail "result execute failed after third script";
+	}
+
+	if not test_result :index 1 "store" {
+		test_fail "first action is not 'store'";
+	}
+
+	if test_result :index 2 "reject" {
+		test_fail "reject action not discarded";
+	}
+}
diff --git a/tests/multiscript/fileinto-inbox.sieve b/tests/multiscript/fileinto-inbox.sieve
new file mode 100644
index 000000000..b5da850e7
--- /dev/null
+++ b/tests/multiscript/fileinto-inbox.sieve
@@ -0,0 +1,4 @@
+require "fileinto";
+
+fileinto "INBOX";
+
diff --git a/tests/multiscript/notify.sieve b/tests/multiscript/notify.sieve
new file mode 100644
index 000000000..9e5507bc7
--- /dev/null
+++ b/tests/multiscript/notify.sieve
@@ -0,0 +1,3 @@
+require "enotify";
+
+notify "mailto:stephan@rename-it.nl";
diff --git a/tests/multiscript/reject-1.sieve b/tests/multiscript/reject-1.sieve
new file mode 100644
index 000000000..06744f60a
--- /dev/null
+++ b/tests/multiscript/reject-1.sieve
@@ -0,0 +1,3 @@
+require "reject";
+
+reject "Message is not wanted.";
diff --git a/tests/multiscript/reject-2.sieve b/tests/multiscript/reject-2.sieve
new file mode 100644
index 000000000..96b75642f
--- /dev/null
+++ b/tests/multiscript/reject-2.sieve
@@ -0,0 +1,3 @@
+require "reject";
+
+reject "Will not accept this nonsense.";
diff --git a/tests/multiscript/vacation.sieve b/tests/multiscript/vacation.sieve
new file mode 100644
index 000000000..d735da5bf
--- /dev/null
+++ b/tests/multiscript/vacation.sieve
@@ -0,0 +1,3 @@
+require "vacation";
+
+vacation "I am not home";
-- 
GitLab