diff --git a/_test/index.php b/_test/index.php
index 87cc10a35970dc01d83bd9d783944ced00fa2f61..f59c44cf43bd7a8397368bc4c3bb548a2d2169c2 100644
--- a/_test/index.php
+++ b/_test/index.php
@@ -130,6 +130,30 @@ function DW_TESTS_PaintGroupTestList() {
     }
 }
 
+function DW_TESTS_PaintPluginTestCaseList() {
+    switch ( DW_TESTS_OUTPUT ) {
+        case DW_TESTS_OUTPUT_XML:
+            echo XMLTestManager::getPluginTestCaseList(TEST_PLUGINS);
+        break;
+        case DW_TESTS_OUTPUT_HTML:
+        default:
+            echo HTMLTestManager::getPluginTestCaseList(TEST_PLUGINS);
+        break;
+    }
+}
+
+function DW_TESTS_PaintPluginGroupTestList() {
+    switch ( DW_TESTS_OUTPUT ) {
+        case DW_TESTS_OUTPUT_XML:
+            echo XMLTestManager::getPluginGroupTestList(TEST_PLUGINS);
+        break;
+        case DW_TESTS_OUTPUT_HTML:
+        default:
+            echo HTMLTestManager::getPluginGroupTestList(TEST_PLUGINS);
+        break;
+    }
+}
+
 function DW_TESTS_PaintFooter() {
     switch ( DW_TESTS_OUTPUT ) {
         case DW_TESTS_OUTPUT_XML:
@@ -160,6 +184,19 @@ if (isset($_GET['group'])) {
     exit();
 }
 
+// If it's a plugin group test
+if (isset($_GET['plugin_group'])) {
+    if ('all' == $_GET['plugin_group']) {
+        TestManager::runAllPluginTests(DW_TESTS_GetReporter());
+    } else {
+        TestManager::runGroupTest(ucfirst($_GET['plugin_group']),
+                                  TEST_PLUGINS,
+                                  DW_TESTS_GetReporter());
+    }
+    DW_TESTS_PaintRunMore();
+    exit();
+}
+
 // If it's a single test case
 if (isset($_GET['case'])) {
     TestManager::runTestCase($_GET['case'], TEST_CASES, DW_TESTS_GetReporter());
@@ -167,6 +204,13 @@ if (isset($_GET['case'])) {
     exit();
 }
 
+// If it's a single plugin test case
+if (isset($_GET['plugin_case'])) {
+    TestManager::runTestCase($_GET['plugin_case'], TEST_PLUGINS, DW_TESTS_GetReporter());
+    DW_TESTS_PaintRunMore();
+    exit();
+}
+
 // Else it's the main page
 DW_TESTS_PaintHeader();
 
@@ -174,9 +218,11 @@ DW_TESTS_PaintSuiteHeader();
 
 if (isset($_GET['show']) && $_GET['show'] == 'cases') {
     DW_TESTS_PaintCaseList();
+    DW_TESTS_PaintPluginTestCaseList();
 } else {
     /* no group specified, so list them all */
     DW_TESTS_PaintGroupTestList();
+    DW_TESTS_PaintPluginGroupTestList();
 }
 
 DW_TESTS_PaintFooter();
diff --git a/_test/lib/testmanager.php b/_test/lib/testmanager.php
index 14cc20bf36f7cdbe29c3c9c2843cae4290204b09..96c9a57a26f0ef3aeb24edae7b3ed8924be52d76 100644
--- a/_test/lib/testmanager.php
+++ b/_test/lib/testmanager.php
@@ -5,6 +5,7 @@
 
 define('TEST_GROUPS',realpath(dirname(__FILE__).'/../cases'));
 define('TEST_CASES',realpath(dirname(__FILE__).'/../cases'));
+define('TEST_PLUGINS',realpath(dirname(__FILE__).'/../../lib/plugins'));
 
 // try to load runkit extension
 if (!extension_loaded('runkit') && function_exists('dl')) {
@@ -59,6 +60,17 @@ class TestManager {
         $test->run($reporter);
     }
 
+    function runAllPluginTests(&$reporter) {
+        $manager =& new TestManager();
+        $test_cases =& $manager->_getTestFileList(TEST_PLUGINS);
+        $test =& new GroupTest('All Plugin Tests');
+        foreach ($test_cases as $test_case) {
+            $test->addTestFile($test_case);
+        }
+        $test->run($reporter);
+    }
+
+
     function runTestCase($testcase_name, $test_case_directory, &$reporter) {
         $manager =& new TestManager();
         
@@ -125,12 +137,12 @@ class TestManager {
     }
 
     function &_getTestCaseList($directory = '.') {
-        $base = TEST_GROUPS . DIRECTORY_SEPARATOR;
         $file_list =& $this->_getTestFileList($directory);
         $testcases = array();
         foreach ($file_list as $testcase_file) {
             $case = str_replace($this->_testcase_extension, '',$testcase_file);
-            $case = str_replace($base, '', $case);
+            $case = str_replace(TEST_GROUPS . DIRECTORY_SEPARATOR, '', $case);
+            $case = str_replace(TEST_PLUGINS . DIRECTORY_SEPARATOR, '', $case);
             $case = str_replace(DIRECTORY_SEPARATOR, ':', $case);
             $testcases[$testcase_file] = $case;
         }
@@ -142,6 +154,16 @@ class TestManager {
                                             array(&$this, '_isTestCaseFile'));
     }
 
+    function &getPluginTestCaseList($directory = '.') {
+        $manager =& new TestManager();
+        return $manager->_getTestCaseList($directory);
+    }
+
+    function &getPluginGroupTestList($directory = '.') {
+        $manager =& new TestManager();
+        return $manager->_getTestGroupList($directory);
+    }
+
     function &getGroupTestList($directory = '.') {
         $manager =& new TestManager();
         return $manager->_getTestGroupList($directory);
@@ -153,12 +175,12 @@ class TestManager {
     }
 
     function &_getTestGroupList($directory = '.') {
-        $base = TEST_GROUPS . DIRECTORY_SEPARATOR;
         $file_list =& $this->_getTestGroupFileList($directory);
         $grouptests = array();
         foreach ($file_list as $grouptest_file) {
             $group = str_replace($this->_grouptest_extension, '',$grouptest_file);
-            $group = str_replace($base, '', $group);
+            $group = str_replace(TEST_GROUPS . DIRECTORY_SEPARATOR, '', $group);
+            $group = str_replace(TEST_PLUGINS . DIRECTORY_SEPARATOR, '', $group);
             $group = str_replace(DIRECTORY_SEPARATOR, ':', $group);
             $grouptests[$grouptest_file] = $group;
         }
@@ -168,7 +190,7 @@ class TestManager {
 
     function &_getGroupTestClassNames($grouptest_file) {
         $file = implode("\n", file($grouptest_file));
-        preg_match("~lass\s+?(.*)\s+?extends GroupTest~", $file, $matches);
+        preg_match("~lass\s+?(.*)\s+?extends .*?GroupTest~", $file, $matches);
         if (! empty($matches)) {
             unset($matches[0]);
             return $matches;
@@ -242,6 +264,29 @@ class CLITestManager extends TestManager {
         }
         return $buffer . "\n";
     }
+
+    function &getPluginTestCaseList($directory = '.') {
+        $manager =& new CLITestManager();
+        $test_cases =& $manager->_getTestCaseList($directory);
+
+        $buffer = "Available test cases:\n";
+        foreach ($test_cases as $test_case) {
+            $buffer .= "  " . $test_case . "\n";
+        }
+        return $buffer . "\n";
+    }
+
+    function &getPluginGroupTestList($directory = '.') {
+        $manager =& new CLITestManager();
+        $test_cases =& $manager->_getTestGroupList($directory);
+
+        $buffer = "Available test cases:\n";
+        foreach ($test_cases as $test_case) {
+            $buffer .= "  " . $test_case . "\n";
+        }
+        return $buffer . "\n";
+    }
+
 }
 
 class HTMLTestManager extends TestManager {
@@ -289,6 +334,42 @@ class HTMLTestManager extends TestManager {
         $buffer .= "</ul>\n";
         return $buffer;
     }
+
+    function &getPluginTestCaseList($directory = '.') {
+        $manager =& new HTMLTestManager();
+        $testcases =& $manager->_getTestCaseList($directory);
+
+        if (1 > count($testcases)) {
+            return "<p>No plugin test cases set up!</p>";
+        }
+        $buffer = "<p>Available plugin test cases:</p>\n<ul>";
+        foreach ($testcases as $testcase) {
+            $buffer .= "<li><a href='" . $manager->getBaseURL() .
+                "?plugin_case=" . urlencode($testcase) . "'>" .
+                $testcase . "</a></li>\n";
+        }
+
+        $buffer .= "</ul>\n";
+        return $buffer;
+    }
+
+    function &getPluginGroupTestList($directory = '.') {
+        $manager =& new HTMLTestManager();
+        $group_tests =& $manager->_getTestGroupList($directory);
+        if (1 > count($group_tests)) {
+            return "<p>No plugin test groups set up!</p>";
+        }
+        $buffer = "<p>Available plugin groups:</p>\n<ul>";
+        $buffer .= "<li><a href='" . $manager->getBaseURL() . "?plugin_group=all'>All tests</a></li>\n";
+        foreach ($group_tests as $group_test) {
+            $buffer .= "<li><a href='" . $manager->getBaseURL() . "?plugin_group={$group_test}'>" .
+                $group_test . "</a></li>\n";
+        }
+
+        $buffer .= "</ul>\n";
+        return $buffer;
+    }
+
 }
 
 /**
diff --git a/_test/lib/unittest.php b/_test/lib/unittest.php
new file mode 100644
index 0000000000000000000000000000000000000000..220aa6c1bf15484839de5bbf10c70d6c25ebaed3
--- /dev/null
+++ b/_test/lib/unittest.php
@@ -0,0 +1,5 @@
+<?php
+class Doku_UnitTestCase extends UnitTestCase {
+}
+class Doku_GroupTest extends GroupTest {
+}
diff --git a/_test/runtests.php b/_test/runtests.php
index e122c59fb2dbefe61a5cca46f7b4e54bfcdaceea..8b93efec3d8183c2d3354a05a8d666637a78d70a 100755
--- a/_test/runtests.php
+++ b/_test/runtests.php
@@ -21,11 +21,17 @@ passes is printed on STDOUT. If ANY of the test cases fail (or raise
 errors) details are printed on STDERR and this script returns a non-zero
 exit code.
   -c  --case=NAME         specify a test case by it's ID (see -i for list)
+  --pcase=NAME            specify a plugin test case by it's ID 
+                          (see --plugincaselist for list)
   -f  --file=NAME         specify a test case file (full or relative path)
   -g  --group=NAME        specify a grouptest. If no grouptest is
                           specified, all test cases will be run.
+  --pgroup=NAME           specify a plugin grouptest. If no grouptest is
+                          specified, all test cases will be run.
   -i  --caselist          list individual test cases by their ID
   -l  --grouplist         list available grouptests
+  --plugincaselist        list all individual plugin test cases by their ID
+  --plugingrouplist       list avialable plugin grouptests
   -s, --separator=SEP     set the character(s) used to separate fail
                           details to SEP
   -p, --path              path to SimpleTest installation
@@ -40,14 +46,18 @@ EOD;
 $opt_separator = '->';
 $opt_caselist = FALSE;
 $opt_grouplist = FALSE;
+$opt_plugincaselist = FALSE;
+$opt_plugingrouplist = FALSE;
 $opt_caseid = FALSE;
+$top_plugincaseid = FALSE;
 $opt_casefile = FALSE;
 $opt_groupfile = FALSE;
+$opt_plugingroupfile = FALSE;
 
 include_once(DOKU_INC.'inc/cliopts.php');
 
 $short_opts = "c:f:g:hils:p:";
-$long_opts  = array("case=","caselist","help", "file=", "group=", "grouplist", "separator=", "path=");
+$long_opts  = array("case=","pcase=","caselist","help", "file=", "group=", "pgroup=", "grouplist", "plugincaselist", "plugingrouplist", "separator=", "path=");
 $OPTS = Doku_Cli_Opts::getOptions(__FILE__,$short_opts,$long_opts);
 if ( $OPTS->isError() ) {
     fwrite( STDERR, $OPTS->getMessage() . "\n");
@@ -61,6 +71,9 @@ foreach ($OPTS->options as $key => $val) {
         case 'case':
             $opt_caseid = $val;
             break;
+        case 'pcase':
+            $opt_plugincaseid = $val;
+            break;
         case 'h':
         case 'help':
             usage();
@@ -73,6 +86,9 @@ foreach ($OPTS->options as $key => $val) {
         case 'group':
             $opt_groupfile = $val;
             break;
+        case 'pgroup':
+            $opt_plugingroupfile = $val;
+            break;
         case 'i':
         case 'caselist':
             $opt_caselist = TRUE;
@@ -81,6 +97,12 @@ foreach ($OPTS->options as $key => $val) {
         case 'grouplist':
             $opt_grouplist = TRUE;
             break;
+        case 'plugincaselist':
+            $opt_plugincaselist = TRUE;
+            break;
+        case 'plugingrouplist':
+            $opt_plugingrouplist = TRUE;
+            break;
         case 's':
         case 'separator':
             $opt_separator = $val;
@@ -110,8 +132,18 @@ if ($opt_caselist) {
     echo CLITestManager::getTestCaseList(TEST_CASES);
 }
 
+/* list plugin test cases */
+if ($opt_plugincaselist) {
+    echo CLITestManager::getPluginTestCaseList(TEST_PLUGINS);
+}
+
+/* list plugin group tests */
+if($opt_plugingrouplist) {
+    echo CLITestManager::getPluginGroupTestList(TEST_PLUGINS);
+}
+
 /* exit if we've displayed a list */
-if ( $opt_grouplist || $opt_caselist ) {
+if ( $opt_grouplist || $opt_caselist || $opt_plugincaselist || $opt_plugingrouplist ) {
     exit(0);
 }
 
@@ -120,17 +152,35 @@ if ($opt_casefile) {
     TestManager::runTestFile($opt_casefile, new CLIReporter($opt_separator));
     exit(0);
 }
-/* run a test case by id*/
+
+/* run a test case by id */
 if ($opt_caseid) {
     TestManager::runTestCase($opt_caseid, TEST_CASES, new CLIReporter($opt_separator));
     exit(0);
 }
+
+/* run a plugin test by case id */
+if ($opt_plugincaseid) {
+    TestManager::runTestCase($opt_plugincaseid, TEST_PLUGINS, new CLIReporter($opt_separator));
+    exit(0);
+}
+
 /* run a grouptest */
 if ($opt_groupfile) {
     TestManager::runGroupTest($opt_groupfile, TEST_GROUPS,
                               new CLIReporter($opt_separator));
     exit(0);
 }
+
+/* run a plugin grouptest */
+if ($opt_plugingroupfile) {
+    TestManager::runGroupTest($opt_plugingroupfile, TEST_PLUGINS,
+                              new CLIReporter($opt_separator));
+    exit(0);
+}
+
+/* run a plugin group test */
+//FIXME
 /* run all tests */
 TestManager::runAllTests(new CLIReporter($opt_separator));
 exit(0);