Index: modules/simpletest/drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v
retrieving revision 1.182
diff -u -r1.182 drupal_web_test_case.php
--- modules/simpletest/drupal_web_test_case.php	15 Dec 2009 05:25:47 -0000	1.182
+++ modules/simpletest/drupal_web_test_case.php	23 Dec 2009 22:44:51 -0000
@@ -184,12 +184,12 @@
 
   /**
    * Delete an assertion record by message ID.
-   * 
+   *
    * @param $message_id
    *   Message ID of the assertion to delete.
    * @return
    *   TRUE if the assertion was deleted, FALSE otherwise.
-   * 
+   *
    * @see DrupalTestCase::insertAssert()
    */
   public static function deleteAssert($message_id) {
@@ -1094,6 +1094,40 @@
     // Reset all statics so that test is performed with a clean environment.
     drupal_static_reset();
 
+    $this->setUpInstall();
+
+    // Rebuild caches.
+    node_types_rebuild();
+    actions_synchronize();
+    _drupal_flush_css_js();
+    $this->refreshVariables();
+    $this->checkPermissions(array(), TRUE);
+
+    // Log in with a clean $user.
+    $this->originalUser = $user;
+    drupal_save_session(FALSE);
+    $user = user_load(1);
+
+    $this->setUpVariables();
+
+    // Set up English language.
+    unset($GLOBALS['conf']['language_default']);
+    $language = language_default();
+
+    // Set path variables
+    variable_set('file_public_path', $public_files_directory);
+    variable_set('file_private_path', $private_files_directory);
+
+    // Use the test mail class instead of the default mail handler class.
+    variable_set('mail_system', array('default-system' => 'TestingMailSystem'));
+
+    drupal_set_time_limit($this->timeLimit);
+  }
+
+  /**
+   * Perform Drupal installation.
+   */
+  protected function setUpInstall() {
     include_once DRUPAL_ROOT . '/includes/install.inc';
     drupal_install_system();
 
@@ -1125,36 +1159,17 @@
     // Run default profile tasks.
     $install_state = array();
     drupal_install_modules(array('default'), TRUE);
+  }
 
-    // Rebuild caches.
-    node_types_rebuild();
-    actions_synchronize();
-    _drupal_flush_css_js();
-    $this->refreshVariables();
-    $this->checkPermissions(array(), TRUE);
-
-    // Log in with a clean $user.
-    $this->originalUser = $user;
-    drupal_save_session(FALSE);
-    $user = user_load(1);
-
+  /**
+   * Set post-installation variables.
+   */
+  protected function setUpVariables() {
     // Restore necessary variables.
     variable_set('install_profile', 'default');
     variable_set('install_task', 'done');
     variable_set('clean_url', $clean_url_original);
     variable_set('site_mail', 'simpletest@example.com');
-    // Set up English language.
-    unset($GLOBALS['conf']['language_default']);
-    $language = language_default();
-
-    // Set path variables
-    variable_set('file_public_path', $public_files_directory);
-    variable_set('file_private_path', $private_files_directory);
-
-    // Use the test mail class instead of the default mail handler class.
-    variable_set('mail_system', array('default-system' => 'TestingMailSystem'));
-
-    drupal_set_time_limit($this->timeLimit);
   }
 
   /**
@@ -2685,6 +2700,97 @@
 
 }
 
+
+/**
+ * Clone an existing database and use it for testing.
+ */
+class DrupalCloneTestCase extends DrupalWebTestCase {
+
+  /**
+   * The prefix to use as the source of the cloning.
+   *
+   * @var string
+   */
+  protected $clonePrefix = '';
+
+  /**
+   * Tables to exlude during data cloning, only their structure will be cloned.
+   *
+   * @var array
+   */
+  protected $excludeTables = array(
+    'cache',
+    'cache_block',
+    'cache_bootstrap',
+    'cache_field',
+    'cache_filter',
+    'cache_form',
+    'cache_image',
+    'cache_menu',
+    'cache_page',
+    'cache_path',
+    'cache_update',
+    'watchdog',
+  );
+
+  /**
+   * New database prefix created by SimpleTest.
+   *
+   * @var string
+   */
+  protected $db_prefix_new = '';
+
+  protected function setUpInstall() {
+    global $db_prefix;
+
+    // Store new database prefix.
+    $this->db_prefix_new = $db_prefix;
+    $db_prefix = $this->clonePrefix;
+
+    // Rebuild schema based on prefixed database and such.
+    $schemas = drupal_get_schema(NULL, TRUE);
+
+    // Create a list of prefixed source table names.
+    $sources = array();
+    foreach ($schemas as $name => $schema) {
+      $sources[$name] = Database::getConnection()->prefixTables('{' . $name . '}');
+    }
+
+    // Return to new prefix before performing cloning.
+    $db_prefix = $this->db_prefix_new;
+
+    // Clone each table into the new database.
+    foreach ($schemas as $name => $schema) {
+      $this->cloneTable($name, $sources[$name], $schema);
+    }
+  }
+
+  protected function setUpVariables() {
+    // Do nothing.
+  }
+
+  /**
+   * Clone an existing table structure and data.
+   *
+   * @param $name
+   *   Table name.
+   * @param $source
+   *   Source table name.
+   * @param $schema
+   *   A Schema API definition array.
+   */
+  protected function cloneTable($name, $source, $schema) {
+    global $db_prefix;
+
+    db_create_table($name, $schema);
+
+    $target = Database::getConnection()->prefixTables('{' . $name . '}');
+    if (!in_array($name, $this->excludeTables)) {
+      db_query('INSERT INTO ' . $target . ' SELECT * FROM ' . $source);
+    }
+  }
+}
+
 /**
  * Log verbose message in a text file.
  *
