diff --git a/drupal_web_test_case.php b/drupal_web_test_case.php index f28c3b9..1a97e1b 100644 --- a/drupal_web_test_case.php +++ b/drupal_web_test_case.php @@ -224,9 +224,9 @@ abstract class DrupalTestCase { // The first element is the call. The second element is the caller. // We skip calls that occurred in one of the methods of our base classes // or in an assertion function. - while (($caller = $backtrace[1]) && - ((isset($caller['class']) && isset($this->skipClasses[$caller['class']])) || - substr($caller['function'], 0, 6) == 'assert')) { + while (($caller = $backtrace[1]) && + ((isset($caller['class']) && isset($this->skipClasses[$caller['class']])) || + substr($caller['function'], 0, 6) == 'assert')) { // We remove that call. array_shift($backtrace); } @@ -1244,14 +1244,42 @@ class DrupalWebTestCase extends DrupalTestCase { ini_set('log_errors', 1); ini_set('error_log', $public_files_directory . '/error.log'); - // Reset all statics and variables to perform tests in a clean environment. - $conf = array(); - // Set the test information for use in other parts of Drupal. $test_info = &$GLOBALS['drupal_test_info']; $test_info['test_run_id'] = $this->databasePrefix; $test_info['in_child_site'] = FALSE; + $this->setUpInstall(func_get_args(), $public_files_directory, $temp_files_directory); + + // Log in with a clean $user. + $this->originalUser = $user; + session_save_session(FALSE); + $user = user_load(array('uid' => 1)); + + // Restore necessary variables. + 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(); + + // Use the test mail class instead of the default mail handler class. + variable_set('smtp_library', drupal_get_path('module', 'simpletest') . '/simpletest.mail.inc'); + + set_time_limit($this->timeLimit); + } + + /** + * Perform Drupal installation. + */ + protected function setUpInstall(array $modules, $public_files_directory, $temp_files_directory) { + global $conf; + + // Reset all statics and variables to perform tests in a clean environment. + $conf = array(); + include_once './includes/install.inc'; drupal_install_system(); @@ -1270,7 +1298,6 @@ class DrupalWebTestCase extends DrupalTestCase { // either a single array argument or a variable number of string arguments. // @todo Remove this compatibility layer in Drupal 8, and only accept // $modules as a single array argument. - $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; } @@ -1291,25 +1318,6 @@ class DrupalWebTestCase extends DrupalTestCase { // Run cron once in that environment, as install.php does at the end of // the installation process. drupal_cron_run(); - - // Log in with a clean $user. - $this->originalUser = $user; - session_save_session(FALSE); - $user = user_load(array('uid' => 1)); - - // Restore necessary variables. - 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(); - - // Use the test mail class instead of the default mail handler class. - variable_set('smtp_library', drupal_get_path('module', 'simpletest') . '/simpletest.mail.inc'); - - set_time_limit($this->timeLimit); } /** @@ -3132,3 +3140,104 @@ function simpletest_verbose($message, $original_file_directory = NULL, $test_cla } return FALSE; } + +/** + * Clone an existing database and use it for testing. + */ +class DrupalCloneTestCase extends DrupalWebTestCase { + + /** + * Tables to exlude during data cloning, only their structure will be cloned. + * + * @var array + */ + protected $excludeTables = array( + 'cache', + 'cache_block', + 'cache_content', + 'cache_filter', + 'cache_form', + 'cache_menu', + 'cache_page', + 'cache_update', + 'watchdog', + ); + + /** + * Perform Drupal installation. + */ + protected function setUpInstall() { + global $db_prefix; + + // Store new database prefix. + $db_prefix_new = $db_prefix; + $db_prefix = $this->originalPrefix; + + // 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] = $this->prefixTable($db_prefix, $name); + } + + // Return to new prefix before performing cloning. + $db_prefix = $db_prefix_new; + + // Clone each table into the new database. + foreach ($schemas as $name => $schema) { + $this->cloneTable($name, $sources[$name], $schema); + } + } + + /** + * 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) { + $ret = array(); + db_create_table($ret, $name, $schema); + + $target = $this->prefixTable($this->databasePrefix, $name); + if (!in_array($name, $this->excludeTables)) { + if ($name == 'users') { + db_query('INSERT INTO ' . $target . ' SELECT * FROM ' . $source . ' WHERE uid <> 1'); + } + else { + db_query('INSERT INTO ' . $target . ' SELECT * FROM ' . $source); + } + } + } + + /** + * Correctly prefix a table name. + * + * This code is based off of core's db_prefix_tables(). + * + * @param $db_prefix + * Mixed array or string with prefixes. + * @param $name + * String with the table name. + * @return + * String with prefixed table name. + */ + protected function prefixTable($db_prefix, $name) { + if (is_array($db_prefix)) { + if (array_key_exists($name, $db_prefix)) { + return $db_prefix[$name] . $name; + } + elseif (array_key_exists('default', $db_prefix)) { + return $db_prefix['default'] . $name; + } + return $name; + } + return $db_prefix . $name; + } + +}