diff --git a/scripts/run-functional-tests.sh b/scripts/run-functional-tests.sh
index 56a0da6d20b78d32d0b116e9fdb82cf229c8a415..669edc8365c00f70b1e3b13dc7ed6d7fe7b3e61d 100755
--- a/scripts/run-functional-tests.sh
+++ b/scripts/run-functional-tests.sh
@@ -4,30 +4,93 @@
 
 /**
  * @file
- * This script can be run with browser or from command line.
- * You can provide class names of the tests you wish to run.
- * When this script is run from browser you can select which reporter to use html or xml.
- * For command line: php run_functional_tests.php SearchMatchTest,ProfileModuleTestSingle
- * For browser: http://yoursite.com/sites/all/modules/simpletest/run_all_tests.php?include=SearchMatchTest,ProfileModuleTestSingle&reporter=html
- * If none of these two options are provided all tests will be run.
+ * This script runs Drupal tests from command line.
+ * You can provide groups or class names of the tests you wish to run.
+ * For example: php scripts/run-functional-tests.sh Profile
+ * If no arguments are provided, the help text will print.
  */
 
-$tests = NULL;
 $reporter = 'text';
+$test_names = array();
 $host = 'localhost';
 $path = '';
-array_shift($_SERVER['argv']); // throw away script name
+$script = basename(array_shift($_SERVER['argv']));
+
+if (in_array('--help', $_SERVER['argv']) || empty($_SERVER['argv'])) {
+  echo <<<EOF
+
+Run Drupal tests from the shell.
+
+Usage:        {$script} [OPTIONS] <tests>
+Example:      {$script} Profile
+
+All arguments are long options.
+
+  --help      Print this page.
+  
+  --clean     Cleans up database tables or directories from previous, failed,
+              tests and then exits (no tests are run).
+
+   --url      Immediately preceeds a URL to set the host and path. You will
+              need this parameter if Drupal is in a subdirectory on your 
+              localhost and you have not set \$base_url in settings.php.
+
+   --reporter Immediatly preceeds the name of the output reporter to use.  This 
+              Defaults to "text", while other options include "xml" and "html".
+
+   --all      Run all available tests.
+
+   --class    Run tests identified by speficic class names.
+
+  <test1>[,<test2>[,<test3> ...]]
+
+              One or more tests to be run.  By default, these are interpreted
+              as the names of test groups as shown at ?q=admin/build/testing.
+              These group names typically correspond to module names like "User"
+              or "Profile" or "System", but there is also a group "XML-RPC".
+              If --class is specified then these are interpreted as the names of
+              specific test classes whose test methods will be run.  Tests must
+              be separated by commas.  Ignored if --all is specified.
+
+To run this script you will normally invoke it from the root directory of your 
+Drupal installation as
+
+php  ./scripts/{$script}
+\n
+EOF;
+  exit;
+}
+
+$clean = FALSE;
+$all = FALSE;
+$class_names = FALSE;
+$test_names = array();
+
 while ($param = array_shift($_SERVER['argv'])) {
   switch ($param) {
     case '--url':
       $url = array_shift($_SERVER['argv']);
-      $parse = parse_url($url);
-      $host = $parse['host'];
-      $path = $parse['path'];
+      $parsed = parse_url($url);
+      $host = $parsed['host'];
+      $path = $parsed['path'];
+      break;
+    case '--all':
+      $all = TRUE;
+      break;
+    case '--class':
+      $class_names = TRUE;
+      break;
+    case '--clean':
+      $clean = TRUE;
+      break;
+    case '--reporter':
+      $reporter = array_shift($_SERVER['argv']);
+      if (!in_array($reporter, array("text", "xml", "html"))) {
+        $reporter = "text";
+      }
       break;
-
     default:
-      $tests = explode(',', $param);
+      $test_names += explode(',', $param);
       break;
   }
 }
@@ -46,13 +109,102 @@
 require_once './includes/bootstrap.inc';
 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
-//load simpletest files
-simpletest_load();
+if (!module_exists('simpletest')) {
+  echo("ERROR: The simpletest module must be enabled before this script can run.\n");
+  exit;
+}
+
+if ($clean) {
+  // Clean up left-over times and directories.
+  simpletest_clean_environment();
+  // Get the status messages and print them.
+  $messages = array_pop(drupal_get_messages('status'));
+  foreach($messages as $text) {
+    echo("- " . $text . "\n");
+  }
+  exit;
+}
+
+// Run tests as user #1.
+$GLOBALS['user'] = user_load(1);
+
+//Load simpletest files
+$total_test = &simpletest_get_total_test();
+
+$test_instances = $total_test->getTestInstances();
+
+if ($all) {
+  $test_list = NULL;
+}
+else {
+  if ($class_names) {
+    $test_list = _run_tests_check_classes($test_names, $test_instances);
+  }
+  else {
+    $test_list = _run_tests_find_classes($test_names, $test_instances);
+  }
+}
+if (empty($test_list) && !$all) {
+  echo("ERROR: No valid tests were specified.\n");
+  exit;
+}
+
 
 // If not in 'safe mode', increase the maximum execution time:
 if (!ini_get('safe_mode')) {
   set_time_limit(360);
 }
 
-simpletest_run_tests($tests, $reporter);
-?>
+// Tell the user about what tests are to be run.
+if (!$all && $reporter == 'text') {
+  echo("Tests to be run:\n");
+  foreach ($test_list as $name) {
+    echo("- " . $name . "\n");
+  }
+  echo("\n");
+}
+
+simpletest_run_tests(array_keys($test_list), $reporter);
+
+// Utility functions:
+/**
+ * Check that each class name exists as a test, return the list of valid ones.
+ */
+function _run_tests_check_classes($test_names, $test_instances) {
+  $test_list = array();
+  $test_names = array_flip($test_names);
+
+  foreach ($test_instances as $group_test) {
+    $tests = $group_test->getTestInstances();
+    foreach ($tests as $test) {
+      $class = get_class($test);
+      $info = $test->getInfo();
+      if (isset($test_names[$class])) {
+        $test_list[$class] = $info['name'];
+      }
+    }
+  }
+  return $test_list;
+}
+
+/**
+ * Check that each group name exists, return the list of class in valid groups.
+ */
+function _run_tests_find_classes($test_names, &$test_instances) {
+  $test_list = array();
+  $test_names = array_flip($test_names);
+
+  uasort($test_instances, 'simpletest_compare_instances');
+  foreach ($test_instances as $group_test) {
+    $group = $group_test->getLabel();
+    if (isset($test_names[$group])) {
+      $tests = $group_test->getTestInstances();
+      foreach ($tests as $test) {
+        $info = $test->getInfo();
+        $test_list[get_class($test)] = $info['name'];
+      }
+    }
+  }
+  return $test_list;
+}
+