diff --git a/Makefile.am b/Makefile.am
index e9b08aa86d392a7608b1b88033bc4c85687b084d..828d228ae2c58792df9dc02a3d5b75473661bb5d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,3 +12,5 @@ ChangeLog: .hg/dirstate
 	hg log --style=changelog > ChangeLog
 endif
 
+test:
+	$(MAKE) -C src/testsuite test
diff --git a/TODO b/TODO
index 73328665eae40f2f149c82f53d99bc17e8a795a7..c91b112294f3e66c3e1b4fe0b9aca1179b47dd7f 100644
--- a/TODO
+++ b/TODO
@@ -2,8 +2,6 @@ Next (in order of descending priority/precedence):
 * Make utility functions for handling sieve system errors.
 * Review sieve-address parsing implementation for past-end checks
 * Improve handling of old/corrupt binaries.
-* Distinguish between 1.2 and 1.1 and start using mailbox_keyword_is_valid()
-  and new const str. 
 
 * Test with dovecot --enable-debug for initial mempool allocation size
 * Full standards compliance review for the engine and all fully implemented 
@@ -13,32 +11,32 @@ Next (in order of descending priority/precedence):
 * Full security review. Enforce limits on number of created objects, script 
   size, execution time, etc...
 * Make simple test suite for the base functionality
+* Distinguish between 1.2 and 1.1 and start using mailbox_keyword_is_valid()
+  and new const str. 
 
 * ## MAKE A FIRST RELEASE ##
 
+* Add normalize() method to comparators to normalize the string before mathing
+  (for efficiency).
+* Verify outgoing mail addresses at runtime when necessary (e.g. after variables 
+  substitution)
+* Implement dropping errors in the user's mailbox as a mail message.
 * Provide a solution for mail_get_headers_utf8 reparsing the whole message each
   time it is called (header and address test; Timo might provide solution from
   within Dovecot)
 * Build a sieve tool to filter an entire existing mailbox through a sieve script.
 * Build a server with test mail accounts that processes lots and lots of mail 
   (e.g. spam, mailing lists etc.)
-* Implement environment extension
-* Implement notify extension with sole support for mailto mechanism. 
-* Implement date and index extensions
 * Make this implementation conform section 2.7.2 of RFC3028 (Comparisons Across
   Character Sets). 
-* Verify outgoing mail addresses at runtime when necessary (e.g. after variables 
-  substitution)
-* Implement dropping errors in the user's mailbox as a mail message.
-* Add normalize() method to comparators to normalize the string before mathing
-  (for efficiency).
 * Implement comparator-i;unicode-casemap
+* Implement environment extension
+* Implement notify extension with sole support for mailto mechanism. 
+* Implement date and index extensions
 * Automate script tests; i.e. build a test suite.
 * Use lib/str-find.h for :contains and :matches match types  
 * Resolve code duplication introduced for handling address-parts and match-types
   in different command implementations.
-* Resolve code duplication amongst comparator, address-part and match-type 
-  support as much as possible.
 * Add development documentation, i.e. comment on library functions and document
   the binary and byte-code format. 
 * Make the engine and its extensions much more configurable. Possibly this can 
diff --git a/configure.in b/configure.in
index 4c225fdaac1311ccbe422338eee7843299cf07c5..7a1e69012763a38916c6fd30fc0be1426226fe43 100644
--- a/configure.in
+++ b/configure.in
@@ -54,6 +54,9 @@ AC_SUBST(MODULE_LIBS)
 AC_SUBST(dovecot_incdir)
 AC_SUBST(moduledir)
 
+TESTSUITE_BIN="\$(top_srcdir)/src/testsuite/testsuite"
+AC_SUBST(TESTSUITE_BIN)
+
 AC_CONFIG_FILES([
 Makefile
 src/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index e3940c66446bf9e83d65392116a8520794ae7bc0..4edf1020e588c0f0043016b09196858c7e324396 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1 +1,2 @@
 SUBDIRS = lib-sieve sieve-bin plugins testsuite
+
diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am
index 1afea99323086a6b39426f129ffb318c64bd57e3..9c57d0d75cb17b5f781050c95eda65dbeeb4c586 100644
--- a/src/testsuite/Makefile.am
+++ b/src/testsuite/Makefile.am
@@ -56,3 +56,21 @@ noinst_HEADERS = \
 	testsuite-objects.h \
 	namespaces.h \
 	mail-raw.h
+
+# Testsuite tests
+
+EXTRA_DIST = tests
+
+test_cases = \
+    tests/control-structures.svtest \
+    tests/testsuite.svtest\
+	tests/comparators/core.svtest \
+	tests/match-types/contains.svtest \
+	tests/match-types/matches.svtest \
+	tests/extensions/variables/basic.svtest
+
+$(test_cases): 
+	@$(TESTSUITE_BIN) $@
+.PHONY: $(test_cases)
+
+test: $(test_cases)
diff --git a/src/testsuite/tests/testsuite.svtest b/src/testsuite/tests/testsuite.svtest
index 05a4e13ad4d0b31aca3e25835a3ed254770e1d48..8b79dbd54d3714464a7fe2636fa35ebf4d8f918f 100644
--- a/src/testsuite/tests/testsuite.svtest
+++ b/src/testsuite/tests/testsuite.svtest
@@ -1,6 +1,6 @@
 require "vnd.dovecot.testsuite";
 
-test "Message environment test" {
+test "Message Environment" {
 	test_set "message" text:
 From: sirius@rename-it.nl
 To: nico@vestingbar.nl
@@ -12,7 +12,7 @@ Frop!
 	test_set "envelope.from" "stephan@rename-it.nl";
 
 	if not header :contains "from" "rename-it.nl" {
-		test_fail "Message data not set properly.";
+		test_fail "message data not set properly.";
 	}
 
 	test_set "message" text:
@@ -26,7 +26,7 @@ Friep!
 	test_set "envelope.from" "stephan@rename-it.nl";
 
 	if not header :is "from" "nico@vestingbar.nl" {
-    	test_fail "Message data not set properly.";
+    	test_fail "message data not set properly.";
 	} 
 
 	keep;
diff --git a/src/testsuite/testsuite-common.c b/src/testsuite/testsuite-common.c
index 5a613850a48a8b649263f8e84ff64e1aca8a9c58..cdfd1d49044bf8f69feb27b72267cc6541d552bc 100644
--- a/src/testsuite/testsuite-common.c
+++ b/src/testsuite/testsuite-common.c
@@ -30,6 +30,7 @@ struct sieve_message_data testsuite_msgdata;
 
 static string_t *test_name;
 unsigned int test_index;
+unsigned int test_failures;
 
 /* 
  * Testsuite message environment 
@@ -176,6 +177,7 @@ void testsuite_test_context_init(void)
 {
 	test_name = str_new(default_pool, 128);
 	test_index = 0;	
+	test_failures = 0;
 }
 
 void testsuite_test_start(string_t *name)
@@ -202,6 +204,8 @@ void testsuite_test_fail(string_t *reason)
 	}
 
 	str_truncate(test_name, 0);
+
+	test_failures++;
 }
 
 void testsuite_test_succeed(string_t *reason)
@@ -226,3 +230,14 @@ void testsuite_test_context_deinit(void)
 	//str_free(test_name);
 }
 
+int testsuite_testcase_result(void)
+{
+	if ( test_failures > 0 ) {
+		printf("\nFAIL: %d of %d tests failed.\n\n", test_failures, test_index);
+		return 1;
+	}
+
+	printf("\nPASS: %d tests succeeded.\n\n", test_index);
+	return 0;
+}
+
diff --git a/src/testsuite/testsuite-common.h b/src/testsuite/testsuite-common.h
index cdf9c3092a1730c63b999c7c9c6ae6faf51d42a9..761b4e5566c0cafe3c451417504ddc2932fffc77 100644
--- a/src/testsuite/testsuite-common.h
+++ b/src/testsuite/testsuite-common.h
@@ -66,4 +66,6 @@ void testsuite_test_fail(string_t *reason);
 void testsuite_test_succeed(string_t *reason);
 void testsuite_test_context_deinit(void);
 
+int testsuite_testcase_result(void);
+
 #endif /* __TESTSUITE_COMMON_H */
diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c
index f72b8b6638b0c3d1e20f239ec8f310002b5d45b4..5d9adb16250b624115b8b9f2da30ca13a52f78d3 100644
--- a/src/testsuite/testsuite.c
+++ b/src/testsuite/testsuite.c
@@ -11,6 +11,8 @@
 #include "namespaces.h"
 #include "sieve.h"
 #include "sieve-extensions.h"
+#include "sieve-result.h"
+#include "sieve-interpreter.h"
 
 #include "testsuite-common.h"
 
@@ -134,6 +136,25 @@ static void print_help(void)
 	);
 }
 
+static int testsuite_run
+(struct sieve_binary *sbin, const struct sieve_script_env *scriptenv)
+{
+	struct sieve_error_handler *ehandler = sieve_stderr_ehandler_create(0);
+	struct sieve_result *sres = sieve_result_create(ehandler);
+	struct sieve_interpreter *interp =
+		sieve_interpreter_create(sbin, ehandler, NULL);
+	int ret = 0;
+
+    ret = sieve_interpreter_run(interp, &testsuite_msgdata, scriptenv, &sres);
+
+	sieve_interpreter_free(&interp);
+	sieve_result_unref(&sres);
+
+	sieve_error_handler_unref(&ehandler);
+
+	return ret;	
+}
+
 int main(int argc, char **argv) 
 {
 	const char *scriptfile, *dumpfile; 
@@ -142,8 +163,6 @@ int main(int argc, char **argv)
 	pool_t namespaces_pool;
 	struct sieve_binary *sbin;
 	struct sieve_script_env scriptenv;
-	struct sieve_error_handler *ehandler;
-	struct ostream *teststream;
 
 	testsuite_init();
 
@@ -168,6 +187,8 @@ int main(int argc, char **argv)
 		print_help();
 		i_fatal("Missing <scriptfile> argument");
 	}
+
+	printf("Test case: %s:\n\n", scriptfile);
 	
 	/* Compile sieve script */
 	sbin = _compile_sieve_script(scriptfile);
@@ -183,23 +204,15 @@ int main(int argc, char **argv)
 	scriptenv.inbox = "INBOX";
 	scriptenv.username = user;
 
-	ehandler = sieve_stderr_ehandler_create(0);	
-
-	teststream = o_stream_create_fd(1, 0, FALSE);
-	
 	/* Run the test */
-	(void) sieve_test
-		(sbin, &testsuite_msgdata, &scriptenv, teststream, ehandler, NULL);
-
-	o_stream_destroy(&teststream);
+	(void) testsuite_run(sbin, &scriptenv);
 
 	sieve_close(&sbin);
-	sieve_error_handler_unref(&ehandler);
 
 	testsuite_message_deinit();
 	namespaces_deinit();
 
 	testsuite_deinit();  
 
-	return 0;
+	return testsuite_testcase_result();
 }