From 67dc990f1ff6150162078e2b04a08ea9b460bc54 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Thu, 29 May 2008 01:57:55 +0200
Subject: [PATCH] Testsuite: added 'test' command to group sieve statements
 into a test.

---
 src/lib-sieve/cmd-if.c              |   2 +-
 src/lib-sieve/sieve-generator.c     |  10 +-
 src/lib-sieve/sieve-generator.h     |   5 +-
 src/lib-sieve/tst-allof.c           |   2 +-
 src/lib-sieve/tst-anyof.c           |   2 +-
 src/testsuite/Makefile.am           |   1 +
 src/testsuite/cmd-test-set.c        |  25 ++---
 src/testsuite/cmd-test.c            | 141 ++++++++++++++++++++++++++++
 src/testsuite/ext-testsuite.c       |   7 +-
 src/testsuite/tests/testsuite.sieve |  33 +++----
 src/testsuite/testsuite-common.h    |   7 ++
 src/testsuite/testsuite-objects.c   |  28 ++++--
 12 files changed, 211 insertions(+), 52 deletions(-)
 create mode 100644 src/testsuite/cmd-test.c

diff --git a/src/lib-sieve/cmd-if.c b/src/lib-sieve/cmd-if.c
index 279f694bd..16c5b55ce 100644
--- a/src/lib-sieve/cmd-if.c
+++ b/src/lib-sieve/cmd-if.c
@@ -148,7 +148,7 @@ static bool cmd_if_generate
 	struct sieve_jumplist jmplist;
 	
 	/* Prepare jumplist */
-	sieve_jumplist_init(&jmplist, sbin);
+	sieve_jumplist_init_temp(&jmplist, sbin);
 	
 	/* Generate test condition */
 	test = sieve_ast_test_first(ctx->ast_node);
diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c
index 27d70874b..d71a6995b 100644
--- a/src/lib-sieve/sieve-generator.c
+++ b/src/lib-sieve/sieve-generator.c
@@ -12,7 +12,15 @@
 #include "sieve-generator.h"
 
 /* Jump list */
-void sieve_jumplist_init(struct sieve_jumplist *jlist, struct sieve_binary *sbin)
+void sieve_jumplist_init
+	(struct sieve_jumplist *jlist, pool_t pool, struct sieve_binary *sbin)
+{
+	jlist->binary = sbin;
+	p_array_init(&jlist->jumps, pool, 4);
+}
+
+void sieve_jumplist_init_temp
+	(struct sieve_jumplist *jlist, struct sieve_binary *sbin)
 {
 	jlist->binary = sbin;
 	t_array_init(&jlist->jumps, 4);
diff --git a/src/lib-sieve/sieve-generator.h b/src/lib-sieve/sieve-generator.h
index 979e118ad..aa1b46003 100644
--- a/src/lib-sieve/sieve-generator.h
+++ b/src/lib-sieve/sieve-generator.h
@@ -36,12 +36,15 @@ inline const void *sieve_generator_extension_get_context
 /* Jump list */
 
 struct sieve_jumplist {
+	pool_t pool;
 	struct sieve_binary *binary;
 	ARRAY_DEFINE(jumps, sieve_size_t);
 };
 
-void sieve_jumplist_init
+void sieve_jumplist_init_temp
 	(struct sieve_jumplist *jlist, struct sieve_binary *sbin);
+void sieve_jumplist_init
+	(struct sieve_jumplist *jlist, pool_t pool, struct sieve_binary *sbin);
 void sieve_jumplist_add
 	(struct sieve_jumplist *jlist, sieve_size_t jump);
 void sieve_jumplist_resolve(struct sieve_jumplist *jlist);
diff --git a/src/lib-sieve/tst-allof.c b/src/lib-sieve/tst-allof.c
index 05f078dfa..1b1d50467 100644
--- a/src/lib-sieve/tst-allof.c
+++ b/src/lib-sieve/tst-allof.c
@@ -38,7 +38,7 @@ static bool tst_allof_generate
 	
 	if ( jump_true ) {
 		/* Prepare jumplist */
-		sieve_jumplist_init(&false_jumps, sbin);
+		sieve_jumplist_init_temp(&false_jumps, sbin);
 	}
 	
 	test = sieve_ast_test_first(ctx->ast_node);
diff --git a/src/lib-sieve/tst-anyof.c b/src/lib-sieve/tst-anyof.c
index f9f6f25da..9ec7f50db 100644
--- a/src/lib-sieve/tst-anyof.c
+++ b/src/lib-sieve/tst-anyof.c
@@ -36,7 +36,7 @@ static bool tst_anyof_generate
 	
 	if ( !jump_true ) {
 		/* Prepare jumplist */
-		sieve_jumplist_init(&true_jumps, sbin);
+		sieve_jumplist_init_temp(&true_jumps, sbin);
 	}
 	
 	test = sieve_ast_test_first(ctx->ast_node);
diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am
index 061606cc4..7d4382dd6 100644
--- a/src/testsuite/Makefile.am
+++ b/src/testsuite/Makefile.am
@@ -38,6 +38,7 @@ testsuite_LDADD = $(ldadd)
 testsuite_DEPENDENCIES = $(libs)
 
 cmds = \
+	cmd-test.c \
 	cmd-test-set.c
 
 testsuite_SOURCES = \
diff --git a/src/testsuite/cmd-test-set.c b/src/testsuite/cmd-test-set.c
index 7506177db..1db6aacb6 100644
--- a/src/testsuite/cmd-test-set.c
+++ b/src/testsuite/cmd-test-set.c
@@ -54,51 +54,38 @@ const struct sieve_command cmd_test_set = {
 const struct sieve_operation test_set_operation = { 
 	"TEST_SET",
 	&testsuite_extension, 
-	0,
+	TESTSUITE_OPERATION_TEST_SET,
 	cmd_test_set_operation_dump, 
 	cmd_test_set_operation_execute 
 };
 
-/* Fields */
-
-enum cmd_test_set_object {
-	CMD_SET_OBJ_MESSAGE,
-	CMD_SET_OBJ_ENVELOPE
-};
-
-enum cmd_test_set_envelope_field {
-	CMD_SET_ENVELOPE_SENDER,
-	CMD_SET_ENVELOPE_RECIPIENT,
-	CMD_SET_ENVELOPE_AUTH_USER
-};
-
 /* 
  * Validation 
  */
  
 static bool cmd_test_set_validate
-(struct sieve_validator *validator, struct sieve_command_context *cmd) 
+(struct sieve_validator *valdtr, struct sieve_command_context *cmd) 
 {
 	struct sieve_ast_argument *arg = cmd->first_positional;
 
 	/* Check arguments */
 	
 	if ( !sieve_validate_positional_argument
-		(validator, cmd, arg, "object", 1, SAAT_STRING) ) {
+		(valdtr, cmd, arg, "object", 1, SAAT_STRING) ) {
 		return FALSE;
 	}
 	
-	if ( !testsuite_object_argument_activate(validator, arg, cmd) )
+	if ( !testsuite_object_argument_activate(valdtr, arg, cmd) )
 		return FALSE;
 	
 	arg = sieve_ast_argument_next(arg);
 	
 	if ( !sieve_validate_positional_argument
-		(validator, cmd, arg, "value", 2, SAAT_STRING) ) {
+		(valdtr, cmd, arg, "value", 2, SAAT_STRING) ) {
 		return FALSE;
 	}
 	
-	return sieve_validator_argument_activate(validator, cmd, arg, FALSE);
+	return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
 }
 
 /*
diff --git a/src/testsuite/cmd-test.c b/src/testsuite/cmd-test.c
new file mode 100644
index 000000000..c1f796d53
--- /dev/null
+++ b/src/testsuite/cmd-test.c
@@ -0,0 +1,141 @@
+#include "sieve-commands.h"
+#include "sieve-commands-private.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-code.h"
+#include "sieve-binary.h"
+#include "sieve-dump.h"
+
+#include "testsuite-common.h"
+
+/* Predeclarations */
+
+static bool cmd_test_operation_dump
+	(const struct sieve_operation *op,
+		const struct sieve_dumptime_env *denv, sieve_size_t *address);
+static bool cmd_test_operation_execute
+	(const struct sieve_operation *op, 
+		const struct sieve_runtime_env *renv, sieve_size_t *address);
+
+static bool cmd_test_validate
+	(struct sieve_validator *validator, struct sieve_command_context *cmd);
+static bool cmd_test_generate
+	(struct sieve_generator *generator, struct sieve_command_context *ctx);
+
+/* Test command
+ *
+ * Syntax:   
+ *   test <test-name: string> <block>
+ */
+const struct sieve_command cmd_test = { 
+	"test", 
+	SCT_COMMAND, 
+	1, 0, TRUE, TRUE,
+	NULL, NULL,
+	cmd_test_validate, 
+	cmd_test_generate, 
+	NULL 
+};
+
+/* Test operation */
+
+const struct sieve_operation test_operation = { 
+	"TEST",
+	&testsuite_extension, 
+	TESTSUITE_OPERATION_TEST,
+	cmd_test_operation_dump, 
+	cmd_test_operation_execute 
+};
+
+/* Validation */
+
+static bool cmd_test_validate
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command_context *cmd) 
+{
+	struct sieve_ast_argument *arg = cmd->first_positional;
+		
+ 	/* Check valid command placement */
+	if ( !sieve_command_is_toplevel(cmd) )
+	{
+		sieve_command_validate_error(valdtr, cmd,
+			"tests cannot be nested: test command must be issued at top-level");
+		return FALSE;
+	}
+	
+	if ( !sieve_validate_positional_argument
+		(valdtr, cmd, arg, "test-name", 1, SAAT_STRING) ) {
+		return FALSE;
+	}
+	
+	return sieve_validator_argument_activate(valdtr, cmd, arg, FALSE);
+}
+
+/* Code generation */
+
+static bool cmd_test_generate
+	(struct sieve_generator *generator, struct sieve_command_context *ctx)
+{
+	struct sieve_binary *sbin = sieve_generator_get_binary(generator);
+	struct sieve_jumplist jmplist;
+	
+	sieve_generator_emit_operation_ext(generator, &test_operation, 
+		ext_testsuite_my_id);
+
+	/* Generate arguments */
+	if ( !sieve_generate_arguments(generator, ctx, NULL) )
+		return FALSE;
+		
+	/* Prepare jumplist */
+	sieve_jumplist_init_temp(&jmplist, sbin);
+		
+	/* Test body */
+	sieve_generate_block(generator, ctx->ast_node);
+	
+	/* Resolve exit jumps to this point */
+	sieve_jumplist_resolve(&jmplist); 
+			
+	return TRUE;
+}
+
+/* 
+ * Code dump
+ */
+ 
+static bool cmd_test_operation_dump
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_dumptime_env *denv, sieve_size_t *address)
+{
+	sieve_code_dumpf(denv, "TEST:");
+	sieve_code_descend(denv);
+
+	return 
+		sieve_opr_string_dump(denv, address);
+}
+
+/*
+ * Intepretation
+ */
+
+static bool cmd_test_operation_execute
+(const struct sieve_operation *op ATTR_UNUSED,
+	const struct sieve_runtime_env *renv, sieve_size_t *address)
+{
+	string_t *test_name;
+
+	t_push();
+
+	if ( !sieve_opr_string_read(renv, address, &test_name) ) {
+		t_pop();
+		return FALSE;
+	}
+
+	printf("TEST: %s\n", str_c(test_name));
+	
+	t_pop();
+	
+	return TRUE;
+}
+
+
+
+
diff --git a/src/testsuite/ext-testsuite.c b/src/testsuite/ext-testsuite.c
index 11100afe0..c787d280e 100644
--- a/src/testsuite/ext-testsuite.c
+++ b/src/testsuite/ext-testsuite.c
@@ -34,6 +34,7 @@ static bool ext_testsuite_binary_load(struct sieve_binary *sbin);
 
 /* Commands */
 
+extern const struct sieve_command cmd_test;
 extern const struct sieve_command cmd_test_set;
 
 /* Operands */
@@ -43,10 +44,11 @@ const struct sieve_operand *testsuite_operands[] =
 
 /* Operations */
 
+extern const struct sieve_operation test_operation;
 extern const struct sieve_operation test_set_operation;
 
 const struct sieve_operation *testsuite_operations[] =
-    { &test_set_operation };
+    { &test_operation, &test_set_operation };
     
 /* Extension definitions */
 
@@ -59,7 +61,7 @@ const struct sieve_extension testsuite_extension = {
 	NULL, NULL,
 	ext_testsuite_binary_load, 
 	NULL, 
-	SIEVE_EXT_DEFINE_OPERATION(test_set_operation),
+	SIEVE_EXT_DEFINE_OPERATIONS(testsuite_operations),
 	SIEVE_EXT_DEFINE_OPERAND(testsuite_object_operand)
 };
 
@@ -74,6 +76,7 @@ static bool ext_testsuite_load(int ext_id)
 
 static bool ext_testsuite_validator_load(struct sieve_validator *validator)
 {
+	sieve_validator_register_command(validator, &cmd_test);
 	sieve_validator_register_command(validator, &cmd_test_set);
 	
 	return testsuite_validator_context_initialize(validator);
diff --git a/src/testsuite/tests/testsuite.sieve b/src/testsuite/tests/testsuite.sieve
index 6a260b4c6..4c076ba26 100644
--- a/src/testsuite/tests/testsuite.sieve
+++ b/src/testsuite/tests/testsuite.sieve
@@ -1,35 +1,36 @@
 require "vnd.dovecot.testsuite";
 
-test_set "message" text:
+test "Message environment test" {
+	test_set "message" text:
 From: sirius@rename-it.nl
 To: nico@vestingbar.nl
 Subject: Frop!
 
 Frop!
 .
-;
-test_set "envelope.from" "stephan@rename-it.nl";
+	;
+	test_set "envelope.from" "stephan@rename-it.nl";
 
-if not header :contains "from" "rename-it.nl" {
-	discard;
-	stop;
-}
+	if not header :contains "from" "rename-it.nl" {
+		discard;
+		stop;
+	}
 
-test_set "message" text:
+	test_set "message" text:
 From: nico@vestingbar.nl
 To: stephan@zuiphol.nl
 Subject: Friep!
 
 Friep!
 .
-;
-test_set "envelope.from" "stephan@rename-it.nl";
-
-if not header :is "from" "nico@vestingbar.nl" {
-    discard;
-    stop;
-} 
+	;
+	test_set "envelope.from" "stephan@rename-it.nl";
 
-keep;
+	if not header :is "from" "nico@vestingbar.nl" {
+    	discard;
+    	stop;
+	} 
 
+	keep;
+}
 
diff --git a/src/testsuite/testsuite-common.h b/src/testsuite/testsuite-common.h
index d2e62e931..c866dd849 100644
--- a/src/testsuite/testsuite-common.h
+++ b/src/testsuite/testsuite-common.h
@@ -26,6 +26,13 @@ struct testsuite_validator_context {
 
 bool testsuite_validator_context_initialize(struct sieve_validator *valdtr);
 
+/* Testsuite operations */
+
+enum testsuite_operation_code {
+	TESTSUITE_OPERATION_TEST,
+	TESTSUITE_OPERATION_TEST_SET
+};
+
 /* Testsuite operands */
 
 extern const struct sieve_operand testsuite_object_operand;
diff --git a/src/testsuite/testsuite-objects.c b/src/testsuite/testsuite-objects.c
index d4dda7b91..31976acd9 100644
--- a/src/testsuite/testsuite-objects.c
+++ b/src/testsuite/testsuite-objects.c
@@ -308,7 +308,6 @@ static int tsto_envelope_get_member_id(const char *identifier);
 static const char *tsto_envelope_get_member_name(int id);
 static bool tsto_envelope_set_member(int id, string_t *value);
 
-
 const struct testsuite_object message_testsuite_object = { 
 	"message",
 	TESTSUITE_OBJECT_MESSAGE,
@@ -328,6 +327,12 @@ const struct testsuite_object envelope_testsuite_object = {
 	NULL
 };
 
+enum testsuite_object_envelope_field {
+	TESTSUITE_OBJECT_ENVELOPE_FROM,
+	TESTSUITE_OBJECT_ENVELOPE_TO,
+	TESTSUITE_OBJECT_ENVELOPE_AUTH_USER
+};
+
 static bool tsto_message_set_member(int id, string_t *value) 
 {
 	if ( id != -1 ) return FALSE;
@@ -340,11 +345,11 @@ static bool tsto_message_set_member(int id, string_t *value)
 static int tsto_envelope_get_member_id(const char *identifier)
 {
 	if ( strcasecmp(identifier, "from") == 0 )
-		return 0;
+		return TESTSUITE_OBJECT_ENVELOPE_FROM;
 	if ( strcasecmp(identifier, "to") == 0 )
-		return 1;
+		return TESTSUITE_OBJECT_ENVELOPE_TO;
 	if ( strcasecmp(identifier, "auth") == 0 )
-		return 2;	
+		return TESTSUITE_OBJECT_ENVELOPE_AUTH_USER;	
 	
 	return -1;
 }
@@ -352,9 +357,12 @@ static int tsto_envelope_get_member_id(const char *identifier)
 static const char *tsto_envelope_get_member_name(int id) 
 {
 	switch ( id ) {
-	case 0: return "from";
-	case 1: return "to";
-	case 2: return "auth";
+	case TESTSUITE_OBJECT_ENVELOPE_FROM: 
+		return "from";
+	case TESTSUITE_OBJECT_ENVELOPE_TO: 
+		return "to";
+	case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER: 
+		return "auth";
 	}
 	
 	return NULL;
@@ -363,13 +371,13 @@ static const char *tsto_envelope_get_member_name(int id)
 static bool tsto_envelope_set_member(int id, string_t *value)
 {
 	switch ( id ) {
-	case 0: 
+	case TESTSUITE_OBJECT_ENVELOPE_FROM: 
 		testsuite_envelope_set_sender(str_c(value));
 		return TRUE;
-	case 1:
+	case TESTSUITE_OBJECT_ENVELOPE_TO:
 		testsuite_envelope_set_recipient(str_c(value));
 		return TRUE;
-	case 2: 
+	case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER: 
 		testsuite_envelope_set_auth_user(str_c(value));
 		return TRUE;
 	}
-- 
GitLab