diff --git a/.htaccess b/.htaccess index 0c89072..f0c5d96 100644 --- a/.htaccess +++ b/.htaccess @@ -108,7 +108,7 @@ DirectoryIndex index.php index.html index.htm RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} !=/favicon.ico - RewriteRule ^ index.php [L] + RewriteRule ^(.*)$ index.php [L] # Rules to correctly serve gzip compressed CSS and JS files. # Requires both mod_rewrite and mod_headers to be enabled. diff --git a/core/CHANGELOG.txt b/core/CHANGELOG.txt index 88ea516..562e3b0 100644 --- a/core/CHANGELOG.txt +++ b/core/CHANGELOG.txt @@ -1,10 +1,6 @@ Drupal 8.0, xxxx-xx-xx (development version) ---------------------- -- Configuration: - * Added a centralized file-based configuration system. - * Allows module authors to provide configuration in a standard format. - * Implements functionality to get, set, add and remove configuration. - Included the HTML5 Shiv library to support HTML5 elements in IE 8 and below. - Included the following Symfony2 components: * ClassLoader - PSR-0-compatible autoload routines. diff --git a/core/authorize.php b/core/authorize.php index d703b33..fd0774d 100644 --- a/core/authorize.php +++ b/core/authorize.php @@ -84,10 +84,7 @@ module_list(TRUE, FALSE, FALSE, $module_list); drupal_load('module', 'system'); drupal_load('module', 'user'); -// We also want to have the language system available, but we do *NOT* want to -// actually call drupal_bootstrap(DRUPAL_BOOTSTRAP_LANGUAGE), since that would -// also force us through the DRUPAL_BOOTSTRAP_PAGE_HEADER phase, which loads -// all the modules, and that's exactly what we're trying to avoid. +// Initialize the language system. drupal_language_initialize(); // Initialize the maintenance theme for this administrative script. diff --git a/core/includes/batch.inc b/core/includes/batch.inc index 83ddd30..0b07d8e 100644 --- a/core/includes/batch.inc +++ b/core/includes/batch.inc @@ -14,6 +14,8 @@ * @see batch_get() */ +use \Symfony\Component\HttpFoundation\JsonResponse; + /** * Loads a batch from the database. * @@ -77,7 +79,7 @@ function _batch_page() { case 'do': // JavaScript-based progress page callback. - _batch_do(); + $output = _batch_do(); break; case 'do_nojs': @@ -160,7 +162,7 @@ function _batch_do() { // Perform actual processing. list($percentage, $message) = _batch_process(); - drupal_json_output(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message)); + return new JsonResponse(array('status' => TRUE, 'percentage' => $percentage, 'message' => $message)); } /** diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index f65ab4c..4e22259 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -4,6 +4,7 @@ use Drupal\Core\Database\Database; use Symfony\Component\ClassLoader\UniversalClassLoader; use Symfony\Component\ClassLoader\ApcUniversalClassLoader; use Drupal\Core\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpFoundation\Request; /** * @file @@ -137,12 +138,13 @@ const DRUPAL_BOOTSTRAP_SESSION = 4; const DRUPAL_BOOTSTRAP_PAGE_HEADER = 5; /** - * Seventh bootstrap phase: find out language of the page. + * Seventh bootstrap phase: load code for subsystems and modules; validate and + * fix input data. */ -const DRUPAL_BOOTSTRAP_LANGUAGE = 6; +const DRUPAL_BOOTSTRAP_CODE = 6; /** - * Final bootstrap phase: Drupal is fully loaded; validate and fix input data. + * Final bootstrap phase: initialize language, path, theme, and modules. */ const DRUPAL_BOOTSTRAP_FULL = 7; @@ -1535,6 +1537,29 @@ function request_uri($omit_query_string = FALSE) { } /** + * Returns the current global request object. + * + * @todo Replace this function with a proper dependency injection container. + * + * @staticvar Symfony\Component\HttpFoundation\Request $request + * + * @param Symfony\Component\HttpFoundation\Request $new_request + * Optional. The new request object to store. This parameter should only be + * used by index.php. + * + * @return Symfony\Component\HttpFoundation\Request + * The current request object. + */ +function request(Request $new_request = NULL) { + static $request; + + if ($new_request) { + $request = $new_request; + } + return $request; +} + +/** * Logs an exception. * * This is a wrapper function for watchdog() which automatically decodes an @@ -2023,7 +2048,7 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) { DRUPAL_BOOTSTRAP_VARIABLES, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_PAGE_HEADER, - DRUPAL_BOOTSTRAP_LANGUAGE, + DRUPAL_BOOTSTRAP_CODE, DRUPAL_BOOTSTRAP_FULL, ); // Not drupal_static(), because the only legitimate API to control this is to @@ -2076,12 +2101,12 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) { _drupal_bootstrap_page_header(); break; - case DRUPAL_BOOTSTRAP_LANGUAGE: - drupal_language_initialize(); + case DRUPAL_BOOTSTRAP_CODE: + require_once DRUPAL_ROOT . '/core/includes/common.inc'; + _drupal_bootstrap_code(); break; case DRUPAL_BOOTSTRAP_FULL: - require_once DRUPAL_ROOT . '/core/includes/common.inc'; _drupal_bootstrap_full(); break; } @@ -2301,11 +2326,6 @@ function _drupal_bootstrap_variables() { */ function _drupal_bootstrap_page_header() { bootstrap_invoke_all('boot'); - - if (!drupal_is_cli()) { - ob_start(); - drupal_page_header(); - } } /** diff --git a/core/includes/common.inc b/core/includes/common.inc index 14154af..8437eff 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -1,5 +1,7 @@ uid == 0) || ($token == drupal_get_token($value))); } -function _drupal_bootstrap_full() { +function _drupal_bootstrap_code() { static $called = FALSE; if ($called) { @@ -5195,6 +5205,24 @@ function _drupal_bootstrap_full() { ini_set('log_errors', 1); ini_set('error_log', 'public://error.log'); } +} + +/** + * Temporary BC function for scripts not using DrupalKernel. + * + * DrupalKernel skips this and replicates it via event listeners. + */ +function _drupal_bootstrap_full($skip = FALSE) { + static $called = FALSE; + + if ($called || $skip) { + $called = TRUE; + return; + } + + // Initialize language (which can strip path prefix) prior to initializing + // current_path(). + drupal_language_initialize(); // Initialize current_path() prior to invoking hook_init(). drupal_path_initialize(); @@ -5228,7 +5256,7 @@ function _drupal_bootstrap_full() { * * @see drupal_page_header() */ -function drupal_page_set_cache() { +function drupal_page_set_cache($response_body) { global $base_root; if (drupal_page_is_cacheable()) { diff --git a/core/includes/config.inc b/core/includes/config.inc index 78d12e8..5e6fa00 100644 --- a/core/includes/config.inc +++ b/core/includes/config.inc @@ -1,6 +1,6 @@ write(file_get_contents($module_config_dir . '/' . $file)); + $verified_storage = new DrupalVerifiedStorageSQL($config_name); + $verified_storage->write(file_get_contents($module_config_dir . '/' . $file)); } } } @@ -88,8 +88,8 @@ function config_get_files_with_prefix($prefix = '') { * @return * @todo */ -function config_get_storage_names_with_prefix($prefix = '') { - return DatabaseStorage::getNamesWithPrefix($prefix); +function config_get_verified_storage_names_with_prefix($prefix = '') { + return DrupalVerifiedStorageSQL::getNamesWithPrefix($prefix); } /** @@ -114,7 +114,7 @@ function config_get_storage_names_with_prefix($prefix = '') { * alternate storage engines.. */ function config($name, $class = 'Drupal\Core\Config\DrupalConfig') { - return new $class(new DatabaseStorage($name)); + return new $class(new DrupalVerifiedStorageSQL($name)); } /** diff --git a/core/includes/errors.inc b/core/includes/errors.inc index 0524170..97f5b6a 100644 --- a/core/includes/errors.inc +++ b/core/includes/errors.inc @@ -5,6 +5,8 @@ * Functions for error handling. */ +use Symfony\Component\HttpFoundation\Response; + /** * Error reporting level: display no errors. */ @@ -215,10 +217,6 @@ function _drupal_log_error($error, $fatal = FALSE) { watchdog('php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']); - if ($fatal) { - drupal_add_http_header('Status', '500 Service unavailable (with message)'); - } - if (drupal_is_cli()) { if ($fatal) { // When called from CLI, simply output a plain text message. @@ -254,8 +252,14 @@ function _drupal_log_error($error, $fatal = FALSE) { drupal_set_title(t('Error')); // We fallback to a maintenance page at this point, because the page generation // itself can generate errors. - print theme('maintenance_page', array('content' => t('The website encountered an unexpected error. Please try again later.'))); - exit; + $output = theme('maintenance_page', array('content' => t('The website encountered an unexpected error. Please try again later.'))); + + $response = new Response($output, 500); + if ($fatal) { + $response->setStatusCode(500, '500 Service unavailable (with message)'); + } + + return $response; } } } diff --git a/core/includes/file.inc b/core/includes/file.inc index b476bc7..7edd4be 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -5,6 +5,9 @@ * API for handling file uploads and server file management. */ +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpFoundation\StreamedResponse; use Drupal\Core\StreamWrapper\LocalStream; /** @@ -2046,18 +2049,27 @@ function file_download() { $function = $module . '_file_download'; $result = $function($uri); if ($result == -1) { - return drupal_access_denied(); + throw new AccessDeniedHttpException(); } if (isset($result) && is_array($result)) { $headers = array_merge($headers, $result); } } if (count($headers)) { - file_transfer($uri, $headers); + return new StreamedResponse(function() use ($uri) { + $scheme = file_uri_scheme($uri); + // Transfer file in 1024 byte chunks to save memory usage. + if ($scheme && file_stream_wrapper_valid_scheme($scheme) && $fd = fopen($uri, 'rb')) { + while (!feof($fd)) { + print fread($fd, 1024); + } + fclose($fd); + } + }, 200, $headers); } - return drupal_access_denied(); + throw new AccessDeniedHttpException(); } - return drupal_not_found(); + throw new NotFoundHttpException(); } diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index 31ef052..dea784b 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -3,6 +3,9 @@ use Drupal\Core\Database\Database; use Drupal\Core\Database\Install\TaskException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + /** * @file * API functions for installing Drupal. @@ -241,6 +244,14 @@ function install_begin_request(&$install_state) { drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); + // A request object from the HTTPFoundation to tell us about the request. + $request = Request::createFromGlobals(); + + // Set the global $request object. This is a temporary measure to + // keep legacy utility functions working. It should be moved to a dependency + // injection container at some point. + request($request); + // This must go after drupal_bootstrap(), which unsets globals! global $conf; @@ -468,6 +479,15 @@ function install_run_task($task, &$install_state) { elseif ($current_batch == $function) { include_once DRUPAL_ROOT . '/core/includes/batch.inc'; $output = _batch_page(); + // Because Batch API now returns a JSON response for intermediary steps, + // but the installer doesn't handle Response objects yet, just send the + // output here and emulate the old model. + // @todo Replace this when we refactor the installer to use a request- + // response workflow. + if ($output instanceof Response) { + $output->send(); + $output = NULL; + } // The task is complete when we try to access the batch page and receive // FALSE in return, since this means we are at a URL where we are no // longer requesting a batch ID. diff --git a/core/includes/update.inc b/core/includes/update.inc index fb6f450..e5c62d8 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -321,11 +321,9 @@ function update_module_enable(array $modules) { * will be displayed at all. * * If it fails for whatever reason, it should throw an instance of - * Drupal\Core\Utility\UpdateException with an appropriate error message, for - * example: + * DrupalUpdateException with an appropriate error message, for example: * @code - * use Drupal\Core\Utility\UpdateException; - * throw new UpdateException(t('Description of what went wrong')); + * throw new DrupalUpdateException(t('Description of what went wrong')); * @endcode * * If an exception is thrown, the current update and all updates that depend on @@ -406,6 +404,11 @@ function update_do_one($module, $number, $dependency_map, &$context) { } /** + * @class Exception class used to throw error if a module update fails. + */ +class DrupalUpdateException extends Exception { } + +/** * Start the database update batch process. * * @param $start diff --git a/core/lib/Drupal/Core/Config/FileStorageException.php b/core/lib/Drupal/Core/Config/ConfigFileStorageException.php similarity index 61% rename from core/lib/Drupal/Core/Config/FileStorageException.php rename to core/lib/Drupal/Core/Config/ConfigFileStorageException.php index bf3ae5f..ce7fb30 100644 --- a/core/lib/Drupal/Core/Config/FileStorageException.php +++ b/core/lib/Drupal/Core/Config/ConfigFileStorageException.php @@ -7,4 +7,4 @@ use Drupal\Core\Config\ConfigException; /** * @todo */ -class FileStorageException extends ConfigException {} +class ConfigFileStorageException extends ConfigException {} diff --git a/core/lib/Drupal/Core/Config/ConfigFileStorageReadException.php b/core/lib/Drupal/Core/Config/ConfigFileStorageReadException.php new file mode 100644 index 0000000..a3ac95c --- /dev/null +++ b/core/lib/Drupal/Core/Config/ConfigFileStorageReadException.php @@ -0,0 +1,10 @@ +storage = $storage; + public function __construct(DrupalConfigVerifiedStorageInterface $verified_storage) { + $this->_verifiedStorage = $verified_storage; $this->read(); } @@ -36,7 +36,7 @@ class DrupalConfig { * Reads config data from the active store into our object. */ public function read() { - $active = (array) config_decode($this->storage->read()); + $active = (array) config_decode($this->_verifiedStorage->read()); foreach ($active as $key => $value) { // If the setting is empty, return an empty string rather than an array. // This is necessary because SimpleXML's default behavior is to return @@ -89,7 +89,7 @@ class DrupalConfig { public function get($key = '') { global $conf; - $name = $this->storage->getName(); + $name = $this->_verifiedStorage->getName(); if (isset($conf[$name])) { $merged_data = drupal_array_merge_deep($this->data, $conf[$name]); } @@ -201,7 +201,7 @@ class DrupalConfig { * Saves the configuration object to disk as XML. */ public function save() { - $this->storage->write(config_encode($this->data)); + $this->_verifiedStorage->write(config_encode($this->data)); } /** @@ -209,6 +209,6 @@ class DrupalConfig { */ public function delete() { $this->data = array(); - $this->storage->delete(); + $this->_verifiedStorage->delete(); } } diff --git a/core/lib/Drupal/Core/Config/StorageBase.php b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorage.php similarity index 68% rename from core/lib/Drupal/Core/Config/StorageBase.php rename to core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorage.php index 7846aed..56cd16d 100644 --- a/core/lib/Drupal/Core/Config/StorageBase.php +++ b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorage.php @@ -2,13 +2,13 @@ namespace Drupal\Core\Config; -use Drupal\Core\Config\StorageInterface; +use Drupal\Core\Config\DrupalConfigVerifiedStorageInterface; use Drupal\Core\Config\FileStorage; /** * @todo */ -abstract class StorageBase implements StorageInterface { +abstract class DrupalConfigVerifiedStorage implements DrupalConfigVerifiedStorageInterface { protected $name; @@ -20,7 +20,7 @@ abstract class StorageBase implements StorageInterface { protected $fileStorage; /** - * Implements StorageInterface::__construct(). + * Implements DrupalConfigVerifiedStorageInterface::__construct(). */ function __construct($name) { $this->name = $name; @@ -40,21 +40,21 @@ abstract class StorageBase implements StorageInterface { } /** - * Implements StorageInterface::copyToFile(). + * Implements DrupalConfigVerifiedStorageInterface::copyToFile(). */ public function copyToFile() { return $this->writeToFile($this->read()); } /** - * Implements StorageInterface::deleteFile(). + * Implements DrupalConfigVerifiedStorageInterface::deleteFile(). */ public function deleteFile() { return $this->fileStorage()->delete(); } /** - * Implements StorageInterface::copyFromFile(). + * Implements DrupalConfigVerifiedStorageInterface::copyFromFile(). */ public function copyFromFile() { return $this->writeToActive($this->readFromFile()); @@ -71,14 +71,14 @@ abstract class StorageBase implements StorageInterface { } /** - * Implements StorageInterface::isOutOfSync(). + * Implements DrupalConfigVerifiedStorageInterface::isOutOfSync(). */ public function isOutOfSync() { return $this->read() !== $this->readFromFile(); } /** - * Implements StorageInterface::write(). + * Implements DrupalConfigVerifiedStorageInterface::write(). */ public function write($data) { $this->writeToActive($data); @@ -86,14 +86,14 @@ abstract class StorageBase implements StorageInterface { } /** - * Implements StorageInterface::writeToFile(). + * Implements DrupalConfigVerifiedStorageInterface::writeToFile(). */ public function writeToFile($data) { return $this->fileStorage()->write($data); } /** - * Implements StorageInterface::delete(). + * Implements DrupalConfigVerifiedStorageInterface::delete(). */ public function delete() { $this->deleteFromActive(); @@ -101,7 +101,7 @@ abstract class StorageBase implements StorageInterface { } /** - * Implements StorageInterface::getName(). + * Implements DrupalConfigVerifiedStorageInterface::getName(). */ public function getName() { return $this->name; diff --git a/core/lib/Drupal/Core/Config/StorageInterface.php b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php similarity index 69% rename from core/lib/Drupal/Core/Config/StorageInterface.php rename to core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php index f1e8a3d..8048e35 100644 --- a/core/lib/Drupal/Core/Config/StorageInterface.php +++ b/core/lib/Drupal/Core/Config/DrupalConfigVerifiedStorageInterface.php @@ -3,15 +3,15 @@ namespace Drupal\Core\Config; /** - * Defines an interface for configuration storage manipulation. + * Defines an interface for verified storage manipulation. * * This class allows reading and writing configuration data from/to the - * storage and copying to/from the file storing the same data. + * verified storage and copying to/from the file storing the same data. */ -interface StorageInterface { +interface DrupalConfigVerifiedStorageInterface { /** - * Constructs a storage manipulation class. + * Constructs a verified storage manipulation class. * * @param $name * Lowercase string, the name for the configuration data. @@ -19,17 +19,17 @@ interface StorageInterface { function __construct($name); /** - * Reads the configuration data from the storage. + * Reads the configuration data from the verified storage. */ function read(); /** - * Copies the configuration data from the storage into a file. + * Copies the configuration data from the verified storage into a file. */ function copyToFile(); /** - * Copies the configuration data from the file into the storage. + * Copies the configuration data from the file into the verified storage. */ function copyFromFile(); @@ -39,10 +39,10 @@ interface StorageInterface { function deleteFile(); /** - * Checks whether the file and the storage is in sync. + * Checks whether the file and the verified storage is in sync. * * @return - * TRUE if the file and the storage contains the same data, FALSE + * TRUE if the file and the verified storage contains the same data, FALSE * if not. */ function isOutOfSync(); diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DrupalVerifiedStorageSQL.php similarity index 78% rename from core/lib/Drupal/Core/Config/DatabaseStorage.php rename to core/lib/Drupal/Core/Config/DrupalVerifiedStorageSQL.php index 63ae7b4..97d499a 100644 --- a/core/lib/Drupal/Core/Config/DatabaseStorage.php +++ b/core/lib/Drupal/Core/Config/DrupalVerifiedStorageSQL.php @@ -2,16 +2,16 @@ namespace Drupal\Core\Config; -use Drupal\Core\Config\StorageBase; +use Drupal\Core\Config\DrupalConfigVerifiedStorage; use Exception; /** * Represents an SQL-based configuration storage object. */ -class DatabaseStorage extends StorageBase { +class DrupalVerifiedStorageSQL extends DrupalConfigVerifiedStorage { /** - * Overrides StorageBase::read(). + * Overrides DrupalConfigVerifiedStorage::read(). */ public function read() { // There are situations, like in the installer, where we may attempt a @@ -26,7 +26,7 @@ class DatabaseStorage extends StorageBase { } /** - * Implements StorageInterface::writeToActive(). + * Implements DrupalConfigVerifiedStorageInterface::writeToActive(). */ public function writeToActive($data) { return db_merge('config') @@ -45,7 +45,7 @@ class DatabaseStorage extends StorageBase { } /** - * Implements StorageInterface::getNamesWithPrefix(). + * Implements DrupalConfigVerifiedStorageInterface::getNamesWithPrefix(). */ static public function getNamesWithPrefix($prefix = '') { return db_query('SELECT name FROM {config} WHERE name LIKE :name', array(':name' => db_like($prefix) . '%'))->fetchCol(); diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php index e65e168..77b8db5 100644 --- a/core/lib/Drupal/Core/Config/FileStorage.php +++ b/core/lib/Drupal/Core/Config/FileStorage.php @@ -32,7 +32,7 @@ class FileStorage { protected function readData() { $data = file_get_contents($this->getFilePath()); if ($data === FALSE) { - throw new FileStorageReadException('Read file is invalid.'); + throw new \Exception('Read file is invalid.'); } return $data; } @@ -68,7 +68,7 @@ class FileStorage { */ public function write($data) { if (!file_put_contents($this->getFilePath(), $data)) { - throw new FileStorageException('Failed to write configuration file: ' . $this->getFilePath()); + throw new \Exception('Failed to write configuration file: ' . $this->getFilePath()); } } diff --git a/core/lib/Drupal/Core/Config/FileStorageReadException.php b/core/lib/Drupal/Core/Config/FileStorageReadException.php deleted file mode 100644 index d613666..0000000 --- a/core/lib/Drupal/Core/Config/FileStorageReadException.php +++ /dev/null @@ -1,10 +0,0 @@ -. + if ($request->get('ajax_iframe_upload', FALSE)) { + return 'iframeupload'; + } + + // AJAX calls need to be run through ajax rendering functions + elseif ($request->isXmlHttpRequest()) { + return 'ajax'; + } + + foreach ($request->getAcceptableContentTypes() as $mime_type) { + $format = $request->getFormat($mime_type); + if (!is_null($format)) { + return $format; + } + } + + // Do HTML last so that it always wins. + return 'html'; + } +} diff --git a/core/lib/Drupal/Core/Database/Connection.php b/core/lib/Drupal/Core/Database/Connection.php index 3805864..dbf7c36 100644 --- a/core/lib/Drupal/Core/Database/Connection.php +++ b/core/lib/Drupal/Core/Database/Connection.php @@ -524,15 +524,14 @@ abstract class Connection extends PDO { } catch (PDOException $e) { if ($options['throw_exception']) { - // Add additional debug information. - if ($query instanceof DatabaseStatementInterface) { - $e->query_string = $stmt->getQueryString(); - } - else { - $e->query_string = $query; - } - $e->args = $args; - throw $e; + // Wrap the exception in another exception, because PHP does not allow + // overriding Exception::getMessage(). Its message is the extra database + // debug information. + $query_string = ($query instanceof DatabaseStatementInterface) ? $stmt->getQueryString() : $query; + $message = $e->getMessage() . ": " . $query_string . "; " . print_r($args, TRUE); + $exception = new DatabaseExceptionWrapper($message, 0, $e); + + throw $exception; } return NULL; } diff --git a/core/lib/Drupal/Core/Database/DatabaseExceptionWrapper.php b/core/lib/Drupal/Core/Database/DatabaseExceptionWrapper.php new file mode 100644 index 0000000..701262a --- /dev/null +++ b/core/lib/Drupal/Core/Database/DatabaseExceptionWrapper.php @@ -0,0 +1,19 @@ +query('RELEASE SAVEPOINT ' . $name); } - catch (PDOException $e) { + catch (DatabaseExceptionWrapper $e) { // However, in MySQL (InnoDB), savepoints are automatically committed // when tables are altered or created (DDL transactions are not // supported). This can cause exceptions due to trying to release @@ -188,7 +190,7 @@ class Connection extends DatabaseConnection { // // To avoid exceptions when no actual error has occurred, we silently // succeed for MySQL error code 1305 ("SAVEPOINT does not exist"). - if ($e->errorInfo[1] == '1305') { + if ($e->getPrevious()->errorInfo[1] == '1305') { // If one SAVEPOINT was released automatically, then all were. // Therefore, clean the transaction stack. $this->transactionLayers = array(); diff --git a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php index a8bdaa9..129ca42 100644 --- a/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/pgsql/Connection.php @@ -157,12 +157,18 @@ class Connection extends DatabaseConnection { } public function mapConditionOperator($operator) { - static $specials = array( - // In PostgreSQL, 'LIKE' is case-sensitive. For case-insensitive LIKE - // statements, we need to use ILIKE instead. - 'LIKE' => array('operator' => 'ILIKE'), - 'NOT LIKE' => array('operator' => 'NOT ILIKE'), - ); + static $specials; + + // Function calls not allowed in static declarations, thus this method. + if (!isset($specials)) { + $specials = array( + // In PostgreSQL, 'LIKE' is case-sensitive. For case-insensitive LIKE + // statements, we need to use ILIKE instead. + 'LIKE' => array('operator' => 'ILIKE'), + 'NOT LIKE' => array('operator' => 'NOT ILIKE'), + ); + } + return isset($specials[$operator]) ? $specials[$operator] : NULL; } diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php new file mode 100644 index 0000000..dc6762b --- /dev/null +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -0,0 +1,90 @@ +dispatcher = $dispatcher; + $this->resolver = $resolver; + + $this->matcher = new UrlMatcher(); + $this->dispatcher->addSubscriber(new RouterListener($this->matcher)); + + $negotiation = new ContentNegotiation(); + + // @todo Make this extensible rather than just hard coding some. + // @todo Add a subscriber to handle other things, too, like our Ajax + // replacement system. + $this->dispatcher->addSubscriber(new ViewSubscriber($negotiation)); + $this->dispatcher->addSubscriber(new AccessSubscriber()); + $this->dispatcher->addSubscriber(new MaintenanceModeSubscriber()); + $this->dispatcher->addSubscriber(new PathSubscriber()); + $this->dispatcher->addSubscriber(new LegacyRequestSubscriber()); + $this->dispatcher->addSubscriber(new LegacyControllerSubscriber()); + $this->dispatcher->addSubscriber(new FinishResponseSubscriber()); + $this->dispatcher->addSubscriber(new RequestCloseSubscriber()); + + // Some other form of error occured that wasn't handled by another kernel + // listener. That could mean that it's a method/mime-type/error + // combination that is not accounted for, or some other type of error. + // Either way, treat it as a server-level error and return an HTTP 500. + // By default, this will be an HTML-type response because that's a decent + // best guess if we don't know otherwise. + $this->dispatcher->addSubscriber(new ExceptionListener(array(new ExceptionController($this, $negotiation), 'execute'))); + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/AccessSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/AccessSubscriber.php new file mode 100644 index 0000000..683f1fb --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/AccessSubscriber.php @@ -0,0 +1,53 @@ +getRequest()->attributes->get('drupal_menu_item'); + + if (isset($router_item['access']) && !$router_item['access']) { + throw new AccessDeniedHttpException(); + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = array('onKernelRequestAccessCheck', 30); + + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php new file mode 100644 index 0000000..6e23845 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php @@ -0,0 +1,83 @@ +getResponse(); + + // Set the X-UA-Compatible HTTP header to force IE to use the most recent + // rendering engine or use Chrome's frame rendering engine if available. + $response->headers->set('X-UA-Compatible', 'IE=edge,chrome=1', false); + + // Set the Content-language header. + $response->headers->set('Content-language', drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode); + + // Because pages are highly dynamic, set the last-modified time to now + // since the page is in fact being regenerated right now. + // @todo Remove this and use a more intelligent default so that HTTP + // caching can function properly. + $response->headers->set('Last-Modified', gmdate(DATE_RFC1123, REQUEST_TIME)); + + // Also give each page a unique ETag. This will force clients to include + // both an If-Modified-Since header and an If-None-Match header when doing + // conditional requests for the page (required by RFC 2616, section 13.3.4), + // making the validation more robust. This is a workaround for a bug in + // Mozilla Firefox that is triggered when Drupal's caching is enabled and + // the user accesses Drupal via an HTTP proxy (see + // https://bugzilla.mozilla.org/show_bug.cgi?id=269303): When an + // authenticated user requests a page, and then logs out and requests the + // same page again, Firefox may send a conditional request based on the + // page that was cached locally when the user was logged in. If this page + // did not have an ETag header, the request only contains an + // If-Modified-Since header. The date will be recent, because with + // authenticated users the Last-Modified header always refers to the time + // of the request. If the user accesses Drupal via a proxy server, and the + // proxy already has a cached copy of the anonymous page with an older + // Last-Modified date, the proxy may respond with 304 Not Modified, making + // the client think that the anonymous and authenticated pageviews are + // identical. + // @todo Remove this line as no longer necessary per + // http://drupal.org/node/1573064 + $response->headers->set('ETag', '"' . REQUEST_TIME . '"'); + + // Authenticated users are always given a 'no-cache' header, and will fetch + // a fresh page on every request. This prevents authenticated users from + // seeing locally cached pages. + // @todo Revisit whether or not this is still appropriate now that the + // Response object does its own cache control procesisng and we intend to + // use partial page caching more extensively. + $response->headers->set('Expires', 'Sun, 19 Nov 1978 05:00:00 GMT'); + $response->headers->set('Cache-Control', 'no-cache, must-revalidate, post-check=0, pre-check=0'); + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::RESPONSE][] = array('onRespond'); + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/LegacyControllerSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LegacyControllerSubscriber.php new file mode 100644 index 0000000..cc4da15 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/LegacyControllerSubscriber.php @@ -0,0 +1,64 @@ +getRequest()->attributes->get('drupal_menu_item'); + $controller = $event->getController(); + + // This BC logic applies only to functions. Otherwise, skip it. + if (is_string($controller) && function_exists($controller)) { + $new_controller = function() use ($router_item) { + return call_user_func_array($router_item['page_callback'], $router_item['page_arguments']); + }; + $event->setController($new_controller); + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::CONTROLLER][] = array('onKernelControllerLegacy', 30); + + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php new file mode 100644 index 0000000..12ca8b6 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php @@ -0,0 +1,56 @@ +getRequestType() == HttpKernelInterface::MASTER_REQUEST) { + menu_set_custom_theme(); + drupal_theme_initialize(); + module_invoke_all('init'); + + // Tell Drupal it is now fully bootstrapped (for the benefit of code that + // calls drupal_get_bootstrap_phase()), but without having + // _drupal_bootstrap_full() do anything, since we've already done the + // equivalent above and in earlier listeners. + _drupal_bootstrap_full(TRUE); + drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = array('onKernelRequestLegacy', 90); + + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php new file mode 100644 index 0000000..daed1c9 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php @@ -0,0 +1,59 @@ +getRequest()->attributes->get('system_path'); + drupal_alter('menu_site_status', $status, $read_only_path); + + // Only continue if the site is online. + if ($status != MENU_SITE_ONLINE) { + // Deliver the 503 page. + drupal_maintenance_theme(); + drupal_set_title(t('Site under maintenance')); + $content = theme('maintenance_page', array('content' => filter_xss_admin(variable_get('maintenance_mode_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))))))); + $response = new Response('Service unavailable', 503); + $response->setContent($content); + $event->setResponse($response); + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = array('onKernelRequestMaintenanceModeCheck', 40); + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/PathListenerBase.php b/core/lib/Drupal/Core/EventSubscriber/PathListenerBase.php new file mode 100644 index 0000000..8f29b4d --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/PathListenerBase.php @@ -0,0 +1,30 @@ +attributes->get('system_path'); + return isset($path) ? $path : trim($request->getPathInfo(), '/'); + } + + public function setPath(Request $request, $path) { + $request->attributes->set('system_path', $path); + + // @todo Remove this line once code has been refactored to use the request + // object directly. + _current_path($path); + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php new file mode 100644 index 0000000..1e2a95a --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php @@ -0,0 +1,127 @@ +getRequest(); + + $path = $this->extractPath($request); + + $path = drupal_get_normal_path($path); + + $this->setPath($request, $path); + } + + /** + * Resolve the front-page default path. + * + * @todo The path system should be objectified to remove the function calls in + * this method. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function onKernelRequestFrontPageResolve(GetResponseEvent $event) { + $request = $event->getRequest(); + $path = $this->extractPath($request); + + if (empty($path)) { + // @todo Temporary hack. Fix when configuration is injectable. + $path = variable_get('site_frontpage', 'user'); + } + + $this->setPath($request, $path); + } + + /** + * Decode language information embedded in the request path. + * + * @todo Refactor this entire method to inline the relevant portions of + * drupal_language_initialize(). See the inline comment for more details. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function onKernelRequestLanguageResolve(GetResponseEvent $event) { + $request = $event->getRequest(); + $path = $this->extractPath($request); + + // drupal_language_initialize() combines: + // - Determination of language from $request information (e.g., path). + // - Determination of language from other information (e.g., site default). + // - Population of determined language into drupal_container(). + // - Removal of language code from _current_path(). + // @todo Decouple the above, but for now, invoke it and update the path + // prior to front page and alias resolution. When above is decoupled, also + // add 'langcode' (determined from $request only) to $request->attributes. + _current_path($path); + drupal_language_initialize(); + $path = _current_path(); + + $this->setPath($request, $path); + } + + /** + * Decodes the path of the request. + * + * Parameters in the URL sometimes represent code-meaningful strings. It is + * therefore useful to always urldecode() those values so that individual + * controllers need not concern themselves with it. This is Drupal-specific + * logic and may not be familiar for developers used to other Symfony-family + * projects. + * + * @todo Revisit whether or not this logic is appropriate for here or if + * controllers should be required to implement this logic themselves. If we + * decide to keep this code, remove this TODO. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function onKernelRequestDecodePath(GetResponseEvent $event) { + $request = $event->getRequest(); + $path = $this->extractPath($request); + + $path = urldecode($path); + + $this->setPath($request, $path); + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::REQUEST][] = array('onKernelRequestDecodePath', 200); + $events[KernelEvents::REQUEST][] = array('onKernelRequestLanguageResolve', 150); + $events[KernelEvents::REQUEST][] = array('onKernelRequestFrontPageResolve', 101); + $events[KernelEvents::REQUEST][] = array('onKernelRequestPathResolve', 100); + + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php new file mode 100644 index 0000000..8b156d4 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php @@ -0,0 +1,64 @@ +getResponse(); + $config = config('system.performance'); + + if ($config->get('cache') && ($cache = drupal_page_set_cache($response->getContent()))) { + drupal_serve_page_from_cache($cache); + } + else { + ob_flush(); + } + + _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE); + drupal_cache_system_paths(); + module_implements_write_cache(); + system_run_automated_cron(); + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::TERMINATE][] = array('onTerminate'); + + return $events; + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/RouterListener.php b/core/lib/Drupal/Core/EventSubscriber/RouterListener.php new file mode 100644 index 0000000..f1a96f7 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/RouterListener.php @@ -0,0 +1,81 @@ +urlMatcher = $urlMatcher; + $this->logger = $logger; + } + + /** + * {@inheritdoc} + * + * This method is nearly identical to the parent, except it passes the + * $request->attributes->get('system_path') variable to the matcher. + * That is where Drupal stores its processed, de-aliased, and sanitized + * internal path. We also pass the full request object to the URL Matcher, + * since we want attributes to be available to the matcher and to controllers. + */ + public function onKernelRequest(GetResponseEvent $event) { + $request = $event->getRequest(); + + if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { + $this->urlMatcher->getContext()->fromRequest($request); + $this->urlMatcher->setRequest($event->getRequest()); + } + + if ($request->attributes->has('_controller')) { + // routing is already done + return; + } + + // add attributes based on the path info (routing) + try { + $parameters = $this->urlMatcher->match($request->attributes->get('system_path')); + + if (null !== $this->logger) { + $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], $this->parametersToString($parameters))); + } + + $request->attributes->add($parameters); + unset($parameters['_route']); + unset($parameters['_controller']); + $request->attributes->set('_route_params', $parameters); + } + catch (ResourceNotFoundException $e) { + $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo()); + + throw new NotFoundHttpException($message, $e); + } + catch (MethodNotAllowedException $e) { + $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods()))); + + throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e); + } + } +} diff --git a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php new file mode 100644 index 0000000..4761d47 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php @@ -0,0 +1,128 @@ +negotiation = $negotiation; + } + + /** + * Processes a successful controller into an HTTP 200 response. + * + * Some controllers may not return a response object but simply the body of + * one. The VIEW event is called in that case, to allow us to mutate that + * body into a Response object. In particular we assume that the return + * from an JSON-type response is a JSON string, so just wrap it into a + * Response object. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function onView(GetResponseEvent $event) { + + $request = $event->getRequest(); + + $method = 'on' . $this->negotiation->getContentType($request); + + if (method_exists($this, $method)) { + $event->setResponse($this->$method($event)); + } + else { + $event->setResponse(new Response('Unsupported Media Type', 415)); + } + } + + public function onJson(GetResponseEvent $event) { + $page_callback_result = $event->getControllerResult(); + + $response = new JsonResponse(); + $response->setContent($page_callback_result); + + return $response; + } + + public function onAjax(GetResponseEvent $event) { + $page_callback_result = $event->getControllerResult(); + + // Construct the response content from the page callback result. + $commands = ajax_prepare_response($page_callback_result); + $json = ajax_render($commands); + + // Build the actual response object. + $response = new JsonResponse(); + $response->setContent($json); + + return $response; + } + + public function onIframeUpload(GetResponseEvent $event) { + $page_callback_result = $event->getControllerResult(); + + // Construct the response content from the page callback result. + $commands = ajax_prepare_response($page_callback_result); + $json = ajax_render($commands); + + // Browser IFRAMEs expect HTML. Browser extensions, such as Linkification + // and Skype's Browser Highlighter, convert URLs, phone numbers, etc. into + // links. This corrupts the JSON response. Protect the integrity of the + // JSON data by making it the value of a textarea. + // @see http://malsup.com/jquery/form/#file-upload + // @see http://drupal.org/node/1009382 + $html = ''; + + return new Response($html); + } + + /** + * Processes a successful controller into an HTTP 200 response. + * + * Some controllers may not return a response object but simply the body of + * one. The VIEW event is called in that case, to allow us to mutate that + * body into a Response object. In particular we assume that the return from + * an HTML-type response is a render array from a legacy page callback and + * render it. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function onHtml(GetResponseEvent $event) { + $page_callback_result = $event->getControllerResult(); + return new Response(drupal_render_page($page_callback_result)); + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + static function getSubscribedEvents() { + $events[KernelEvents::VIEW][] = array('onView'); + + return $events; + } +} diff --git a/core/lib/Drupal/Core/ExceptionController.php b/core/lib/Drupal/Core/ExceptionController.php new file mode 100644 index 0000000..c52013d --- /dev/null +++ b/core/lib/Drupal/Core/ExceptionController.php @@ -0,0 +1,382 @@ +kernel = $kernel; + $this->negotiation = $negotiation; + } + + /** + * Handles an exception on a request. + * + * @param Symfony\Component\HttpKernel\Exception\FlattenException $exception + * The flattened exception. + * @param Symfony\Component\HttpFoundation\Request $request + * The request that generated the exception. + * + * @return Symfony\Component\HttpFoundation\Response + * A response object to be sent to the server. + */ + public function execute(FlattenException $exception, Request $request) { + $method = 'on' . $exception->getStatusCode() . $this->negotiation->getContentType($request); + + if (method_exists($this, $method)) { + return $this->$method($exception, $request); + } + + return new Response('A fatal error occurred: ' . $exception->getMessage(), $exception->getStatusCode()); + } + + /** + * Processes a MethodNotAllowed exception into an HTTP 405 response. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function on405Html(FlattenException $exception, Request $request) { + $event->setResponse(new Response('Method Not Allowed', 405)); + } + + /** + * Processes an AccessDenied exception into an HTTP 403 response. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function on403Html(FlattenException $exception, Request $request) { + $system_path = $request->attributes->get('system_path'); + watchdog('access denied', $system_path, NULL, WATCHDOG_WARNING); + + $path = drupal_get_normal_path(variable_get('site_403', '')); + if ($path && $path != $system_path) { + // Keep old path for reference, and to allow forms to redirect to it. + if (!isset($_GET['destination'])) { + $_GET['destination'] = $system_path; + } + + $subrequest = Request::create('/' . $path, 'get', array('destination' => $system_path), $request->cookies->all(), array(), $request->server->all()); + + // The active trail is being statically cached from the parent request to + // the subrequest, like any other static. Unfortunately that means the + // data in it is incorrect and does not get regenerated correctly for + // the subrequest. In this instance, that even causes a fatal error in + // some circumstances because menu_get_active_trail() ends up having + // a missing localized_options value. To work around that, reset the + // menu static variables and let them be regenerated as needed. + // @todo It is likely that there are other such statics that need to be + // reset that are not triggering test failures right now. If found, + // add them here. + // @todo Refactor the breadcrumb system so that it does not rely on static + // variables in the first place, which will eliminate the need for this + // hack. + drupal_static_reset('menu_set_active_trail'); + menu_reset_static_cache(); + + $response = $this->kernel->handle($subrequest, DrupalKernel::SUB_REQUEST); + $response->setStatusCode(403, 'Access denied'); + } + else { + $response = new Response('Access Denied', 403); + + // @todo Replace this block with something cleaner. + $return = t('You are not authorized to access this page.'); + drupal_set_title(t('Access denied')); + drupal_set_page_content($return); + $page = element_info('page'); + $content = drupal_render_page($page); + + $response->setContent($content); + } + + return $response; + } + + /** + * Processes a generic exception into an HTTP 500 response. + * + * @param FlattenException $exception + * Metadata about the exception that was thrown. + * @param Symfony\Component\HttpFoundation\Request $request + * The request object that triggered this exception. + */ + public function on500Html(FlattenException $exception, Request $request) { + $error = $this->decodeException($exception); + + // Because the kernel doesn't run until full bootstrap, we know that + // most subsystems are already initialized. + + $headers = array(); + + // When running inside the testing framework, we relay the errors + // to the tested site by the way of HTTP headers. + $test_info = &$GLOBALS['drupal_test_info']; + if (!empty($test_info['in_child_site']) && !headers_sent() && (!defined('SIMPLETEST_COLLECT_ERRORS') || SIMPLETEST_COLLECT_ERRORS)) { + // $number does not use drupal_static as it should not be reset + // as it uniquely identifies each PHP error. + static $number = 0; + $assertion = array( + $error['!message'], + $error['%type'], + array( + 'function' => $error['%function'], + 'file' => $error['%file'], + 'line' => $error['%line'], + ), + ); + $headers['X-Drupal-Assertion-' . $number] = rawurlencode(serialize($assertion)); + $number++; + } + + watchdog('php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']); + + // Display the message if the current error reporting level allows this type + // of message to be displayed, and unconditionnaly in update.php. + if (error_displayable($error)) { + $class = 'error'; + + // If error type is 'User notice' then treat it as debug information + // instead of an error message, see dd(). + if ($error['%type'] == 'User notice') { + $error['%type'] = 'Debug'; + $class = 'status'; + } + + drupal_set_message(t('%type: !message in %function (line %line of %file).', $error), $class); + } + + drupal_set_title(t('Error')); + // We fallback to a maintenance page at this point, because the page + // generation itself can generate errors. + $output = theme('maintenance_page', array('content' => t('The website encountered an unexpected error. Please try again later.'))); + + $response = new Response($output, 500); + $response->setStatusCode(500, '500 Service unavailable (with message)'); + + return $response; + } + + /** + * This method is a temporary port of _drupal_decode_exception(). + * + * @todo This should get refactored. FlattenException could use some + * improvement as well. + * + * @return array + */ + protected function decodeException(FlattenException $exception) { + $message = $exception->getMessage(); + + $backtrace = $exception->getTrace(); + + // This value is missing from the stack for some reason in the + // FlattenException version of the backtrace. + $backtrace[0]['line'] = $exception->getLine(); + + // For database errors, we try to return the initial caller, + // skipping internal functions of the database layer. + if (strpos($exception->getClass(), 'DatabaseExceptionWrapper') !== FALSE) { + // A DatabaseExceptionWrapper exception is actually just a courier for + // the original PDOException. It's the stack trace from that exception + // that we care about. + $backtrace = $exception->getPrevious()->getTrace(); + $backtrace[0]['line'] = $exception->getLine(); + + // The first element in the stack is the call, the second element gives us the caller. + // We skip calls that occurred in one of the classes of the database layer + // or in one of its global functions. + $db_functions = array('db_query', 'db_query_range'); + while (!empty($backtrace[1]) && ($caller = $backtrace[1]) && + ((strpos($caller['namespace'], 'Drupal\Core\Database') !== FALSE || strpos($caller['class'], 'PDO') !== FALSE)) || + in_array($caller['function'], $db_functions)) { + // We remove that call. + array_shift($backtrace); + } + } + $caller = $this->getLastCaller($backtrace); + + return array( + '%type' => $exception->getClass(), + // The standard PHP exception handler considers that the exception message + // is plain-text. We mimick this behavior here. + '!message' => check_plain($message), + '%function' => $caller['function'], + '%file' => $caller['file'], + '%line' => $caller['line'], + 'severity_level' => WATCHDOG_ERROR, + ); + } + + /** + * Gets the last caller from a backtrace. + * + * The last caller is not necessarily the first item in the backtrace. Rather, + * it is the first item in the backtrace that is a PHP userspace function, + * and not one of our debug functions. + * + * @param $backtrace + * A standard PHP backtrace. + * + * @return + * An associative array with keys 'file', 'line' and 'function'. + */ + protected function getLastCaller($backtrace) { + // Ignore black listed error handling functions. + $blacklist = array('debug', '_drupal_error_handler', '_drupal_exception_handler'); + + // Errors that occur inside PHP internal functions do not generate + // information about file and line. + while (($backtrace && !isset($backtrace[0]['line'])) || + (isset($backtrace[1]['function']) && in_array($backtrace[1]['function'], $blacklist))) { + array_shift($backtrace); + } + + // The first trace is the call itself. + // It gives us the line and the file of the last call. + $call = $backtrace[0]; + + // The second call give us the function where the call originated. + if (isset($backtrace[1])) { + if (isset($backtrace[1]['class'])) { + $call['function'] = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()'; + } + else { + $call['function'] = $backtrace[1]['function'] . '()'; + } + } + else { + $call['function'] = 'main()'; + } + return $call; + } + + /** + * Processes a NotFound exception into an HTTP 403 response. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function on404Html(FlattenException $exception, Request $request) { + watchdog('page not found', check_plain($request->attributes->get('system_path')), NULL, WATCHDOG_WARNING); + + // Check for and return a fast 404 page if configured. + // @todo Inline this rather than using a function. + drupal_fast_404(); + + $system_path = $request->attributes->get('system_path'); + + // Keep old path for reference, and to allow forms to redirect to it. + if (!isset($_GET['destination'])) { + $_GET['destination'] = $system_path; + } + + $path = drupal_get_normal_path(variable_get('site_404', '')); + if ($path && $path != $system_path) { + // @todo Um, how do I specify an override URL again? Totally not clear. Do + // that and sub-call the kernel rather than using meah(). + // @todo The create() method expects a slash-prefixed path, but we store a + // normal system path in the site_404 variable. + $subrequest = Request::create('/' . $path, 'get', array(), $request->cookies->all(), array(), $request->server->all()); + + $response = $this->kernel->handle($subrequest, HttpKernelInterface::SUB_REQUEST); + $response->setStatusCode(404, 'Not Found'); + } + else { + $response = new Response('Not Found', 404); + + // @todo Replace this block with something cleaner. + $return = t('The requested page "@path" could not be found.', array('@path' => $request->getPathInfo())); + drupal_set_title(t('Page not found')); + drupal_set_page_content($return); + $page = element_info('page'); + $content = drupal_render_page($page); + + $response->setContent($content); + } + + return $response; + } + + /** + * Processes an AccessDenied exception into an HTTP 403 response. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function on403Json(FlattenException $exception, Request $request) { + $response = new JsonResponse(); + $response->setStatusCode(403, 'Access Denied'); + return $response; + } + + /** + * Processes a NotFound exception into an HTTP 404 response. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function on404Json(FlattenException $exception, Request $request) { + $response = new JsonResponse(); + $response->setStatusCode(404, 'Not Found'); + return $response; + } + + /** + * Processes a MethodNotAllowed exception into an HTTP 405 response. + * + * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event + * The Event to process. + */ + public function on405Json(FlattenException $exception, Request $request) { + $response = new JsonResponse(); + $response->setStatusCode(405, 'Method Not Allowed'); + return $response; + } +} diff --git a/core/lib/Drupal/Core/Lock/DatabaseLockBackend.php b/core/lib/Drupal/Core/Lock/DatabaseLockBackend.php index 6971d9f..d877dba 100644 --- a/core/lib/Drupal/Core/Lock/DatabaseLockBackend.php +++ b/core/lib/Drupal/Core/Lock/DatabaseLockBackend.php @@ -7,7 +7,7 @@ namespace Drupal\Core\Lock; -use PDOException; +use Drupal\Core\Database\DatabaseExceptionWrapper; /** * Defines the database lock backend. This is the default backend in Drupal. @@ -53,7 +53,7 @@ class DatabaseLockBackend extends LockBackendAbstract { // We never need to try again. $retry = FALSE; } - catch (PDOException $e) { + catch (DatabaseExceptionWrapper $e) { // Suppress the error. If this is our first pass through the loop, // then $retry is FALSE. In this case, the insert must have failed // meaning some other request acquired the lock but did not release it. diff --git a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php index 0cd76e0..1b4abc9 100644 --- a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php @@ -44,7 +44,7 @@ abstract class LocalStream implements StreamWrapperInterface { /** * Gets the path that the wrapper is responsible for. - * @TODO: Review this method name in D8 per http://drupal.org/node/701358 + * @todo: Review this method name in D8 per http://drupal.org/node/701358 * * @return string * String specifying the path. diff --git a/core/lib/Drupal/Core/Updater/Updater.php b/core/lib/Drupal/Core/Updater/Updater.php index 2dca5ba..ad2213a 100644 --- a/core/lib/Drupal/Core/Updater/Updater.php +++ b/core/lib/Drupal/Core/Updater/Updater.php @@ -213,7 +213,7 @@ class Updater { $this->makeWorldReadable($filetransfer, $args['install_dir'] . '/' . $this->name); // Run the updates. - // @TODO: decide if we want to implement this. + // @todo: decide if we want to implement this. $this->postUpdate(); // For now, just return a list of links of things to do. @@ -252,7 +252,7 @@ class Updater { $this->makeWorldReadable($filetransfer, $args['install_dir'] . '/' . $this->name); // Potentially enable something? - // @TODO: decide if we want to implement this. + // @todo: decide if we want to implement this. $this->postInstall(); // For now, just return a list of links of things to do. return $this->postInstallTasks(); diff --git a/core/lib/Drupal/Core/UrlMatcher.php b/core/lib/Drupal/Core/UrlMatcher.php new file mode 100644 index 0000000..7d6e24c --- /dev/null +++ b/core/lib/Drupal/Core/UrlMatcher.php @@ -0,0 +1,140 @@ +context = new RequestContext(); + } + + /** + * Sets the request context. + * + * This method is just to satisfy the interface, and is largely vestigial. + * The request context object does not contain the information we need, so + * we will use the original request object. + * + * @param Symfony\Component\Routing\RequestContext $context + * The context. + * + * @api + */ + public function setContext(RequestContext $context) { + $this->context = $context; + } + + /** + * Gets the request context. + * + * This method is just to satisfy the interface, and is largely vestigial. + * The request context object does not contain the information we need, so + * we will use the original request object. + * + * @return Symfony\Component\Routing\RequestContext + * The context. + */ + public function getContext() { + return $this->context; + } + + public function setRequest(Request $request) { + $this->request = $request; + } + + public function getRequest() { + return $this->request; + } + + /** + * {@inheritDoc} + * + * @api + */ + public function match($pathinfo) { + if ($router_item = $this->matchDrupalItem($pathinfo)) { + $ret = $this->convertDrupalItem($router_item); + // Stash the router item in the attributes while we're transitioning. + $ret['drupal_menu_item'] = $router_item; + + // Most legacy controllers (aka page callbacks) are in a separate file, + // so we have to include that. + if ($router_item['include_file']) { + require_once DRUPAL_ROOT . '/' . $router_item['include_file']; + } + + return $ret; + } + + // This matcher doesn't differentiate by method, so don't bother with those + // exceptions. + throw new ResourceNotFoundException(); + } + + /** + * Get a drupal menu item. + * + * @todo Make this return multiple possible candidates for the resolver to + * consider. + * + * @param string $path + * The path being looked up by + */ + protected function matchDrupalItem($path) { + // For now we can just proxy our procedural method. At some point this will + // become more complicated because we'll need to get back candidates for a + // path and them resolve them based on things like method and scheme which + // we currently can't do. + return menu_get_item($path); + } + + protected function convertDrupalItem($router_item) { + $route = array( + '_controller' => $router_item['page_callback'] + ); + + // Place argument defaults on the route. + // @todo For some reason drush test runs have a serialized page_arguments + // but HTTP requests are unserialized. Hack to get around this for now. + // This might be because page arguments aren't unserialized in + // menu_get_item() when the access is denied. + !is_array($router_item['page_arguments']) ? $page_arguments = unserialize($router_item['page_arguments']) : $page_arguments = $router_item['page_arguments']; + foreach ($page_arguments as $k => $v) { + $route[$k] = $v; + } + return $route; + } +} diff --git a/core/lib/Drupal/Core/Utility/UpdateException.php b/core/lib/Drupal/Core/Utility/UpdateException.php deleted file mode 100644 index d86992c..0000000 --- a/core/lib/Drupal/Core/Utility/UpdateException.php +++ /dev/null @@ -1,13 +0,0 @@ -fid)) { - return MENU_ACCESS_DENIED; - } aggregator_refresh($feed); drupal_goto('admin/config/services/aggregator'); } diff --git a/core/modules/aggregator/aggregator.module b/core/modules/aggregator/aggregator.module index 0626f72..ee285e2 100644 --- a/core/modules/aggregator/aggregator.module +++ b/core/modules/aggregator/aggregator.module @@ -138,7 +138,8 @@ function aggregator_menu() { 'title' => 'Update items', 'page callback' => 'aggregator_admin_refresh_feed', 'page arguments' => array(5), - 'access arguments' => array('administer news feeds'), + 'access callback' => 'aggregator_admin_refresh_feed_access', + 'access arguments' => array(5), 'file' => 'aggregator.admin.inc', ); $items['admin/config/services/aggregator/list'] = array( @@ -796,3 +797,23 @@ function aggregator_preprocess_block(&$variables) { $variables['attributes_array']['role'] = 'complementary'; } } + +/** + * Access callback: Determines if feed refresh is accessible. + * + * @param $feed + * An object describing the feed to be refreshed. + * + * @see aggregator_admin_refresh_feed() + * @see aggregator_menu() + */ +function aggregator_admin_refresh_feed_access($feed) { + if (!user_access('administer news feeds')) { + return FALSE; + } + $token = request()->query->get('token'); + if (!isset($token) || !drupal_valid_token($token, 'aggregator/update/' . $feed->fid)) { + return FALSE; + } + return TRUE; +} diff --git a/core/modules/aggregator/aggregator.test b/core/modules/aggregator/aggregator.test index afba181..f58fb65 100644 --- a/core/modules/aggregator/aggregator.test +++ b/core/modules/aggregator/aggregator.test @@ -5,9 +5,7 @@ * Tests for aggregator.module. */ -use Drupal\simpletest\WebTestBase; - -class AggregatorTestCase extends WebTestBase { +class AggregatorTestCase extends DrupalWebTestCase { function setUp() { parent::setUp(array('node', 'block', 'aggregator', 'aggregator_test')); diff --git a/core/modules/block/block.test b/core/modules/block/block.test index 7782e77..192e264 100644 --- a/core/modules/block/block.test +++ b/core/modules/block/block.test @@ -5,10 +5,7 @@ * Tests for block.module. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - -class BlockTestCase extends WebTestBase { +class BlockTestCase extends DrupalWebTestCase { protected $regions; protected $admin_user; @@ -401,7 +398,7 @@ class BlockTestCase extends WebTestBase { } } -class NonDefaultBlockAdmin extends WebTestBase { +class NonDefaultBlockAdmin extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Non default theme admin', @@ -429,7 +426,7 @@ class NonDefaultBlockAdmin extends WebTestBase { /** * Test blocks correctly initialized when picking a new default theme. */ -class NewDefaultThemeBlocks extends WebTestBase { +class NewDefaultThemeBlocks extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'New default theme blocks', @@ -484,7 +481,7 @@ class NewDefaultThemeBlocks extends WebTestBase { /** * Test the block system with admin themes. */ -class BlockAdminThemeTestCase extends WebTestBase { +class BlockAdminThemeTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Admin theme block admin accessibility', @@ -520,7 +517,7 @@ class BlockAdminThemeTestCase extends WebTestBase { /** * Test block caching. */ -class BlockCacheTestCase extends WebTestBase { +class BlockCacheTestCase extends DrupalWebTestCase { protected $admin_user; protected $normal_user; protected $normal_user_alt; @@ -707,7 +704,7 @@ class BlockCacheTestCase extends WebTestBase { /** * Test block HTML id validity. */ -class BlockHTMLIdTestCase extends WebTestBase { +class BlockHTMLIdTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -746,7 +743,7 @@ class BlockHTMLIdTestCase extends WebTestBase { /** * Unit tests for template_preprocess_block(). */ -class BlockTemplateSuggestionsUnitTest extends UnitTestBase { +class BlockTemplateSuggestionsUnitTest extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Block template suggestions', @@ -791,7 +788,7 @@ class BlockTemplateSuggestionsUnitTest extends UnitTestBase { /** * Tests that hidden regions do not inherit blocks when a theme is enabled. */ -class BlockHiddenRegionTestCase extends WebTestBase { +class BlockHiddenRegionTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Blocks not in hidden region', @@ -851,7 +848,7 @@ class BlockHiddenRegionTestCase extends WebTestBase { /** * Functional tests for the language list configuration forms. */ -class BlockLanguageTestCase extends WebTestBase { +class BlockLanguageTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Language block visibility', @@ -1037,7 +1034,7 @@ class BlockLanguageTestCase extends WebTestBase { /** * Tests that a block assigned to an invalid region triggers the warning. */ -class BlockInvalidRegionTestCase extends WebTestBase { +class BlockInvalidRegionTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Blocks in invalid regions', diff --git a/core/modules/book/book.test b/core/modules/book/book.test index 00995cb..f7d8280 100644 --- a/core/modules/book/book.test +++ b/core/modules/book/book.test @@ -6,9 +6,8 @@ */ use Drupal\node\Node; -use Drupal\simpletest\WebTestBase; -class BookTestCase extends WebTestBase { +class BookTestCase extends DrupalWebTestCase { protected $book; // $book_author is a user with permission to create and edit books. protected $book_author; diff --git a/core/modules/color/color.test b/core/modules/color/color.test index 8835e5b..616d19a 100644 --- a/core/modules/color/color.test +++ b/core/modules/color/color.test @@ -5,12 +5,10 @@ * Tests for color module. */ -use Drupal\simpletest\WebTestBase; - /** * Tests the Color module functionality. */ -class ColorTestCase extends WebTestBase { +class ColorTestCase extends DrupalWebTestCase { protected $big_user; protected $themes; protected $colorTests; diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc index ccc307e..9eabe13 100644 --- a/core/modules/comment/comment.admin.inc +++ b/core/modules/comment/comment.admin.inc @@ -260,7 +260,7 @@ function comment_confirm_delete_page($cid) { if ($comment = comment_load($cid)) { return drupal_get_form('comment_confirm_delete', $comment); } - return MENU_NOT_FOUND; + drupal_not_found(); } /** diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 79f2ecb..285d9fe 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -277,7 +277,8 @@ function comment_menu() { 'title' => 'Approve', 'page callback' => 'comment_approve', 'page arguments' => array(1), - 'access arguments' => array('administer comments'), + 'access callback' => 'comment_approve_access', + 'access arguments' => array(1), 'file' => 'comment.pages.inc', 'weight' => 1, ); @@ -2514,3 +2515,23 @@ function comment_file_download_access($field, $entity_type, $entity) { return FALSE; } } + +/** + * Access callback: Determines if comment approval is accessible. + * + * @param $cid + * A comment identifier. + * + * @see comment_approve() + * @see comment_menu() + */ +function comment_approve_access($cid) { + if (!user_access('administer comments')) { + return FALSE; + } + $token = request()->query->get('token'); + if (!isset($token) || !drupal_valid_token($token, "comment/$cid/approve")) { + return FALSE; + } + return TRUE; +} diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc index bac078b..59423ec 100644 --- a/core/modules/comment/comment.pages.inc +++ b/core/modules/comment/comment.pages.inc @@ -105,11 +105,9 @@ function comment_reply(Node $node, $pid = NULL) { * A comment identifier. * * @see comment_menu() + * @see comment_approve_access() */ function comment_approve($cid) { - if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], "comment/$cid/approve")) { - return MENU_ACCESS_DENIED; - } if ($comment = comment_load($cid)) { $comment->status = COMMENT_PUBLISHED; comment_save($comment); @@ -117,5 +115,5 @@ function comment_approve($cid) { drupal_set_message(t('Comment approved.')); drupal_goto('node/' . $comment->nid); } - return MENU_NOT_FOUND; + drupal_not_found(); } diff --git a/core/modules/comment/comment.test b/core/modules/comment/comment.test index 2e0a209..3f5b040 100644 --- a/core/modules/comment/comment.test +++ b/core/modules/comment/comment.test @@ -6,9 +6,8 @@ */ use Drupal\comment\Comment; -use Drupal\simpletest\WebTestBase; -class CommentHelperCase extends WebTestBase { +class CommentHelperCase extends DrupalWebTestCase { protected $profile = 'standard'; protected $admin_user; @@ -819,7 +818,7 @@ class CommentInterfaceTest extends CommentHelperCase { user_role_change_permissions($rid, $perms); // Output verbose debugging information. - // @see Drupal\simpletest\TestBase::error() + // @see DrupalTestCase::error() $t_form = array( COMMENT_FORM_BELOW => 'below', COMMENT_FORM_SEPARATE_PAGE => 'separate page', @@ -1516,7 +1515,7 @@ class CommentNodeAccessTest extends CommentHelperCase { } function setUp() { - WebTestBase::setUp('comment', 'search', 'node_access_test'); + DrupalWebTestCase::setUp('comment', 'search', 'node_access_test'); node_access_rebuild(); // Create users and test node. diff --git a/core/modules/config/config.test b/core/modules/config/config.test index f69dde9..c111aba 100644 --- a/core/modules/config/config.test +++ b/core/modules/config/config.test @@ -6,12 +6,11 @@ */ use Drupal\Core\Config\FileStorage; -use Drupal\simpletest\WebTestBase; /** * Tests the secure file writer. */ -class ConfigFileSecurityTestCase extends WebTestBase { +class ConfigFileSecurityTestCase extends DrupalWebTestCase { protected $filename = 'foo.bar'; protected $testContent = 'Good morning, Denver!'; @@ -51,7 +50,7 @@ class ConfigFileSecurityTestCase extends WebTestBase { /** * Tests reading and writing file contents. */ -class ConfigFileContentTestCase extends WebTestBase { +class ConfigFileContentTestCase extends DrupalWebTestCase { protected $fileExtension = 'xml'; public static function getInfo() { @@ -232,7 +231,7 @@ class ConfigFileContentTestCase extends WebTestBase { /** * Tests configuration overriding from settings.php. */ -class ConfOverrideTestCase extends WebTestBase { +class ConfOverrideTestCase extends DrupalWebTestCase { protected $testContent = 'Good morning, Denver!'; public static function getInfo() { @@ -260,7 +259,7 @@ class ConfOverrideTestCase extends WebTestBase { /** * Tests function providing configuration upgrade from Drupal 7 to 8. */ -class ConfUpdate7to8TestCase extends WebTestBase { +class ConfUpdate7to8TestCase extends DrupalWebTestCase { protected $testContent = 'Olá, Sao Paulo!'; public static function getInfo() { diff --git a/core/modules/contact/contact.test b/core/modules/contact/contact.test index c80f21d..490d8f8 100644 --- a/core/modules/contact/contact.test +++ b/core/modules/contact/contact.test @@ -4,12 +4,10 @@ * Tests for the Contact module. */ -use Drupal\simpletest\WebTestBase; - /** * Tests the site-wide contact form. */ -class ContactSitewideTestCase extends WebTestBase { +class ContactSitewideTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Site-wide contact form', @@ -300,7 +298,7 @@ class ContactSitewideTestCase extends WebTestBase { /** * Tests the personal contact form. */ -class ContactPersonalTestCase extends WebTestBase { +class ContactPersonalTestCase extends DrupalWebTestCase { private $admin_user; private $web_user; private $contact_user; diff --git a/core/modules/contextual/contextual.test b/core/modules/contextual/contextual.test index 8749f3a..734f7cf 100644 --- a/core/modules/contextual/contextual.test +++ b/core/modules/contextual/contextual.test @@ -5,12 +5,10 @@ * Tests for contextual.module. */ -use Drupal\simpletest\WebTestBase; - /** * Tests accessible links after inaccessible links on dynamic context. */ -class ContextualDynamicContextTestCase extends WebTestBase { +class ContextualDynamicContextTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Contextual links on node lists', diff --git a/core/modules/dashboard/dashboard.test b/core/modules/dashboard/dashboard.test index 2808dc4..ff37d57 100644 --- a/core/modules/dashboard/dashboard.test +++ b/core/modules/dashboard/dashboard.test @@ -5,13 +5,10 @@ * Tests for dashboard.module. */ - -use Drupal\simpletest\WebTestBase; - /** * Tests the Dashboard module blocks. */ -class DashboardBlocksTestCase extends WebTestBase { +class DashboardBlocksTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Dashboard blocks', @@ -109,7 +106,7 @@ class DashboardBlocksTestCase extends WebTestBase { } } -class DashboardBlockAvailabilityTestCase extends WebTestBase { +class DashboardBlockAvailabilityTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { diff --git a/core/modules/dblog/dblog.test b/core/modules/dblog/dblog.test index 92763c1..77765d7 100644 --- a/core/modules/dblog/dblog.test +++ b/core/modules/dblog/dblog.test @@ -5,10 +5,7 @@ * Tests for dblog.module. */ - -use Drupal\simpletest\WebTestBase; - -class DBLogTestCase extends WebTestBase { +class DBLogTestCase extends DrupalWebTestCase { protected $profile = 'standard'; protected $big_user; diff --git a/core/modules/entity/tests/entity.test b/core/modules/entity/tests/entity.test index d920937..abc02ef 100644 --- a/core/modules/entity/tests/entity.test +++ b/core/modules/entity/tests/entity.test @@ -5,12 +5,10 @@ * Entity CRUD API tests. */ -use Drupal\simpletest\WebTestBase; - /** * Tests the basic Entity API. */ -class EntityAPITestCase extends WebTestBase { +class EntityAPITestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -94,7 +92,7 @@ class EntityAPITestCase extends WebTestBase { /** * Tests entity translation. */ -class EntityTranslationTestCase extends WebTestBase { +class EntityTranslationTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -203,7 +201,7 @@ class EntityTranslationTestCase extends WebTestBase { /** * Tests Entity API base functionality. */ -class EntityAPIInfoTestCase extends WebTestBase { +class EntityAPIInfoTestCase extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/entity/tests/entity_crud_hook_test.test b/core/modules/entity/tests/entity_crud_hook_test.test index dd4aa70..33dbb2e 100644 --- a/core/modules/entity/tests/entity_crud_hook_test.test +++ b/core/modules/entity/tests/entity_crud_hook_test.test @@ -5,8 +5,6 @@ * CRUD hook tests for the Entity CRUD API. */ -use Drupal\simpletest\WebTestBase; - /** * Tests invocation of hooks when performing an action. * @@ -19,7 +17,7 @@ use Drupal\simpletest\WebTestBase; * As well as all type-specific hooks, like hook_node_insert(), * hook_comment_update(), etc. */ -class EntityCrudHookTestCase extends WebTestBase { +class EntityCrudHookTestCase extends DrupalWebTestCase { protected $ids = array(); diff --git a/core/modules/entity/tests/entity_query.test b/core/modules/entity/tests/entity_query.test index edcf95a..c7ac575 100644 --- a/core/modules/entity/tests/entity_query.test +++ b/core/modules/entity/tests/entity_query.test @@ -5,12 +5,10 @@ * Unit test file for the entity API. */ -use Drupal\simpletest\WebTestBase; - /** * Tests EntityFieldQuery. */ -class EntityFieldQueryTestCase extends WebTestBase { +class EntityFieldQueryTestCase extends DrupalWebTestCase { public static function getInfo() { diff --git a/core/modules/field/modules/field_sql_storage/field_sql_storage.test b/core/modules/field/modules/field_sql_storage/field_sql_storage.test index 2a90434..20b5bdc 100644 --- a/core/modules/field/modules/field_sql_storage/field_sql_storage.test +++ b/core/modules/field/modules/field_sql_storage/field_sql_storage.test @@ -2,7 +2,6 @@ use Drupal\Core\Database\Database; use Drupal\field\FieldException; -use Drupal\simpletest\WebTestBase; /** * @file @@ -15,7 +14,7 @@ use Drupal\simpletest\WebTestBase; /** * Tests field storage. */ -class FieldSqlStorageTestCase extends WebTestBase { +class FieldSqlStorageTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Field SQL Storage tests', diff --git a/core/modules/field/modules/number/number.test b/core/modules/field/modules/number/number.test index ddf9f1f..e394aea 100644 --- a/core/modules/field/modules/number/number.test +++ b/core/modules/field/modules/number/number.test @@ -5,12 +5,10 @@ * Tests for number.module. */ -use Drupal\simpletest\WebTestBase; - /** * Tests for number field types. */ -class NumberFieldTestCase extends WebTestBase { +class NumberFieldTestCase extends DrupalWebTestCase { protected $field; protected $instance; protected $web_user; diff --git a/core/modules/field/modules/text/text.test b/core/modules/field/modules/text/text.test index a41e8cd..77efce9 100644 --- a/core/modules/field/modules/text/text.test +++ b/core/modules/field/modules/text/text.test @@ -6,9 +6,8 @@ */ use Drupal\field\FieldValidationException; -use Drupal\simpletest\WebTestBase; -class TextFieldTestCase extends WebTestBase { +class TextFieldTestCase extends DrupalWebTestCase { protected $instance; protected $admin_user; protected $web_user; @@ -240,7 +239,7 @@ class TextFieldTestCase extends WebTestBase { } } -class TextSummaryTestCase extends WebTestBase { +class TextSummaryTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -410,7 +409,7 @@ class TextSummaryTestCase extends WebTestBase { } } -class TextTranslationTestCase extends WebTestBase { +class TextTranslationTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { diff --git a/core/modules/field/tests/field.test b/core/modules/field/tests/field.test index 9a850d9..4b59fc8 100644 --- a/core/modules/field/tests/field.test +++ b/core/modules/field/tests/field.test @@ -7,12 +7,11 @@ use Drupal\field\FieldException; use Drupal\field\FieldValidationException; -use Drupal\simpletest\WebTestBase; /** * Parent class for Field API tests. */ -class FieldTestCase extends WebTestBase { +class FieldTestCase extends DrupalWebTestCase { var $default_storage = 'field_sql_storage'; /** @@ -20,9 +19,8 @@ class FieldTestCase extends WebTestBase { */ function setUp() { // Since this is a base class for many test cases, support the same - // flexibility that Drupal\simpletest\WebTestBase::setUp() has for the - // modules to be passed in as either an array or a variable number of string - // arguments. + // flexibility that DrupalWebTestCase::setUp() has for the modules to be + // passed in as either an array or a variable number of string arguments. $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; @@ -79,9 +77,8 @@ class FieldTestCase extends WebTestBase { class FieldAttachTestCase extends FieldTestCase { function setUp() { // Since this is a base class for many test cases, support the same - // flexibility that Drupal\simpletest\WebTestBase::setUp() has for the - // modules to be passed in as either an array or a variable number of string - // arguments. + // flexibility that DrupalWebTestCase::setUp() has for the modules to be + // passed in as either an array or a variable number of string arguments. $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; diff --git a/core/modules/field/theme/field-rtl.css b/core/modules/field/theme/field-rtl.css index 7aa7936..5d35a86 100644 --- a/core/modules/field/theme/field-rtl.css +++ b/core/modules/field/theme/field-rtl.css @@ -1,3 +1,7 @@ + +form .field-multiple-table th.field-label { + padding-right: 0; +} form .field-multiple-table td.field-multiple-drag { padding-left: 0; } diff --git a/core/modules/field/theme/field.css b/core/modules/field/theme/field.css index b46b41b..9eba32f 100644 --- a/core/modules/field/theme/field.css +++ b/core/modules/field/theme/field.css @@ -12,6 +12,9 @@ form .field-multiple-table { margin: 0; } +form .field-multiple-table th.field-label { + padding-left: 0; /*LTR*/ +} form .field-multiple-table td.field-multiple-drag { width: 30px; padding-right: 0; /*LTR*/ diff --git a/core/modules/field_ui/field_ui.test b/core/modules/field_ui/field_ui.test index c33552c..80edc38 100644 --- a/core/modules/field_ui/field_ui.test +++ b/core/modules/field_ui/field_ui.test @@ -6,18 +6,16 @@ */ use Drupal\node\Node; -use Drupal\simpletest\WebTestBase; /** * Provides common functionality for the Field UI test classes. */ -class FieldUITestCase extends WebTestBase { +class FieldUITestCase extends DrupalWebTestCase { function setUp() { // Since this is a base class for many test cases, support the same - // flexibility that Drupal\simpletest\WebTestBase::setUp() has for the - // modules to be passed in as either an array or a variable number of string - // arguments. + // flexibility that DrupalWebTestCase::setUp() has for the modules to be + // passed in as either an array or a variable number of string arguments. $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; @@ -683,7 +681,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { $output = drupal_render($element); $this->verbose(t('Rendered node - view mode: @view_mode', array('@view_mode' => $view_mode)) . '
'. $output); - // Assign content so that WebTestBase functions can be used. + // Assign content so that DrupalWebTestCase functions can be used. $this->drupalSetContent($output); $method = ($not_exists ? 'assertNoText' : 'assertText'); $return = $this->{$method}((string) $text, $message); @@ -698,7 +696,7 @@ class FieldUIManageDisplayTestCase extends FieldUITestCase { /** * Tests custom widget hooks and callbacks on the field administration pages. */ -class FieldUIAlterTestCase extends WebTestBase { +class FieldUIAlterTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Widget customization', diff --git a/core/modules/file/tests/file.test b/core/modules/file/tests/file.test index febd1da..92b7ef3 100644 --- a/core/modules/file/tests/file.test +++ b/core/modules/file/tests/file.test @@ -5,21 +5,18 @@ * Tests for file.module. */ -use Drupal\simpletest\WebTestBase; - /** * Provides methods specifically for testing File module's field handling. */ -class FileFieldTestCase extends WebTestBase { +class FileFieldTestCase extends DrupalWebTestCase { protected $profile = 'standard'; protected $admin_user; function setUp() { // Since this is a base class for many test cases, support the same - // flexibility that Drupal\simpletest\WebTestBase::setUp() has for the - // modules to be passed in as either an array or a variable number of string - // arguments. + // flexibility that DrupalWebTestCase::setUp() has for the modules to be + // passed in as either an array or a variable number of string arguments. $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { $modules = $modules[0]; diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module index 5d5589e..1e6c28c 100644 --- a/core/modules/filter/filter.module +++ b/core/modules/filter/filter.module @@ -1424,7 +1424,7 @@ function _filter_url($text, $filter) { $tasks['_filter_url_parse_full_links'] = $pattern; // Match e-mail addresses. - $url_pattern = "[A-Za-z0-9._-]{1,254}@(?:$domain)"; + $url_pattern = "[A-Za-z0-9._-]+@(?:$domain)"; $pattern = "`($url_pattern)`"; $tasks['_filter_url_parse_email_links'] = $pattern; diff --git a/core/modules/filter/filter.test b/core/modules/filter/filter.test index 923a047..a387f1f 100644 --- a/core/modules/filter/filter.test +++ b/core/modules/filter/filter.test @@ -5,13 +5,10 @@ * Tests for filter.module. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - /** * Tests for text format and filter CRUD operations. */ -class FilterCRUDTestCase extends WebTestBase { +class FilterCRUDTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Filter CRUD operations', @@ -163,7 +160,7 @@ class FilterCRUDTestCase extends WebTestBase { } } -class FilterAdminTestCase extends WebTestBase { +class FilterAdminTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -418,7 +415,7 @@ class FilterAdminTestCase extends WebTestBase { } } -class FilterFormatAccessTestCase extends WebTestBase { +class FilterFormatAccessTestCase extends DrupalWebTestCase { protected $admin_user; protected $filter_admin_user; protected $web_user; @@ -665,7 +662,7 @@ class FilterFormatAccessTestCase extends WebTestBase { } } -class FilterDefaultFormatTestCase extends WebTestBase { +class FilterDefaultFormatTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Default text format functionality', @@ -725,7 +722,7 @@ class FilterDefaultFormatTestCase extends WebTestBase { } } -class FilterNoFormatTestCase extends WebTestBase { +class FilterNoFormatTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Unassigned text format functionality', @@ -748,7 +745,7 @@ class FilterNoFormatTestCase extends WebTestBase { /** * Security tests for missing/vanished text formats or filters. */ -class FilterSecurityTestCase extends WebTestBase { +class FilterSecurityTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Security', @@ -812,7 +809,7 @@ class FilterSecurityTestCase extends WebTestBase { /** * Unit tests for core filters. */ -class FilterUnitTestCase extends UnitTestBase { +class FilterUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Filter module filters', @@ -1217,11 +1214,6 @@ class FilterUnitTestCase extends UnitTestBase { // - absolute, mail, partial // - characters/encoding, surrounding markup, security - // Create a e-mail that is too long. - $long_email = str_repeat('a', 254) . '@example.com'; - $too_long_email = str_repeat('b', 255) . '@example.com'; - - // Filter selection/pattern matching. $tests = array( // HTTP URLs. @@ -1233,12 +1225,10 @@ http://example.com or www.example.com ), // MAILTO URLs. ' -person@example.com or mailto:person2@example.com or ' . $long_email . ' but not ' . $too_long_email . ' +person@example.com or mailto:person2@example.com ' => array( 'person@example.com' => TRUE, 'mailto:person2@example.com' => TRUE, - '' . $long_email . '' => TRUE, - '' . $too_long_email . '' => FALSE, ), // URI parts and special characters. ' @@ -1805,7 +1795,7 @@ body {color:red} /** * Tests for filter hook invocation. */ -class FilterHooksTestCase extends WebTestBase { +class FilterHooksTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Filter format hooks', @@ -1867,7 +1857,7 @@ class FilterHooksTestCase extends WebTestBase { /** * Tests filter settings. */ -class FilterSettingsTestCase extends WebTestBase { +class FilterSettingsTestCase extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { diff --git a/core/modules/forum/forum.test b/core/modules/forum/forum.test index 4561092..9d8a9f1 100644 --- a/core/modules/forum/forum.test +++ b/core/modules/forum/forum.test @@ -6,9 +6,8 @@ */ use Drupal\node\Node; -use Drupal\simpletest\WebTestBase; -class ForumTestCase extends WebTestBase { +class ForumTestCase extends DrupalWebTestCase { protected $admin_user; protected $edit_own_topics_user; protected $edit_any_topics_user; @@ -595,7 +594,7 @@ class ForumTestCase extends WebTestBase { /** * Tests the forum index listing. */ -class ForumIndexTestCase extends WebTestBase { +class ForumIndexTestCase extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/help/help.test b/core/modules/help/help.test index 2621431..7bffe70 100644 --- a/core/modules/help/help.test +++ b/core/modules/help/help.test @@ -5,12 +5,10 @@ * Tests for help.module. */ -use Drupal\simpletest\WebTestBase; - /** * Tests help display and user access for all modules implementing help. */ -class HelpTestCase extends WebTestBase { +class HelpTestCase extends DrupalWebTestCase { // Tests help implementations of many arbitrary core modules. protected $profile = 'standard'; @@ -110,7 +108,7 @@ class HelpTestCase extends WebTestBase { /** * Tests a module without help to verify it is not listed in the help page. */ -class NoHelpTestCase extends WebTestBase { +class NoHelpTestCase extends DrupalWebTestCase { /** * The user who will be created. */ diff --git a/core/modules/image/image.module b/core/modules/image/image.module index 3edf83c..8fd8cee 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -516,7 +516,7 @@ function image_styles() { $styles = array(); // Select the styles we have configured. - $configured_styles = config_get_storage_names_with_prefix('image.style'); + $configured_styles = config_get_verified_storage_names_with_prefix('image.style'); foreach ($configured_styles as $config_name) { // @todo Allow to retrieve the name without prefix only. $style = image_style_load(str_replace('image.style.', '', $config_name)); diff --git a/core/modules/image/image.test b/core/modules/image/image.test index f9a4ec1..84b1296 100644 --- a/core/modules/image/image.test +++ b/core/modules/image/image.test @@ -5,9 +5,6 @@ * Tests for image.module. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - /** * TODO: Test the following functions. * @@ -31,7 +28,7 @@ use Drupal\simpletest\UnitTestBase; /** * This class provides methods specifically for testing Image's field handling. */ -class ImageFieldTestCase extends WebTestBase { +class ImageFieldTestCase extends DrupalWebTestCase { protected $admin_user; function setUp() { @@ -121,7 +118,7 @@ class ImageFieldTestCase extends WebTestBase { /** * Tests the functions for generating paths and URLs for image styles. */ -class ImageStylesPathAndUrlUnitTest extends WebTestBase { +class ImageStylesPathAndUrlUnitTest extends DrupalWebTestCase { protected $style_name; protected $image_info; protected $image_filepath; @@ -658,7 +655,7 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase { // sent by Drupal. $this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png; name="' . $test_image->filename . '"', t('Content-Type header was sent.')); $this->assertEqual($this->drupalGetHeader('Content-Disposition'), 'inline; filename="' . $test_image->filename . '"', t('Content-Disposition header was sent.')); - $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'private', t('Cache-Control header was sent.')); + $this->assertTrue(strstr($this->drupalGetHeader('Cache-Control'),'private') !== FALSE, t('Cache-Control header was sent.')); // Log out and try to access the file. $this->drupalLogout(); @@ -904,7 +901,7 @@ class ImageFieldValidateTestCase extends ImageFieldTestCase { /** * Tests that images have correct dimensions when styled. */ -class ImageDimensionsUnitTest extends WebTestBase { +class ImageDimensionsUnitTest extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { @@ -1127,7 +1124,7 @@ class ImageDimensionsUnitTest extends WebTestBase { /** * Tests image_dimensions_scale(). */ -class ImageDimensionsScaleTestCase extends UnitTestBase { +class ImageDimensionsScaleTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'image_dimensions_scale()', diff --git a/core/modules/language/language.test b/core/modules/language/language.test index d633d82..380e64f 100644 --- a/core/modules/language/language.test +++ b/core/modules/language/language.test @@ -10,12 +10,10 @@ use Drupal\Core\DependencyInjection\ContainerBuilder; * - comparison of $GLOBALS default language against dependency injection; */ -use Drupal\simpletest\WebTestBase; - /** * Functional tests for the language list configuration forms. */ -class LanguageListTest extends WebTestBase { +class LanguageListTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Language list configuration', @@ -170,7 +168,7 @@ class LanguageListTest extends WebTestBase { /** * Test for dependency injected language object. */ -class LanguageDependencyInjectionTest extends WebTestBase { +class LanguageDependencyInjectionTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Language dependency injection', diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test index 09523fc..be2b319 100644 --- a/core/modules/locale/locale.test +++ b/core/modules/locale/locale.test @@ -20,13 +20,11 @@ * - a functional test fot language types/negotiation info. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; /** * Functional tests for language configuration's effect on negotiation setup. */ -class LocaleConfigurationTest extends WebTestBase { +class LocaleConfigurationTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Language negotiation autoconfiguration', @@ -92,7 +90,7 @@ class LocaleConfigurationTest extends WebTestBase { /** * Functional tests for JavaScript parsing for translatable strings. */ -class LocaleJavascriptTranslationTest extends WebTestBase { +class LocaleJavascriptTranslationTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Javascript translation', @@ -181,7 +179,7 @@ class LocaleJavascriptTranslationTest extends WebTestBase { /** * Functional test for string translation and validation. */ -class LocaleTranslationFunctionalTest extends WebTestBase { +class LocaleTranslationFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'String translate, search and validate', @@ -589,7 +587,7 @@ class LocaleTranslationFunctionalTest extends WebTestBase { /** * Tests plural format handling functionality. */ -class LocalePluralFormatTest extends WebTestBase { +class LocalePluralFormatTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Plural handling', @@ -902,7 +900,7 @@ EOF; /** * Functional tests for the import of translation files. */ -class LocaleImportFunctionalTest extends WebTestBase { +class LocaleImportFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Translation import', @@ -1379,7 +1377,7 @@ EOF; /** * Functional tests for the export of translation files. */ -class LocaleExportFunctionalTest extends WebTestBase { +class LocaleExportFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Translation export', @@ -1521,7 +1519,7 @@ EOF; /** * Tests for the st() function. */ -class LocaleInstallTest extends WebTestBase { +class LocaleInstallTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'String translation using st()', @@ -1550,7 +1548,7 @@ class LocaleInstallTest extends WebTestBase { /** * Locale uninstall with English UI functional test. */ -class LocaleUninstallFunctionalTest extends WebTestBase { +class LocaleUninstallFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Locale uninstall (EN)', @@ -1696,7 +1694,7 @@ class LocaleUninstallFrenchFunctionalTest extends LocaleUninstallFunctionalTest /** * Functional tests for the language switching feature. */ -class LocaleLanguageSwitchingFunctionalTest extends WebTestBase { +class LocaleLanguageSwitchingFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1774,7 +1772,7 @@ class LocaleLanguageSwitchingFunctionalTest extends WebTestBase { /** * Test browser language detection. */ -class LocaleBrowserDetectionTest extends UnitTestBase { +class LocaleBrowserDetectionTest extends DrupalUnitTestCase { public static function getInfo() { return array( @@ -1895,7 +1893,7 @@ class LocaleBrowserDetectionTest extends UnitTestBase { /** * Functional tests for configuring a different path alias per language. */ -class LocalePathFunctionalTest extends WebTestBase { +class LocalePathFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Path language settings', @@ -1943,7 +1941,7 @@ class LocalePathFunctionalTest extends WebTestBase { // Check that the "xx" front page is readily available because path prefix // negotiation is pre-configured. $this->drupalGet($prefix); - $this->assertText(t('Welcome to Drupal'), t('The "xx" front page is readibly available.')); + $this->assertText(t('Welcome to Drupal'), t('The "xx" front page is readily available.')); // Create a node. $node = $this->drupalCreateNode(array('type' => 'page')); @@ -2034,7 +2032,7 @@ class LocalePathFunctionalTest extends WebTestBase { /** * Functional tests for multilingual support on nodes. */ -class LocaleContentFunctionalTest extends WebTestBase { +class LocaleContentFunctionalTest extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -2257,7 +2255,7 @@ class LocaleContentFunctionalTest extends WebTestBase { * http://example.cn/admin/config * UI language in Chinese */ -class LocaleUILanguageNegotiationTest extends WebTestBase { +class LocaleUILanguageNegotiationTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'UI language negotiation', @@ -2551,7 +2549,7 @@ class LocaleUILanguageNegotiationTest extends WebTestBase { /** * Test that URL rewriting works as expected. */ -class LocaleUrlRewritingTest extends WebTestBase { +class LocaleUrlRewritingTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'URL rewriting', @@ -2623,7 +2621,7 @@ class LocaleUrlRewritingTest extends WebTestBase { /** * Functional test for multilingual fields. */ -class LocaleMultilingualFieldsFunctionalTest extends WebTestBase { +class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Multilingual fields', @@ -2750,7 +2748,7 @@ class LocaleMultilingualFieldsFunctionalTest extends WebTestBase { /** * Functional tests for comment language. */ -class LocaleCommentLanguageFunctionalTest extends WebTestBase { +class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -2845,7 +2843,7 @@ class LocaleCommentLanguageFunctionalTest extends WebTestBase { /** * Functional tests for localizing date formats. */ -class LocaleDateFormatsFunctionalTest extends WebTestBase { +class LocaleDateFormatsFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( @@ -2917,7 +2915,7 @@ class LocaleDateFormatsFunctionalTest extends WebTestBase { /** * Functional test for language types/negotiation info. */ -class LocaleLanguageNegotiationInfoFunctionalTest extends WebTestBase { +class LocaleLanguageNegotiationInfoFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/menu/menu.test b/core/modules/menu/menu.test index 14fe96b..e1f2aa9 100644 --- a/core/modules/menu/menu.test +++ b/core/modules/menu/menu.test @@ -5,9 +5,7 @@ * Tests for menu.module. */ -use Drupal\simpletest\WebTestBase; - -class MenuTestCase extends WebTestBase { +class MenuTestCase extends DrupalWebTestCase { protected $profile = 'standard'; protected $big_user; @@ -585,7 +583,7 @@ class MenuTestCase extends WebTestBase { /** * Test menu settings for nodes. */ -class MenuNodeTestCase extends WebTestBase { +class MenuNodeTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { diff --git a/core/modules/node/node.module b/core/modules/node/node.module index 8dbc060..a21591e 100644 --- a/core/modules/node/node.module +++ b/core/modules/node/node.module @@ -1,10 +1,5 @@ \n"; - drupal_add_http_header('Content-Type', 'application/rss+xml; charset=utf-8'); - print $output; + return new Response($output, 200, array('Content-Type' => 'application/rss+xml; charset=utf-8')); } /** diff --git a/core/modules/node/node.test b/core/modules/node/node.test index deccada..ab053d1 100644 --- a/core/modules/node/node.test +++ b/core/modules/node/node.test @@ -1,14 +1,13 @@ format_date($nodes[1]->revision_timestamp), '@type' => 'Basic page', '%title' => $nodes[1]->title)), t('Revision deleted.')); $this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid and vid = :vid', array(':nid' => $node->nid, ':vid' => $nodes[1]->vid))->fetchField() == 0, t('Revision not found.')); - - // Set the revision timestamp to an older date to make sure that the - // confirmation message correctly displays the stored revision date. - $old_revision_date = REQUEST_TIME - 86400; - db_update('node_revision') - ->condition('vid', $nodes[2]->vid) - ->fields(array( - 'timestamp' => $old_revision_date, - )) - ->execute(); - $this->drupalPost("node/$node->nid/revisions/{$nodes[2]->vid}/revert", array(), t('Revert')); - $this->assertRaw(t('@type %title has been reverted back to the revision from %revision-date.', array( - '@type' => 'Basic page', - '%title' => $nodes[2]->title, - '%revision-date' => format_date($old_revision_date), - ))); } /** @@ -1785,7 +1768,7 @@ class NodeTitleTestCase extends NodeWebTestCase { /** * Test the node_feed() functionality. */ -class NodeFeedTestCase extends WebTestBase { +class NodeFeedTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Node feed', @@ -1798,11 +1781,8 @@ class NodeFeedTestCase extends WebTestBase { * Ensure that node_feed accepts and prints extra channel elements. */ function testNodeFeedExtraChannelElements() { - ob_start(); - node_feed(array(), array('copyright' => 'Drupal is a registered trademark of Dries Buytaert.')); - $output = ob_get_clean(); - - $this->assertTrue(strpos($output, 'Drupal is a registered trademark of Dries Buytaert.') !== FALSE); + $response = node_feed(array(), array('copyright' => 'Drupal is a registered trademark of Dries Buytaert.')); + $this->assertTrue(strpos($response->getContent(), 'Drupal is a registered trademark of Dries Buytaert.') !== FALSE); } } @@ -1945,7 +1925,7 @@ class NodeBlockFunctionalTest extends NodeWebTestCase { /** * Test multistep node forms basic options. */ -class MultiStepNodeFormBasicOptionsTest extends WebTestBase { +class MultiStepNodeFormBasicOptionsTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Multistep node form basic options', @@ -2440,7 +2420,7 @@ class NodeRevisionPermissionsTestCase extends NodeWebTestCase { /** * Tests pagination with a node access module enabled. */ -class NodeAccessPagerTestCase extends WebTestBase { +class NodeAccessPagerTestCase extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/openid/openid.test b/core/modules/openid/openid.test index 34e0567..1beea00 100644 --- a/core/modules/openid/openid.test +++ b/core/modules/openid/openid.test @@ -5,12 +5,10 @@ * Tests for openid.module. */ -use Drupal\simpletest\WebTestBase; - /** * Base class for OpenID tests. */ -abstract class OpenIDWebTestCase extends WebTestBase { +abstract class OpenIDWebTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { @@ -697,7 +695,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { /** * Test internal helper functions. */ -class OpenIDUnitTest extends WebTestBase { +class OpenIDUnitTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'OpenID helper functions', diff --git a/core/modules/openid/tests/openid_test.module b/core/modules/openid/tests/openid_test.module index ac49dbd..4481818 100644 --- a/core/modules/openid/tests/openid_test.module +++ b/core/modules/openid/tests/openid_test.module @@ -20,6 +20,9 @@ * key is used for verifying the signed messages from the provider. */ +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Response; + /** * Implements hook_menu(). */ @@ -97,8 +100,7 @@ function openid_test_yadis_xrds() { if (arg(3) == 'xri' && (arg(4) != '@example*résumé;%25' || $_GET['_xrd_r'] != 'application/xrds xml')) { drupal_not_found(); } - drupal_add_http_header('Content-Type', 'application/xrds+xml'); - print ' + $output = ' @@ -127,7 +129,7 @@ function openid_test_yadis_xrds() { '; if (arg(3) == 'server') { - print ' + $output .= ' http://specs.openid.net/auth/2.0/server http://example.com/this-has-too-low-priority @@ -138,7 +140,7 @@ function openid_test_yadis_xrds() { '; } elseif (arg(3) == 'delegate') { - print ' + $output .= ' http://specs.openid.net/auth/2.0/signon http://openid.net/srv/ax/1.0 @@ -146,9 +148,10 @@ function openid_test_yadis_xrds() { http://example.com/xrds-delegate '; } - print ' + $output .= ' '; + return new Response($output, 200, array('Content-type' => 'application/xrds+xml; charset=utf-8')); } else { return t('This is a regular HTML page. If the client sends an Accept: application/xrds+xml header when requesting this URL, an XRDS document is returned.'); @@ -207,11 +210,9 @@ function openid_test_html_openid2() { function openid_test_endpoint() { switch ($_REQUEST['openid_mode']) { case 'associate': - _openid_test_endpoint_associate(); - break; + return _openid_test_endpoint_associate(); case 'checkid_setup': - _openid_test_endpoint_authenticate(); - break; + return _openid_test_endpoint_authenticate(); } } @@ -226,8 +227,7 @@ function openid_test_redirect($count = 0) { $url = url('openid-test/redirect/' . --$count, array('absolute' => TRUE)); } $http_response_code = variable_get('openid_test_redirect_http_reponse_code', 301); - header('Location: ' . $url, TRUE, $http_response_code); - exit(); + return new RedirectResponse($url, $http_response_code); } /** @@ -283,8 +283,7 @@ function _openid_test_endpoint_associate() { // Respond to Relying Party in the special Key-Value Form Encoding (see OpenID // Authentication 1.0, section 4.1.1). - drupal_add_http_header('Content-Type', 'text/plain'); - print _openid_create_message($response); + return new Response(_openid_create_message($response), 200, array('Content-Type' => 'text/plain')); } /** @@ -306,9 +305,7 @@ function _openid_test_endpoint_authenticate() { 'openid.mode' => 'error', 'openid.error' => 'Unexpted identity', ); - drupal_add_http_header('Content-Type', 'text/plain'); - header('Location: ' . url($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE))); - return; + return new RedirectResponse(url($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE))); } // Generate unique identifier for this authentication. @@ -348,8 +345,7 @@ function _openid_test_endpoint_authenticate() { // Put the signed message into the query string of a URL supplied by the // Relying Party, and redirect the user. - drupal_add_http_header('Content-Type', 'text/plain'); - header('Location: ' . url($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE))); + return new RedirectResponse(url($_REQUEST['openid_return_to'], array('query' => $response, 'external', TRUE))); } /** diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module index 02c0883..2628260 100644 --- a/core/modules/overlay/overlay.module +++ b/core/modules/overlay/overlay.module @@ -5,6 +5,8 @@ * Displays the Drupal administration interface in an overlay. */ +use Symfony\Component\HttpFoundation\Response; + /** * Implements hook_help(). */ @@ -19,7 +21,7 @@ function overlay_help($path, $arg) { } /** - * Implements hook_menu(). + * Implements hook_menu() */ function overlay_menu() { $items['overlay-ajax/%'] = array( @@ -32,7 +34,7 @@ function overlay_menu() { $items['overlay/dismiss-message'] = array( 'title' => '', 'page callback' => 'overlay_user_dismiss_message', - 'access arguments' => array('access overlay'), + 'access callback' => 'overlay_user_dismiss_message_access', 'type' => MENU_CALLBACK, ); return $items; @@ -299,25 +301,44 @@ function overlay_page_alter(&$page) { } /** - * Menu callback; dismisses the overlay accessibility message for this user. + * Access callback; determines access to dismiss the overlay accessibility message. + * + * @see overlay_user_dismiss_message() + * @see overlay_menu() */ -function overlay_user_dismiss_message() { +function overlay_user_dismiss_message_access() { global $user; + if (!user_access('access overlay')) { + return FALSE; + } // It's unlikely, but possible that "access overlay" permission is granted to // the anonymous role. In this case, we do not display the message to disable - // the overlay, so there is nothing to dismiss. Also, protect against - // cross-site request forgeries by validating a token. - if (empty($user->uid) || !isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'overlay')) { - return MENU_ACCESS_DENIED; + // the overlay, so there is nothing to dismiss. + if (empty($user->uid)) { + return FALSE; } - else { - $account = user_load($user->uid); - $account->data['overlay_message_dismissed'] = 1; - $account->save(); - drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.')); - // Destination is normally given. Go to the user profile as a fallback. - drupal_goto('user/' . $user->uid . '/edit'); + // Protect against cross-site request forgeries by validating a token. + $token = request()->query->get('token'); + if (!isset($token) || !drupal_valid_token($token, 'overlay')) { + return FALSE; } + return TRUE; +} + +/** + * Menu callback; dismisses the overlay accessibility message for this user. + * + * @see overlay_user_dismiss_message_access() + * @see overlay_menu() + */ +function overlay_user_dismiss_message() { + global $user; + $account = user_load($user->uid); + $account->data['overlay_message_dismissed'] = 1; + $account->save(); + drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.')); + // Destination is normally given. Go to the user profile as a fallback. + drupal_goto('user/' . $user->uid . '/edit'); } /** @@ -667,7 +688,8 @@ function overlay_overlay_child_initialize() { // it to the same content rendered in overlay_exit(), at the end of the page // request. This allows us to check if anything actually did change, and, if // so, trigger an immediate Ajax refresh of the parent window. - if (!empty($_POST) || isset($_GET['token'])) { + $token = request()->query->get('token'); + if (!empty($_POST) || isset($token)) { foreach (overlay_supplemental_regions() as $region) { overlay_store_rendered_content($region, overlay_render_region($region)); } @@ -979,5 +1001,5 @@ function overlay_trigger_refresh() { * @see Drupal.overlay.refreshRegions() */ function overlay_ajax_render_region($region) { - print overlay_render_region($region); + return new Response(overlay_render_region($region)); } diff --git a/core/modules/path/path.test b/core/modules/path/path.test index bf80b4d..7150e61 100644 --- a/core/modules/path/path.test +++ b/core/modules/path/path.test @@ -5,12 +5,10 @@ * Tests for the Path module. */ -use Drupal\simpletest\WebTestBase; - /** * Provides a base class for testing the Path module. */ -class PathTestCase extends WebTestBase { +class PathTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { diff --git a/core/modules/php/php.test b/core/modules/php/php.test index 7f86ecc..f6009c7 100644 --- a/core/modules/php/php.test +++ b/core/modules/php/php.test @@ -5,12 +5,10 @@ * Tests for php.module. */ -use Drupal\simpletest\WebTestBase; - /** * Defines a base PHP test case class. */ -class PHPTestCase extends WebTestBase { +class PHPTestCase extends DrupalWebTestCase { protected $php_code_format; function setUp() { diff --git a/core/modules/poll/poll.test b/core/modules/poll/poll.test index b43c4073..cba67ba 100644 --- a/core/modules/poll/poll.test +++ b/core/modules/poll/poll.test @@ -5,9 +5,7 @@ * Tests for poll.module. */ -use Drupal\simpletest\WebTestBase; - -class PollWebTestCase extends WebTestBase { +class PollWebTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { @@ -95,7 +93,7 @@ class PollWebTestCase extends WebTestBase { * @return * An indexed array containing: * - The generated POST values, suitable for - * Drupal\simpletest\WebTestBase::drupalPost(). + * DrupalWebTestCase::drupalPost(). * - The number of poll choices contained in 'edit', for potential re-usage * in subsequent invocations of this function. */ @@ -436,7 +434,7 @@ class PollBlockTestCase extends PollWebTestCase { /** * Test adding new choices. */ -class PollJSAddChoice extends WebTestBase { +class PollJSAddChoice extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/rdf/rdf.test b/core/modules/rdf/rdf.test index 0c60f41..c160ccb 100644 --- a/core/modules/rdf/rdf.test +++ b/core/modules/rdf/rdf.test @@ -6,9 +6,8 @@ */ use Drupal\node\Node; -use Drupal\simpletest\WebTestBase; -class RdfMappingHookTestCase extends WebTestBase { +class RdfMappingHookTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'RDF mapping hook', @@ -44,7 +43,7 @@ class RdfMappingHookTestCase extends WebTestBase { /** * Test RDFa markup generation. */ -class RdfRdfaMarkupTestCase extends WebTestBase { +class RdfRdfaMarkupTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -213,7 +212,7 @@ class RdfRdfaMarkupTestCase extends WebTestBase { } } -class RdfCrudTestCase extends WebTestBase { +class RdfCrudTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'RDF mapping CRUD functions', @@ -579,7 +578,7 @@ class RdfCommentAttributesTestCase extends CommentHelperCase { } } -class RdfTrackerAttributesTestCase extends WebTestBase { +class RdfTrackerAttributesTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -696,7 +695,7 @@ class RdfTrackerAttributesTestCase extends WebTestBase { /** * Tests for RDF namespaces declaration with hook_rdf_namespaces(). */ -class RdfGetRdfNamespacesTestCase extends WebTestBase { +class RdfGetRdfNamespacesTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'RDF namespaces', @@ -726,7 +725,7 @@ class RdfGetRdfNamespacesTestCase extends WebTestBase { /** * Tests for RDF namespaces XML serialization. */ -class DrupalGetRdfNamespacesTestCase extends WebTestBase { +class DrupalGetRdfNamespacesTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'RDF namespaces serialization test', diff --git a/core/modules/search/search.test b/core/modules/search/search.test index 619055c..6085465 100644 --- a/core/modules/search/search.test +++ b/core/modules/search/search.test @@ -11,10 +11,7 @@ const SEARCH_TYPE = '_test_'; const SEARCH_TYPE_2 = '_test2_'; const SEARCH_TYPE_JPN = '_test3_'; -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - -class SearchWebTestCase extends WebTestBase { +class SearchWebTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { @@ -974,7 +971,7 @@ class SearchCommentTestCase extends SearchWebTestCase { * * @see http://drupal.org/node/419388 (issue) */ -class SearchExpressionInsertExtractTestCase extends UnitTestBase { +class SearchExpressionInsertExtractTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Search expression insert/extract', @@ -1592,7 +1589,7 @@ class SearchConfigSettingsForm extends SearchWebTestCase { /** * Tests the search_excerpt() function. */ -class SearchExcerptTestCase extends UnitTestBase { +class SearchExcerptTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Search excerpt extraction', diff --git a/core/modules/shortcut/shortcut.test b/core/modules/shortcut/shortcut.test index 815b732..550c10c 100644 --- a/core/modules/shortcut/shortcut.test +++ b/core/modules/shortcut/shortcut.test @@ -5,12 +5,10 @@ * Tests for shortcut.module. */ -use Drupal\simpletest\WebTestBase; - /** * Defines base class for shortcut test cases. */ -class ShortcutTestCase extends WebTestBase { +class ShortcutTestCase extends DrupalWebTestCase { /** * User with permission to administer shortcuts. diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/drupal_web_test_case.php similarity index 77% rename from core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php rename to core/modules/simpletest/drupal_web_test_case.php index 277e97b..8e59c54 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php +++ b/core/modules/simpletest/drupal_web_test_case.php @@ -1,25 +1,768 @@ 0, + '#fail' => 0, + '#exception' => 0, + '#debug' => 0, + ); + + /** + * Assertions thrown in that test case. + * + * @var Array + */ + protected $assertions = array(); + + /** + * This class is skipped when looking for the source of an assertion. + * + * When displaying which function an assert comes from, it's not too useful + * to see "drupalWebTestCase->drupalLogin()', we would like to see the test + * that called it. So we need to skip the classes defining these helper + * methods. + */ + protected $skipClasses = array(__CLASS__ => TRUE); + + /** + * Flag to indicate whether the test has been set up. + * + * The setUp() method isolates the test from the parent Drupal site by + * creating a random prefix for the database and setting up a clean file + * storage directory. The tearDown() method then cleans up this test + * environment. We must ensure that setUp() has been run. Otherwise, + * tearDown() will act on the parent Drupal site rather than the test + * environment, destroying live data. + */ + protected $setup = FALSE; + + /** + * Constructor for DrupalTestCase. + * + * @param $test_id + * Tests with the same id are reported together. + */ + public function __construct($test_id = NULL) { + $this->testId = $test_id; + } + + /** + * Checks the matching requirements for DrupalTestCase. + * + * @return + * Array of errors containing a list of unmet requirements. + */ + protected function checkRequirements() { + return array(); + } + + /** + * Internal helper: stores the assert. + * + * @param $status + * Can be 'pass', 'fail', 'exception'. + * TRUE is a synonym for 'pass', FALSE for 'fail'. + * @param $message + * The message string. + * @param $group + * Which group this assert belongs to. + * @param $caller + * By default, the assert comes from a function whose name starts with + * 'test'. Instead, you can specify where this assert originates from + * by passing in an associative array as $caller. Key 'file' is + * the name of the source file, 'line' is the line number and 'function' + * is the caller function itself. + */ + protected function assert($status, $message = '', $group = 'Other', array $caller = NULL) { + // Convert boolean status to string status. + if (is_bool($status)) { + $status = $status ? 'pass' : 'fail'; + } + + // Increment summary result counter. + $this->results['#' . $status]++; + + // Get the function information about the call to the assertion method. + if (!$caller) { + $caller = $this->getAssertionCall(); + } + + // Creation assertion array that can be displayed while tests are running. + $this->assertions[] = $assertion = array( + 'test_id' => $this->testId, + 'test_class' => get_class($this), + 'status' => $status, + 'message' => $message, + 'message_group' => $group, + 'function' => $caller['function'], + 'line' => $caller['line'], + 'file' => $caller['file'], + ); + + // Store assertion for display after the test has completed. + try { + $connection = Database::getConnection('default', 'simpletest_original_default'); + } + catch (ConnectionNotDefinedException $e) { + // If the test was not set up, the simpletest_original_default + // connection does not exist. + $connection = Database::getConnection('default', 'default'); + } + $connection + ->insert('simpletest') + ->fields($assertion) + ->execute(); + + // We do not use a ternary operator here to allow a breakpoint on + // test failure. + if ($status == 'pass') { + return TRUE; + } + else { + return FALSE; + } + } + + /** + * Store an assertion from outside the testing context. + * + * This is useful for inserting assertions that can only be recorded after + * the test case has been destroyed, such as PHP fatal errors. The caller + * information is not automatically gathered since the caller is most likely + * inserting the assertion on behalf of other code. In all other respects + * the method behaves just like DrupalTestCase::assert() in terms of storing + * the assertion. + * + * @return + * Message ID of the stored assertion. + * + * @see DrupalTestCase::assert() + * @see DrupalTestCase::deleteAssert() + */ + public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = array()) { + // Convert boolean status to string status. + if (is_bool($status)) { + $status = $status ? 'pass' : 'fail'; + } + + $caller += array( + 'function' => t('Unknown'), + 'line' => 0, + 'file' => t('Unknown'), + ); + + $assertion = array( + 'test_id' => $test_id, + 'test_class' => $test_class, + 'status' => $status, + 'message' => $message, + 'message_group' => $group, + 'function' => $caller['function'], + 'line' => $caller['line'], + 'file' => $caller['file'], + ); + + return db_insert('simpletest') + ->fields($assertion) + ->execute(); + } + + /** + * 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) { + return (bool) db_delete('simpletest') + ->condition('message_id', $message_id) + ->execute(); + } + + /** + * Cycles through backtrace until the first non-assertion method is found. + * + * @return + * Array representing the true caller. + */ + protected function getAssertionCall() { + $backtrace = debug_backtrace(); + + // 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')) { + // We remove that call. + array_shift($backtrace); + } + + return _drupal_get_last_caller($backtrace); + } + + /** + * Check to see if a value is not false (not an empty string, 0, NULL, or FALSE). + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertTrue($value, $message = '', $group = 'Other') { + return $this->assert((bool) $value, $message ? $message : t('Value @value is TRUE.', array('@value' => var_export($value, TRUE))), $group); + } + + /** + * Check to see if a value is false (an empty string, 0, NULL, or FALSE). + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertFalse($value, $message = '', $group = 'Other') { + return $this->assert(!$value, $message ? $message : t('Value @value is FALSE.', array('@value' => var_export($value, TRUE))), $group); + } + + /** + * Check to see if a value is NULL. + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertNull($value, $message = '', $group = 'Other') { + return $this->assert(!isset($value), $message ? $message : t('Value @value is NULL.', array('@value' => var_export($value, TRUE))), $group); + } + + /** + * Check to see if a value is not NULL. + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertNotNull($value, $message = '', $group = 'Other') { + return $this->assert(isset($value), $message ? $message : t('Value @value is not NULL.', array('@value' => var_export($value, TRUE))), $group); + } + + /** + * Check to see if two values are equal. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertEqual($first, $second, $message = '', $group = 'Other') { + return $this->assert($first == $second, $message ? $message : t('Value @first is equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); + } + + /** + * Check to see if two values are not equal. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertNotEqual($first, $second, $message = '', $group = 'Other') { + return $this->assert($first != $second, $message ? $message : t('Value @first is not equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); + } + + /** + * Check to see if two values are identical. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertIdentical($first, $second, $message = '', $group = 'Other') { + return $this->assert($first === $second, $message ? $message : t('Value @first is identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); + } + + /** + * Check to see if two values are not identical. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE if the assertion succeeded, FALSE otherwise. + */ + protected function assertNotIdentical($first, $second, $message = '', $group = 'Other') { + return $this->assert($first !== $second, $message ? $message : t('Value @first is not identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); + } + + /** + * Fire an assertion that is always positive. + * + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE. + */ + protected function pass($message = NULL, $group = 'Other') { + return $this->assert(TRUE, $message, $group); + } + + /** + * Fire an assertion that is always negative. + * + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * FALSE. + */ + protected function fail($message = NULL, $group = 'Other') { + return $this->assert(FALSE, $message, $group); + } + + /** + * Fire an error assertion. + * + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @param $caller + * The caller of the error. + * @return + * FALSE. + */ + protected function error($message = '', $group = 'Other', array $caller = NULL) { + if ($group == 'User notice') { + // Since 'User notice' is set by trigger_error() which is used for debug + // set the message to a status of 'debug'. + return $this->assert('debug', $message, 'Debug', $caller); + } + + return $this->assert('exception', $message, $group, $caller); + } + + /** + * Logs verbose message in a text file. + * + * The a link to the vebose message will be placed in the test results via + * as a passing assertion with the text '[verbose message]'. + * + * @param $message + * The verbose message to be stored. + * + * @see simpletest_verbose() + */ + protected function verbose($message) { + if ($id = simpletest_verbose($message)) { + $url = file_create_url($this->originalFileDirectory . '/simpletest/verbose/' . get_class($this) . '-' . $id . '.html'); + $this->error(l(t('Verbose message'), $url, array('attributes' => array('target' => '_blank'))), 'User notice'); + } + } + + /** + * Run all tests in this class. + * + * Regardless of whether $methods are passed or not, only method names + * starting with "test" are executed. + * + * @param $methods + * (optional) A list of method names in the test case class to run; e.g., + * array('testFoo', 'testBar'). By default, all methods of the class are + * taken into account, but it can be useful to only run a few selected test + * methods during debugging. + */ + public function run(array $methods = array()) { + // Initialize verbose debugging. + simpletest_verbose(NULL, variable_get('file_public_path', conf_path() . '/files'), get_class($this)); + + // HTTP auth settings (:) for the simpletest browser + // when sending requests to the test site. + $this->httpauth_method = variable_get('simpletest_httpauth_method', CURLAUTH_BASIC); + $username = variable_get('simpletest_httpauth_username', NULL); + $password = variable_get('simpletest_httpauth_password', NULL); + if ($username && $password) { + $this->httpauth_credentials = $username . ':' . $password; + } + + set_error_handler(array($this, 'errorHandler')); + $class = get_class($this); + // Iterate through all the methods in this class, unless a specific list of + // methods to run was passed. + $class_methods = get_class_methods($class); + if ($methods) { + $class_methods = array_intersect($class_methods, $methods); + } + $missing_requirements = $this->checkRequirements(); + if (!empty($missing_requirements)) { + $missing_requirements_object = new ReflectionObject($this); + $caller = array( + 'file' => $missing_requirements_object->getFileName(), + ); + foreach ($missing_requirements as $missing_requirement) { + DrupalTestCase::insertAssert($this->testId, $class, FALSE, $missing_requirement, 'Requirements check.', $caller); + } + } + else { + foreach ($class_methods as $method) { + // If the current method starts with "test", run it - it's a test. + if (strtolower(substr($method, 0, 4)) == 'test') { + // Insert a fail record. This will be deleted on completion to ensure + // that testing completed. + $method_info = new ReflectionMethod($class, $method); + $caller = array( + 'file' => $method_info->getFileName(), + 'line' => $method_info->getStartLine(), + 'function' => $class . '->' . $method . '()', + ); + $completion_check_id = DrupalTestCase::insertAssert($this->testId, $class, FALSE, t('The test did not complete due to a fatal error.'), 'Completion check', $caller); + $this->setUp(); + if ($this->setup) { + try { + $this->$method(); + // Finish up. + } + catch (Exception $e) { + $this->exceptionHandler($e); + } + $this->tearDown(); + } + else { + $this->fail(t("The test cannot be executed because it has not been set up properly.")); + } + // Remove the completion check record. + DrupalTestCase::deleteAssert($completion_check_id); + } + } + } + // Clear out the error messages and restore error handler. + drupal_get_messages(); + restore_error_handler(); + } + + /** + * Handle errors during test runs. + * + * Because this is registered in set_error_handler(), it has to be public. + * @see set_error_handler + */ + public function errorHandler($severity, $message, $file = NULL, $line = NULL) { + if ($severity & error_reporting()) { + $error_map = array( + E_STRICT => 'Run-time notice', + E_WARNING => 'Warning', + E_NOTICE => 'Notice', + E_CORE_ERROR => 'Core error', + E_CORE_WARNING => 'Core warning', + E_USER_ERROR => 'User error', + E_USER_WARNING => 'User warning', + E_USER_NOTICE => 'User notice', + E_RECOVERABLE_ERROR => 'Recoverable error', + ); + + $backtrace = debug_backtrace(); + $this->error($message, $error_map[$severity], _drupal_get_last_caller($backtrace)); + } + return TRUE; + } + + /** + * Handle exceptions. + * + * @see set_exception_handler + */ + protected function exceptionHandler($exception) { + $backtrace = $exception->getTrace(); + // Push on top of the backtrace the call that generated the exception. + array_unshift($backtrace, array( + 'line' => $exception->getLine(), + 'file' => $exception->getFile(), + )); + require_once DRUPAL_ROOT . '/core/includes/errors.inc'; + // The exception message is run through check_plain() by _drupal_decode_exception(). + $this->error(t('%type: !message in %function (line %line of %file).', _drupal_decode_exception($exception)), 'Uncaught exception', _drupal_get_last_caller($backtrace)); + } + + /** + * Generates a random string of ASCII characters of codes 32 to 126. + * + * The generated string includes alpha-numeric characters and common misc + * characters. Use this method when testing general input where the content + * is not restricted. + * + * @param $length + * Length of random string to generate. + * @return + * Randomly generated string. + */ + public static function randomString($length = 8) { + $str = ''; + for ($i = 0; $i < $length; $i++) { + $str .= chr(mt_rand(32, 126)); + } + return $str; + } + + /** + * Generates a random string containing letters and numbers. + * + * The string will always start with a letter. The letters may be upper or + * lower case. This method is better for restricted inputs that do not + * accept certain characters. For example, when testing input fields that + * require machine readable values (i.e. without spaces and non-standard + * characters) this method is best. + * + * @param $length + * Length of random string to generate. + * @return + * Randomly generated string. + */ + public static function randomName($length = 8) { + $values = array_merge(range(65, 90), range(97, 122), range(48, 57)); + $max = count($values) - 1; + $str = chr(mt_rand(97, 122)); + for ($i = 1; $i < $length; $i++) { + $str .= chr($values[mt_rand(0, $max)]); + } + return $str; + } + + /** + * Converts a list of possible parameters into a stack of permutations. + * + * Takes a list of parameters containing possible values, and converts all of + * them into a list of items containing every possible permutation. + * + * Example: + * @code + * $parameters = array( + * 'one' => array(0, 1), + * 'two' => array(2, 3), + * ); + * $permutations = $this->permute($parameters); + * // Result: + * $permutations == array( + * array('one' => 0, 'two' => 2), + * array('one' => 1, 'two' => 2), + * array('one' => 0, 'two' => 3), + * array('one' => 1, 'two' => 3), + * ) + * @endcode + * + * @param $parameters + * An associative array of parameters, keyed by parameter name, and whose + * values are arrays of parameter values. + * + * @return + * A list of permutations, which is an array of arrays. Each inner array + * contains the full list of parameters that have been passed, but with a + * single value only. + */ + public static function generatePermutations($parameters) { + $all_permutations = array(array()); + foreach ($parameters as $parameter => $values) { + $new_permutations = array(); + // Iterate over all values of the parameter. + foreach ($values as $value) { + // Iterate over all existing permutations. + foreach ($all_permutations as $permutation) { + // Add the new parameter value to existing permutations. + $new_permutations[] = $permutation + array($parameter => $value); + } + } + // Replace the old permutations with the new permutations. + $all_permutations = $new_permutations; + } + return $all_permutations; + } +} /** - * Test case for typical Drupal tests. + * Test case for Drupal unit tests. + * + * These tests can not access the database nor files. Calling any Drupal + * function that needs the database will throw exceptions. These include + * watchdog(), module_implements(), module_invoke_all() etc. */ -abstract class WebTestBase extends TestBase { +class DrupalUnitTestCase extends DrupalTestCase { + + /** + * Constructor for DrupalUnitTestCase. + */ + function __construct($test_id = NULL) { + parent::__construct($test_id); + $this->skipClasses[__CLASS__] = TRUE; + } + + /** + * Sets up unit test environment. + * + * Unlike DrupalWebTestCase::setUp(), DrupalUnitTestCase::setUp() does not + * install modules because tests are performed without accessing the database. + * Any required files must be explicitly included by the child class setUp() + * method. + */ + protected function setUp() { + global $conf; + + // Store necessary current values before switching to the test environment. + $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files'); + + // Reset all statics so that test is performed with a clean environment. + drupal_static_reset(); + + // Generate temporary prefixed database to ensure that tests have a clean starting point. + $this->databasePrefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}'); + // Create test directory. + $public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10); + file_prepare_directory($public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); + $conf['file_public_path'] = $public_files_directory; + + // Clone the current connection and replace the current prefix. + $connection_info = Database::getConnectionInfo('default'); + Database::renameConnection('default', 'simpletest_original_default'); + foreach ($connection_info as $target => $value) { + $connection_info[$target]['prefix'] = array( + 'default' => $value['prefix']['default'] . $this->databasePrefix, + ); + } + Database::addConnectionInfo('default', 'default', $connection_info['default']); + + // Set user agent to be consistent with web test case. + $_SERVER['HTTP_USER_AGENT'] = $this->databasePrefix; + + // If locale is enabled then t() will try to access the database and + // subsequently will fail as the database is not accessible. + $module_list = module_list(); + if (isset($module_list['locale'])) { + $this->originalModuleList = $module_list; + unset($module_list['locale']); + module_list(TRUE, FALSE, FALSE, $module_list); + } + $this->setup = TRUE; + } + + protected function tearDown() { + global $conf; + + // Get back to the original connection. + Database::removeConnection('default'); + Database::renameConnection('simpletest_original_default', 'default'); + + $conf['file_public_path'] = $this->originalFileDirectory; + // Restore modules if necessary. + if (isset($this->originalModuleList)) { + module_list(TRUE, FALSE, FALSE, $this->originalModuleList); + } + } +} + +/** + * Test case for typical Drupal tests. + */ +class DrupalWebTestCase extends DrupalTestCase { /** * The profile to install as a basis for testing. * @@ -94,8 +837,7 @@ abstract class WebTestBase extends TestBase { /** * Additional cURL options. * - * Drupal\simpletest\WebTestBase itself never sets this but always obeys what is - * set. + * DrupalWebTestCase itself never sets this but always obeys what is set. */ protected $additionalCurlOptions = array(); @@ -144,7 +886,7 @@ abstract class WebTestBase extends TestBase { protected $redirect_count; /** - * Constructor for Drupal\simpletest\WebTestBase. + * Constructor for DrupalWebTestCase. */ function __construct($test_id = NULL) { parent::__construct($test_id); @@ -539,14 +1281,14 @@ abstract class WebTestBase extends TestBase { * * The generated database table prefix is used for the Drupal installation * being performed for the test. It is also used as user agent HTTP header - * value by the cURL-based browser of Drupal\simpletest\WebTestBase, which is sent - * to the Drupal installation of the test. During early Drupal bootstrap, the - * user agent HTTP header is parsed, and if it matches, all database queries - * use the database table prefix that has been generated here. + * value by the cURL-based browser of DrupalWebTestCase, which is sent to the + * Drupal installation of the test. During early Drupal bootstrap, the user + * agent HTTP header is parsed, and if it matches, all database queries use + * the database table prefix that has been generated here. * - * @see Drupal\simpletest\WebTestBase::curlInitialize() + * @see DrupalWebTestCase::curlInitialize() * @see drupal_valid_test_ua() - * @see Drupal\simpletest\WebTestBase::setUp() + * @see DrupalWebTestCase::setUp() */ protected function prepareDatabasePrefix() { $this->databasePrefix = 'simpletest' . mt_rand(1000, 1000000); @@ -563,7 +1305,7 @@ abstract class WebTestBase extends TestBase { /** * Changes the database connection to the prefixed one. * - * @see Drupal\simpletest\WebTestBase::setUp() + * @see DrupalWebTestCase::setUp() */ protected function changeDatabasePrefix() { if (empty($this->databasePrefix)) { @@ -591,8 +1333,8 @@ abstract class WebTestBase extends TestBase { * Also sets up new resources for the testing environment, such as the public * filesystem and configuration directories. * - * @see Drupal\simpletest\WebTestBase::setUp() - * @see Drupal\simpletest\WebTestBase::tearDown() + * @see DrupalWebTestCase::setUp() + * @see DrupalWebTestCase::tearDown() */ protected function prepareEnvironment() { global $user, $language_interface, $conf; @@ -649,9 +1391,9 @@ abstract class WebTestBase extends TestBase { * Sets up a Drupal site for running functional and integration tests. * * Generates a random database prefix and installs Drupal with the specified - * installation profile in Drupal\simpletest\WebTestBase::$profile into the - * prefixed database. Afterwards, installs any additional modules specified by - * the test. + * installation profile in DrupalWebTestCase::$profile into the prefixed + * database. Afterwards, installs any additional modules specified by the + * test. * * After installation all caches are flushed and several configuration values * are reset to the values of the parent site executing the test, since the @@ -662,9 +1404,9 @@ abstract class WebTestBase extends TestBase { * List of modules to enable for the duration of the test. This can be * either a single array or a variable number of string arguments. * - * @see Drupal\simpletest\WebTestBase::prepareDatabasePrefix() - * @see Drupal\simpletest\WebTestBase::changeDatabasePrefix() - * @see Drupal\simpletest\WebTestBase::prepareEnvironment() + * @see DrupalWebTestCase::prepareDatabasePrefix() + * @see DrupalWebTestCase::changeDatabasePrefix() + * @see DrupalWebTestCase::prepareEnvironment() */ protected function setUp() { global $user, $language_interface, $conf; @@ -769,8 +1511,8 @@ abstract class WebTestBase extends TestBase { /** * Preload the registry from the testing site. * - * This method is called by Drupal\simpletest\WebTestBase::setUp(), and preloads - * the registry from the testing site to cut down on the time it takes to + * This method is called by DrupalWebTestCase::setUp(), and preloads the + * registry from the testing site to cut down on the time it takes to * set up a clean environment for the current test run. */ protected function preloadRegistry() { @@ -805,7 +1547,7 @@ abstract class WebTestBase extends TestBase { /** * Reset all data structures after having enabled new modules. * - * This method is called by Drupal\simpletest\WebTestBase::setUp() after enabling + * This method is called by DrupalWebTestCase::setUp() after enabling * the requested modules. It must be called again when additional modules * are enabled later. */ @@ -1055,9 +1797,9 @@ abstract class WebTestBase extends TestBase { // Errors are being sent via X-Drupal-Assertion-* headers, // generated by _drupal_log_error() in the exact form required - // by Drupal\simpletest\WebTestBase::error(). + // by DrupalWebTestCase::error(). if (preg_match('/^X-Drupal-Assertion-[0-9]+: (.*)$/', $header, $matches)) { - // Call Drupal\simpletest\WebTestBase::error() with the parameters from the header. + // Call DrupalWebTestCase::error() with the parameters from the header. call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1]))); } @@ -1153,6 +1895,7 @@ abstract class WebTestBase extends TestBase { * Retrieve a Drupal path or an absolute path and JSON decode the result. */ protected function drupalGetAJAX($path, array $options = array(), array $headers = array()) { + $headers[] = 'X-Requested-With: XMLHttpRequest'; return drupal_json_decode($this->drupalGet($path, $options, $headers)); } @@ -1360,6 +2103,7 @@ abstract class WebTestBase extends TestBase { } $content = $this->content; $drupal_settings = $this->drupalSettings; + $headers[] = 'X-Requested-With: XMLHttpRequest'; // Get the Ajax settings bound to the triggering element. if (!isset($ajax_settings)) { @@ -2864,3 +3608,51 @@ abstract class WebTestBase extends TestBase { } } } + +/** + * Logs verbose message in a text file. + * + * If verbose mode is enabled then page requests will be dumped to a file and + * presented on the test result screen. The messages will be placed in a file + * located in the simpletest directory in the original file system. + * + * @param $message + * The verbose message to be stored. + * @param $original_file_directory + * The original file directory, before it was changed for testing purposes. + * @param $test_class + * The active test case class. + * + * @return + * The ID of the message to be placed in related assertion messages. + * + * @see DrupalTestCase->originalFileDirectory + * @see DrupalWebTestCase->verbose() + */ +function simpletest_verbose($message, $original_file_directory = NULL, $test_class = NULL) { + static $file_directory = NULL, $class = NULL, $id = 1, $verbose = NULL; + + // Will pass first time during setup phase, and when verbose is TRUE. + if (!isset($original_file_directory) && !$verbose) { + return FALSE; + } + + if ($message && $file_directory) { + $message = '
ID #' . $id . ' (Previous | Next)
' . $message; + file_put_contents($file_directory . "/simpletest/verbose/$class-$id.html", $message, FILE_APPEND); + return $id++; + } + + if ($original_file_directory) { + $file_directory = $original_file_directory; + $class = $test_class; + $verbose = variable_get('simpletest_verbose', TRUE); + $directory = $file_directory . '/simpletest/verbose'; + $writable = file_prepare_directory($directory, FILE_CREATE_DIRECTORY); + if ($writable && !file_exists($directory . '/.htaccess')) { + file_put_contents($directory . '/.htaccess', "\nExpiresActive Off\n\n"); + } + return $writable; + } + return FALSE; +} diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php deleted file mode 100644 index 552b4e3..0000000 --- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php +++ /dev/null @@ -1,677 +0,0 @@ - 0, - '#fail' => 0, - '#exception' => 0, - '#debug' => 0, - ); - - /** - * Assertions thrown in that test case. - * - * @var Array - */ - protected $assertions = array(); - - /** - * This class is skipped when looking for the source of an assertion. - * - * When displaying which function an assert comes from, it's not too useful - * to see "WebTestBase->drupalLogin()', we would like to see the test - * that called it. So we need to skip the classes defining these helper - * methods. - */ - protected $skipClasses = array(__CLASS__ => TRUE); - - /** - * Flag to indicate whether the test has been set up. - * - * The setUp() method isolates the test from the parent Drupal site by - * creating a random prefix for the database and setting up a clean file - * storage directory. The tearDown() method then cleans up this test - * environment. We must ensure that setUp() has been run. Otherwise, - * tearDown() will act on the parent Drupal site rather than the test - * environment, destroying live data. - */ - protected $setup = FALSE; - - /** - * Constructor for Test. - * - * @param $test_id - * Tests with the same id are reported together. - */ - public function __construct($test_id = NULL) { - $this->testId = $test_id; - } - - /** - * Checks the matching requirements for Test. - * - * @return - * Array of errors containing a list of unmet requirements. - */ - protected function checkRequirements() { - return array(); - } - - /** - * Internal helper: stores the assert. - * - * @param $status - * Can be 'pass', 'fail', 'exception'. - * TRUE is a synonym for 'pass', FALSE for 'fail'. - * @param $message - * The message string. - * @param $group - * Which group this assert belongs to. - * @param $caller - * By default, the assert comes from a function whose name starts with - * 'test'. Instead, you can specify where this assert originates from - * by passing in an associative array as $caller. Key 'file' is - * the name of the source file, 'line' is the line number and 'function' - * is the caller function itself. - */ - protected function assert($status, $message = '', $group = 'Other', array $caller = NULL) { - // Convert boolean status to string status. - if (is_bool($status)) { - $status = $status ? 'pass' : 'fail'; - } - - // Increment summary result counter. - $this->results['#' . $status]++; - - // Get the function information about the call to the assertion method. - if (!$caller) { - $caller = $this->getAssertionCall(); - } - - // Creation assertion array that can be displayed while tests are running. - $this->assertions[] = $assertion = array( - 'test_id' => $this->testId, - 'test_class' => get_class($this), - 'status' => $status, - 'message' => $message, - 'message_group' => $group, - 'function' => $caller['function'], - 'line' => $caller['line'], - 'file' => $caller['file'], - ); - - // Store assertion for display after the test has completed. - try { - $connection = Database::getConnection('default', 'simpletest_original_default'); - } - catch (ConnectionNotDefinedException $e) { - // If the test was not set up, the simpletest_original_default - // connection does not exist. - $connection = Database::getConnection('default', 'default'); - } - $connection - ->insert('simpletest') - ->fields($assertion) - ->execute(); - - // We do not use a ternary operator here to allow a breakpoint on - // test failure. - if ($status == 'pass') { - return TRUE; - } - else { - return FALSE; - } - } - - /** - * Store an assertion from outside the testing context. - * - * This is useful for inserting assertions that can only be recorded after - * the test case has been destroyed, such as PHP fatal errors. The caller - * information is not automatically gathered since the caller is most likely - * inserting the assertion on behalf of other code. In all other respects - * the method behaves just like Drupal\simpletest\TestBase::assert() in terms - * of storing the assertion. - * - * @return - * Message ID of the stored assertion. - * - * @see Drupal\simpletest\TestBase::assert() - * @see Drupal\simpletest\TestBase::deleteAssert() - */ - public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = array()) { - // Convert boolean status to string status. - if (is_bool($status)) { - $status = $status ? 'pass' : 'fail'; - } - - $caller += array( - 'function' => t('Unknown'), - 'line' => 0, - 'file' => t('Unknown'), - ); - - $assertion = array( - 'test_id' => $test_id, - 'test_class' => $test_class, - 'status' => $status, - 'message' => $message, - 'message_group' => $group, - 'function' => $caller['function'], - 'line' => $caller['line'], - 'file' => $caller['file'], - ); - - return db_insert('simpletest') - ->fields($assertion) - ->execute(); - } - - /** - * 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 Drupal\simpletest\TestBase::insertAssert() - */ - public static function deleteAssert($message_id) { - return (bool) db_delete('simpletest') - ->condition('message_id', $message_id) - ->execute(); - } - - /** - * Cycles through backtrace until the first non-assertion method is found. - * - * @return - * Array representing the true caller. - */ - protected function getAssertionCall() { - $backtrace = debug_backtrace(); - - // 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')) { - // We remove that call. - array_shift($backtrace); - } - - return _drupal_get_last_caller($backtrace); - } - - /** - * Check to see if a value is not false (not an empty string, 0, NULL, or FALSE). - * - * @param $value - * The value on which the assertion is to be done. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertTrue($value, $message = '', $group = 'Other') { - return $this->assert((bool) $value, $message ? $message : t('Value @value is TRUE.', array('@value' => var_export($value, TRUE))), $group); - } - - /** - * Check to see if a value is false (an empty string, 0, NULL, or FALSE). - * - * @param $value - * The value on which the assertion is to be done. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertFalse($value, $message = '', $group = 'Other') { - return $this->assert(!$value, $message ? $message : t('Value @value is FALSE.', array('@value' => var_export($value, TRUE))), $group); - } - - /** - * Check to see if a value is NULL. - * - * @param $value - * The value on which the assertion is to be done. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertNull($value, $message = '', $group = 'Other') { - return $this->assert(!isset($value), $message ? $message : t('Value @value is NULL.', array('@value' => var_export($value, TRUE))), $group); - } - - /** - * Check to see if a value is not NULL. - * - * @param $value - * The value on which the assertion is to be done. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertNotNull($value, $message = '', $group = 'Other') { - return $this->assert(isset($value), $message ? $message : t('Value @value is not NULL.', array('@value' => var_export($value, TRUE))), $group); - } - - /** - * Check to see if two values are equal. - * - * @param $first - * The first value to check. - * @param $second - * The second value to check. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertEqual($first, $second, $message = '', $group = 'Other') { - return $this->assert($first == $second, $message ? $message : t('Value @first is equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); - } - - /** - * Check to see if two values are not equal. - * - * @param $first - * The first value to check. - * @param $second - * The second value to check. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertNotEqual($first, $second, $message = '', $group = 'Other') { - return $this->assert($first != $second, $message ? $message : t('Value @first is not equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); - } - - /** - * Check to see if two values are identical. - * - * @param $first - * The first value to check. - * @param $second - * The second value to check. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertIdentical($first, $second, $message = '', $group = 'Other') { - return $this->assert($first === $second, $message ? $message : t('Value @first is identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); - } - - /** - * Check to see if two values are not identical. - * - * @param $first - * The first value to check. - * @param $second - * The second value to check. - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE if the assertion succeeded, FALSE otherwise. - */ - protected function assertNotIdentical($first, $second, $message = '', $group = 'Other') { - return $this->assert($first !== $second, $message ? $message : t('Value @first is not identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); - } - - /** - * Fire an assertion that is always positive. - * - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * TRUE. - */ - protected function pass($message = NULL, $group = 'Other') { - return $this->assert(TRUE, $message, $group); - } - - /** - * Fire an assertion that is always negative. - * - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @return - * FALSE. - */ - protected function fail($message = NULL, $group = 'Other') { - return $this->assert(FALSE, $message, $group); - } - - /** - * Fire an error assertion. - * - * @param $message - * The message to display along with the assertion. - * @param $group - * The type of assertion - examples are "Browser", "PHP". - * @param $caller - * The caller of the error. - * @return - * FALSE. - */ - protected function error($message = '', $group = 'Other', array $caller = NULL) { - if ($group == 'User notice') { - // Since 'User notice' is set by trigger_error() which is used for debug - // set the message to a status of 'debug'. - return $this->assert('debug', $message, 'Debug', $caller); - } - - return $this->assert('exception', $message, $group, $caller); - } - - /** - * Logs verbose message in a text file. - * - * The a link to the vebose message will be placed in the test results via - * as a passing assertion with the text '[verbose message]'. - * - * @param $message - * The verbose message to be stored. - * - * @see simpletest_verbose() - */ - protected function verbose($message) { - if ($id = simpletest_verbose($message)) { - $url = file_create_url($this->originalFileDirectory . '/simpletest/verbose/' . get_class($this) . '-' . $id . '.html'); - $this->error(l(t('Verbose message'), $url, array('attributes' => array('target' => '_blank'))), 'User notice'); - } - } - - /** - * Run all tests in this class. - * - * Regardless of whether $methods are passed or not, only method names - * starting with "test" are executed. - * - * @param $methods - * (optional) A list of method names in the test case class to run; e.g., - * array('testFoo', 'testBar'). By default, all methods of the class are - * taken into account, but it can be useful to only run a few selected test - * methods during debugging. - */ - public function run(array $methods = array()) { - // Initialize verbose debugging. - simpletest_verbose(NULL, variable_get('file_public_path', conf_path() . '/files'), get_class($this)); - - // HTTP auth settings (:) for the simpletest browser - // when sending requests to the test site. - $this->httpauth_method = variable_get('simpletest_httpauth_method', CURLAUTH_BASIC); - $username = variable_get('simpletest_httpauth_username', NULL); - $password = variable_get('simpletest_httpauth_password', NULL); - if ($username && $password) { - $this->httpauth_credentials = $username . ':' . $password; - } - - set_error_handler(array($this, 'errorHandler')); - $class = get_class($this); - // Iterate through all the methods in this class, unless a specific list of - // methods to run was passed. - $class_methods = get_class_methods($class); - if ($methods) { - $class_methods = array_intersect($class_methods, $methods); - } - $missing_requirements = $this->checkRequirements(); - if (!empty($missing_requirements)) { - $missing_requirements_object = new ReflectionObject($this); - $caller = array( - 'file' => $missing_requirements_object->getFileName(), - ); - foreach ($missing_requirements as $missing_requirement) { - TestBase::insertAssert($this->testId, $class, FALSE, $missing_requirement, 'Requirements check.', $caller); - } - } - else { - foreach ($class_methods as $method) { - // If the current method starts with "test", run it - it's a test. - if (strtolower(substr($method, 0, 4)) == 'test') { - // Insert a fail record. This will be deleted on completion to ensure - // that testing completed. - $method_info = new ReflectionMethod($class, $method); - $caller = array( - 'file' => $method_info->getFileName(), - 'line' => $method_info->getStartLine(), - 'function' => $class . '->' . $method . '()', - ); - $completion_check_id = TestBase::insertAssert($this->testId, $class, FALSE, t('The test did not complete due to a fatal error.'), 'Completion check', $caller); - $this->setUp(); - if ($this->setup) { - try { - $this->$method(); - // Finish up. - } - catch (Exception $e) { - $this->exceptionHandler($e); - } - $this->tearDown(); - } - else { - $this->fail(t("The test cannot be executed because it has not been set up properly.")); - } - // Remove the completion check record. - TestBase::deleteAssert($completion_check_id); - } - } - } - // Clear out the error messages and restore error handler. - drupal_get_messages(); - restore_error_handler(); - } - - /** - * Handle errors during test runs. - * - * Because this is registered in set_error_handler(), it has to be public. - * @see set_error_handler - */ - public function errorHandler($severity, $message, $file = NULL, $line = NULL) { - if ($severity & error_reporting()) { - $error_map = array( - E_STRICT => 'Run-time notice', - E_WARNING => 'Warning', - E_NOTICE => 'Notice', - E_CORE_ERROR => 'Core error', - E_CORE_WARNING => 'Core warning', - E_USER_ERROR => 'User error', - E_USER_WARNING => 'User warning', - E_USER_NOTICE => 'User notice', - E_RECOVERABLE_ERROR => 'Recoverable error', - ); - - $backtrace = debug_backtrace(); - $this->error($message, $error_map[$severity], _drupal_get_last_caller($backtrace)); - } - return TRUE; - } - - /** - * Handle exceptions. - * - * @see set_exception_handler - */ - protected function exceptionHandler($exception) { - $backtrace = $exception->getTrace(); - // Push on top of the backtrace the call that generated the exception. - array_unshift($backtrace, array( - 'line' => $exception->getLine(), - 'file' => $exception->getFile(), - )); - require_once DRUPAL_ROOT . '/core/includes/errors.inc'; - // The exception message is run through check_plain() by _drupal_decode_exception(). - $this->error(t('%type: !message in %function (line %line of %file).', _drupal_decode_exception($exception)), 'Uncaught exception', _drupal_get_last_caller($backtrace)); - } - - /** - * Generates a random string of ASCII characters of codes 32 to 126. - * - * The generated string includes alpha-numeric characters and common misc - * characters. Use this method when testing general input where the content - * is not restricted. - * - * @param $length - * Length of random string to generate. - * @return - * Randomly generated string. - */ - public static function randomString($length = 8) { - $str = ''; - for ($i = 0; $i < $length; $i++) { - $str .= chr(mt_rand(32, 126)); - } - return $str; - } - - /** - * Generates a random string containing letters and numbers. - * - * The string will always start with a letter. The letters may be upper or - * lower case. This method is better for restricted inputs that do not - * accept certain characters. For example, when testing input fields that - * require machine readable values (i.e. without spaces and non-standard - * characters) this method is best. - * - * @param $length - * Length of random string to generate. - * @return - * Randomly generated string. - */ - public static function randomName($length = 8) { - $values = array_merge(range(65, 90), range(97, 122), range(48, 57)); - $max = count($values) - 1; - $str = chr(mt_rand(97, 122)); - for ($i = 1; $i < $length; $i++) { - $str .= chr($values[mt_rand(0, $max)]); - } - return $str; - } - - /** - * Converts a list of possible parameters into a stack of permutations. - * - * Takes a list of parameters containing possible values, and converts all of - * them into a list of items containing every possible permutation. - * - * Example: - * @code - * $parameters = array( - * 'one' => array(0, 1), - * 'two' => array(2, 3), - * ); - * $permutations = $this->permute($parameters); - * // Result: - * $permutations == array( - * array('one' => 0, 'two' => 2), - * array('one' => 1, 'two' => 2), - * array('one' => 0, 'two' => 3), - * array('one' => 1, 'two' => 3), - * ) - * @endcode - * - * @param $parameters - * An associative array of parameters, keyed by parameter name, and whose - * values are arrays of parameter values. - * - * @return - * A list of permutations, which is an array of arrays. Each inner array - * contains the full list of parameters that have been passed, but with a - * single value only. - */ - public static function generatePermutations($parameters) { - $all_permutations = array(array()); - foreach ($parameters as $parameter => $values) { - $new_permutations = array(); - // Iterate over all values of the parameter. - foreach ($values as $value) { - // Iterate over all existing permutations. - foreach ($all_permutations as $permutation) { - // Add the new parameter value to existing permutations. - $new_permutations[] = $permutation + array($parameter => $value); - } - } - // Replace the old permutations with the new permutations. - $all_permutations = $new_permutations; - } - return $all_permutations; - } -} diff --git a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php deleted file mode 100644 index 5b5850b..0000000 --- a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php +++ /dev/null @@ -1,92 +0,0 @@ -skipClasses[__CLASS__] = TRUE; - } - - /** - * Sets up unit test environment. - * - * Unlike Drupal\simpletest\WebTestBase::setUp(), UnitTestBase::setUp() does not - * install modules because tests are performed without accessing the database. - * Any required files must be explicitly included by the child class setUp() - * method. - */ - protected function setUp() { - global $conf; - - // Store necessary current values before switching to the test environment. - $this->originalFileDirectory = variable_get('file_public_path', conf_path() . '/files'); - - // Reset all statics so that test is performed with a clean environment. - drupal_static_reset(); - - // Generate temporary prefixed database to ensure that tests have a clean starting point. - $this->databasePrefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}'); - - // Create test directory. - $public_files_directory = $this->originalFileDirectory . '/simpletest/' . substr($this->databasePrefix, 10); - file_prepare_directory($public_files_directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS); - $conf['file_public_path'] = $public_files_directory; - - // Clone the current connection and replace the current prefix. - $connection_info = Database::getConnectionInfo('default'); - Database::renameConnection('default', 'simpletest_original_default'); - foreach ($connection_info as $target => $value) { - $connection_info[$target]['prefix'] = array( - 'default' => $value['prefix']['default'] . $this->databasePrefix, - ); - } - Database::addConnectionInfo('default', 'default', $connection_info['default']); - - // Set user agent to be consistent with web test case. - $_SERVER['HTTP_USER_AGENT'] = $this->databasePrefix; - - // If locale is enabled then t() will try to access the database and - // subsequently will fail as the database is not accessible. - $module_list = module_list(); - if (isset($module_list['locale'])) { - $this->originalModuleList = $module_list; - unset($module_list['locale']); - module_list(TRUE, FALSE, FALSE, $module_list); - } - $this->setup = TRUE; - } - - protected function tearDown() { - global $conf; - - // Get back to the original connection. - Database::removeConnection('default'); - Database::renameConnection('simpletest_original_default', 'default'); - - $conf['file_public_path'] = $this->originalFileDirectory; - // Restore modules if necessary. - if (isset($this->originalModuleList)) { - module_list(TRUE, FALSE, FALSE, $this->originalModuleList); - } - } -} diff --git a/core/modules/simpletest/simpletest.api.php b/core/modules/simpletest/simpletest.api.php index df6d634..04c080b 100644 --- a/core/modules/simpletest/simpletest.api.php +++ b/core/modules/simpletest/simpletest.api.php @@ -6,18 +6,6 @@ */ /** - * Global variable that holds information about the tests being run. - * - * An array, with the following keys: - * - 'test_run_id': the ID of the test being run, in the form 'simpletest_%" - * - 'in_child_site': TRUE if the current request is a cURL request from - * the parent site. - * - * @var array - */ -global $drupal_test_info; - -/** * @addtogroup hooks * @{ */ @@ -59,9 +47,9 @@ function hook_test_group_finished() { * This hook is called when an individual test has finished. * * @param - * $results The results of the test as gathered by Drupal\simpletest\WebTestBase. + * $results The results of the test as gathered by DrupalWebTestCase. * - * @see Drupal\simpletest\WebTestBase->results() + * @see DrupalWebTestCase->results */ function hook_test_finished($results) { } diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module index 38c360b..9bd735e 100644 --- a/core/modules/simpletest/simpletest.module +++ b/core/modules/simpletest/simpletest.module @@ -1,7 +1,6 @@ $match[4], 'file' => $match[3], ); - TestBase::insertAssert($test_id, $test_class, FALSE, $match[2], $match[1], $caller); + DrupalTestCase::insertAssert($test_id, $test_class, FALSE, $match[2], $match[1], $caller); } else { // Unknown format, place the entire message in the log. - TestBase::insertAssert($test_id, $test_class, FALSE, $line, 'Fatal error'); + DrupalTestCase::insertAssert($test_id, $test_class, FALSE, $line, 'Fatal error'); } $found = TRUE; } @@ -566,51 +565,3 @@ function simpletest_mail_alter(&$message) { $message['send'] = FALSE; } } - -/** - * Logs verbose message in a text file. - * - * If verbose mode is enabled then page requests will be dumped to a file and - * presented on the test result screen. The messages will be placed in a file - * located in the simpletest directory in the original file system. - * - * @param $message - * The verbose message to be stored. - * @param $original_file_directory - * The original file directory, before it was changed for testing purposes. - * @param $test_class - * The active test case class. - * - * @return - * The ID of the message to be placed in related assertion messages. - * - * @see Drupal\simpletest\TestBase->originalFileDirectory() - * @see Drupal\simpletest\WebTestBase->verbose() - */ -function simpletest_verbose($message, $original_file_directory = NULL, $test_class = NULL) { - static $file_directory = NULL, $class = NULL, $id = 1, $verbose = NULL; - - // Will pass first time during setup phase, and when verbose is TRUE. - if (!isset($original_file_directory) && !$verbose) { - return FALSE; - } - - if ($message && $file_directory) { - $message = '
ID #' . $id . ' (Previous | Next)
' . $message; - file_put_contents($file_directory . "/simpletest/verbose/$class-$id.html", $message, FILE_APPEND); - return $id++; - } - - if ($original_file_directory) { - $file_directory = $original_file_directory; - $class = $test_class; - $verbose = variable_get('simpletest_verbose', TRUE); - $directory = $file_directory . '/simpletest/verbose'; - $writable = file_prepare_directory($directory, FILE_CREATE_DIRECTORY); - if ($writable && !file_exists($directory . '/.htaccess')) { - file_put_contents($directory . '/.htaccess', "\nExpiresActive Off\n\n"); - } - return $writable; - } - return FALSE; -} diff --git a/core/modules/simpletest/simpletest.test b/core/modules/simpletest/simpletest.test index cc4e026..185a71a 100644 --- a/core/modules/simpletest/simpletest.test +++ b/core/modules/simpletest/simpletest.test @@ -5,10 +5,7 @@ * Tests for simpletest.module. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - -class SimpleTestFunctionalTest extends WebTestBase { +class SimpleTestFunctionalTest extends DrupalWebTestCase { /** * The results array that has been parsed by getTestResults(). */ @@ -326,7 +323,7 @@ class SimpleTestFunctionalTest extends WebTestBase { /** * Test internal testing framework browser. */ -class SimpleTestBrowserTestCase extends WebTestBase { +class SimpleTestBrowserTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'SimpleTest browser', @@ -341,7 +338,7 @@ class SimpleTestBrowserTestCase extends WebTestBase { } /** - * Test Drupal\simpletest\WebTestBase::getAbsoluteUrl(). + * Test DrupalWebTestCase::getAbsoluteUrl(). */ function testGetAbsoluteUrl() { $url = 'user/login'; @@ -385,7 +382,7 @@ EOF; } } -class SimpleTestMailCaptureTestCase extends WebTestBase { +class SimpleTestMailCaptureTestCase extends DrupalWebTestCase { /** * Implement getInfo(). */ @@ -464,7 +461,7 @@ class SimpleTestMailCaptureTestCase extends WebTestBase { /** * Test Folder creation */ -class SimpleTestFolderTestCase extends WebTestBase { +class SimpleTestFolderTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Testing SimpleTest setUp', @@ -486,7 +483,7 @@ class SimpleTestFolderTestCase extends WebTestBase { /** * Test required modules for tests. */ -class SimpleTestMissingDependentModuleUnitTest extends UnitTestBase { +class SimpleTestMissingDependentModuleUnitTest extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Testing dependent module test', @@ -508,13 +505,12 @@ class SimpleTestMissingDependentModuleUnitTest extends UnitTestBase { * Tests a test case that does not run parent::setUp() in its setUp() method. * * If a test case does not call parent::setUp(), running - * Drupal\simpletest\WebTestBase::tearDown() would destroy the main site's - * database tables. Therefore, we ensure that tests which are not set up - * properly are skipped. + * DrupalTestCase::tearDown() would destroy the main site's database tables. + * Therefore, we ensure that tests which are not set up properly are skipped. * - * @see Drupal\simpletest\WebTestBase + * @see DrupalTestCase */ -class SimpleTestBrokenSetUp extends WebTestBase { +class SimpleTestBrokenSetUp extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Broken SimpleTest method', @@ -575,7 +571,7 @@ class SimpleTestBrokenSetUp extends WebTestBase { /** * Tests missing requirements to run test. */ -class SimpleTestMissingCheckedRequirements extends WebTestBase { +class SimpleTestMissingCheckedRequirements extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Broken requirements test', @@ -624,7 +620,7 @@ class SimpleTestMissingCheckedRequirements extends WebTestBase { /** * Verifies that tests bundled with installation profile modules are found. */ -class SimpleTestInstallationProfileModuleTestsTestCase extends WebTestBase { +class SimpleTestInstallationProfileModuleTestsTestCase extends DrupalWebTestCase { /** * Use the Testing profile. * @@ -673,7 +669,7 @@ class SimpleTestInstallationProfileModuleTestsTestCase extends WebTestBase { * * @see SimpleTestInstallationProfileModuleTestsTestCase */ -class SimpleTestOtherInstallationProfileModuleTestsTestCase extends WebTestBase { +class SimpleTestOtherInstallationProfileModuleTestsTestCase extends DrupalWebTestCase { /** * Use the Minimal profile. * diff --git a/core/modules/statistics/statistics.test b/core/modules/statistics/statistics.test index bb28b01..3314761 100644 --- a/core/modules/statistics/statistics.test +++ b/core/modules/statistics/statistics.test @@ -5,12 +5,10 @@ * Tests for the Statistics module. */ -use Drupal\simpletest\WebTestBase; - /** * Defines a base class for testing the Statistics module. */ -class StatisticsTestCase extends WebTestBase { +class StatisticsTestCase extends DrupalWebTestCase { function setUp() { parent::setUp(array('node', 'block', 'statistics')); @@ -55,10 +53,10 @@ class StatisticsTestCase extends WebTestBase { /** * Tests that logging via statistics_exit() works for all pages. * - * We subclass WebTestBase rather than StatisticsTestCase, because we + * We subclass DrupalWebTestCase rather than StatisticsTestCase, because we * want to test requests from an anonymous user. */ -class StatisticsLoggingTestCase extends WebTestBase { +class StatisticsLoggingTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Statistics logging tests', @@ -321,7 +319,7 @@ class StatisticsBlockVisitorsTestCase extends StatisticsTestCase { /** * Tests the statistics administration screen. */ -class StatisticsAdminTestCase extends WebTestBase { +class StatisticsAdminTestCase extends DrupalWebTestCase { /** * A user that has permission to administer and access statistics. diff --git a/core/modules/syslog/syslog.test b/core/modules/syslog/syslog.test index 49da077..1f7ab2e 100644 --- a/core/modules/syslog/syslog.test +++ b/core/modules/syslog/syslog.test @@ -5,12 +5,10 @@ * Tests for syslog.module. */ -use Drupal\simpletest\WebTestBase; - /** * Tests the Syslog module functionality. */ -class SyslogTestCase extends WebTestBase { +class SyslogTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Syslog functionality', diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index dcc289a..075129d 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -5,6 +5,8 @@ * Admin page callbacks for the system module. */ +use Symfony\Component\HttpFoundation\Response; + /** * Menu callback; Provide the administration overview page. */ @@ -2268,6 +2270,9 @@ function system_batch_page() { if ($output === FALSE) { drupal_access_denied(); } + elseif ($output instanceof Response) { + return $output; + } elseif (isset($output)) { // Force a page without blocks or messages to // display a list of collected messages later. diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 0b66f2c..574a132 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -5,8 +5,6 @@ * Hooks provided by Drupal core and the System module. */ -use Drupal\Core\Utility\UpdateException; - /** * @addtogroup hooks * @{ @@ -2970,11 +2968,10 @@ function hook_install() { * @param $sandbox * Stores information for multipass updates. See above for more information. * - * @throws Drupal\Core\Utility\UpdateException, PDOException - * In case of error, update hooks should throw an instance of - * Drupal\Core\Utility\UpdateException with a meaningful message for the user. - * If a database query fails for whatever reason, it will throw a - * PDOException. + * @throws DrupalUpdateException, PDOException + * In case of error, update hooks should throw an instance of DrupalUpdateException + * with a meaningful message for the user. If a database query fails for whatever + * reason, it will throw a PDOException. * * @return * Optionally update hooks may return a translated string that will be displayed @@ -3025,7 +3022,7 @@ function hook_update_N(&$sandbox) { return t('The update did what it was supposed to do.'); // In case of an error, simply throw an exception with an error message. - throw new UpdateException('Something went wrong; here is what you should do.'); + throw new DrupalUpdateException('Something went wrong; here is what you should do.'); } /** diff --git a/core/modules/system/system.module b/core/modules/system/system.module index f26bb07..85f41c4 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -5,6 +5,8 @@ * Configuration system that lets administrators modify the workings of the site. */ +use Symfony\Component\HttpFoundation\Response; + /** * Maximum age of temporary files in seconds. */ @@ -1119,11 +1121,13 @@ function system_menu() { * * @see system_cron_access(). */ + function system_cron_page() { drupal_page_is_cacheable(FALSE); drupal_cron_run(); - // Returning nothing causes no output to be generated. + // HTTP 204 is "No content", meaning "I did what you asked and we're done." + return new Response('a', 204); } /** @@ -2013,8 +2017,11 @@ function system_add_module_assets() { * Implements hook_custom_theme(). */ function system_custom_theme() { - if (user_access('view the administration theme') && path_is_admin(current_path())) { - return variable_get('admin_theme'); + if ($request = request()) { + $path = $request->attributes->get('system_path'); + if (user_access('view the administration theme') && path_is_admin($path)) { + return variable_get('admin_theme'); + } } } diff --git a/core/modules/system/system.test b/core/modules/system/system.test index e4dc730..a938ea1 100644 --- a/core/modules/system/system.test +++ b/core/modules/system/system.test @@ -2,8 +2,6 @@ use Drupal\Core\Database\Database; use Drupal\Component\Graph\Graph; -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; /** * @file @@ -13,7 +11,7 @@ use Drupal\simpletest\UnitTestBase; /** * Helper class for module test cases. */ -class ModuleTestCase extends WebTestBase { +class ModuleTestCase extends DrupalWebTestCase { protected $admin_user; function setUp() { @@ -711,7 +709,7 @@ class ModuleRequiredTestCase extends ModuleTestCase { } } -class IPAddressBlockingTestCase extends WebTestBase { +class IPAddressBlockingTestCase extends DrupalWebTestCase { protected $blocking_user; /** @@ -790,7 +788,7 @@ class IPAddressBlockingTestCase extends WebTestBase { } } -class CronRunTestCase extends WebTestBase { +class CronRunTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Cron run', @@ -821,7 +819,7 @@ class CronRunTestCase extends WebTestBase { // Run cron anonymously with the valid cron key. $key = variable_get('cron_key', 'drupal'); $this->drupalGet('cron/' . $key); - $this->assertResponse(200); + $this->assertResponse(204); } /** @@ -922,7 +920,7 @@ class CronRunTestCase extends WebTestBase { } } -class AdminMetaTagTestCase extends WebTestBase { +class AdminMetaTagTestCase extends DrupalWebTestCase { /** * Implement getInfo(). */ @@ -945,7 +943,7 @@ class AdminMetaTagTestCase extends WebTestBase { } } -class DefaultMobileMetaTagsTestCase extends WebTestBase { +class DefaultMobileMetaTagsTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Default mobile meta tags', @@ -989,7 +987,7 @@ class DefaultMobileMetaTagsTestCase extends WebTestBase { /** * Tests custom access denied functionality. */ -class AccessDeniedTestCase extends WebTestBase { +class AccessDeniedTestCase extends DrupalWebTestCase { protected $admin_user; public static function getInfo() { @@ -1066,7 +1064,7 @@ class AccessDeniedTestCase extends WebTestBase { } } -class PageNotFoundTestCase extends WebTestBase { +class PageNotFoundTestCase extends DrupalWebTestCase { protected $admin_user; public static function getInfo() { @@ -1106,7 +1104,7 @@ class PageNotFoundTestCase extends WebTestBase { /** * Tests site maintenance functionality. */ -class SiteMaintenanceTestCase extends WebTestBase { +class SiteMaintenanceTestCase extends DrupalWebTestCase { protected $admin_user; public static function getInfo() { @@ -1210,7 +1208,7 @@ class SiteMaintenanceTestCase extends WebTestBase { /** * Tests generic date and time handling capabilities of Drupal. */ -class DateTimeFunctionalTest extends WebTestBase { +class DateTimeFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Date and time', @@ -1403,7 +1401,7 @@ class DateTimeFunctionalTest extends WebTestBase { } } -class PageTitleFiltering extends WebTestBase { +class PageTitleFiltering extends DrupalWebTestCase { protected $content_user; protected $saved_title; @@ -1512,7 +1510,7 @@ class PageTitleFiltering extends WebTestBase { /** * Test front page functionality and administration. */ -class FrontPageTestCase extends WebTestBase { +class FrontPageTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1566,7 +1564,7 @@ class FrontPageTestCase extends WebTestBase { } } -class SystemBlockTestCase extends WebTestBase { +class SystemBlockTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Block functionality', @@ -1633,7 +1631,7 @@ class SystemBlockTestCase extends WebTestBase { /** * Test main content rendering fallback provided by system module. */ -class SystemMainContentFallback extends WebTestBase { +class SystemMainContentFallback extends DrupalWebTestCase { protected $admin_user; protected $web_user; @@ -1711,7 +1709,7 @@ class SystemMainContentFallback extends WebTestBase { /** * Tests for the theme interface functionality. */ -class SystemThemeFunctionalTest extends WebTestBase { +class SystemThemeFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Theme interface functionality', @@ -1935,7 +1933,7 @@ class SystemThemeFunctionalTest extends WebTestBase { /** * Test token replacement in strings. */ -class TokenReplaceTestCase extends WebTestBase { +class TokenReplaceTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Token replacement', @@ -2091,7 +2089,7 @@ class TokenReplaceTestCase extends WebTestBase { } } -class InfoFileParserTestCase extends UnitTestBase { +class InfoFileParserTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Info file format parser', @@ -2165,7 +2163,7 @@ array_space[a b] = Value'; /** * Tests the effectiveness of hook_system_info_alter(). */ -class SystemInfoAlterTestCase extends WebTestBase { +class SystemInfoAlterTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'System info alter', @@ -2232,7 +2230,7 @@ class SystemInfoAlterTestCase extends WebTestBase { /** * Tests for the update system functionality. */ -class UpdateScriptFunctionalTest extends WebTestBase { +class UpdateScriptFunctionalTest extends DrupalWebTestCase { private $update_url; private $update_user; @@ -2401,7 +2399,7 @@ class UpdateScriptFunctionalTest extends WebTestBase { /** * Functional tests for the flood control mechanism. */ -class FloodFunctionalTest extends WebTestBase { +class FloodFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Flood control mechanism', @@ -2439,7 +2437,7 @@ class FloodFunctionalTest extends WebTestBase { /** * Test HTTP file downloading capability. */ -class RetrieveFileTestCase extends WebTestBase { +class RetrieveFileTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'HTTP file retrieval', @@ -2488,7 +2486,7 @@ class RetrieveFileTestCase extends WebTestBase { /** * Functional tests shutdown functions. */ -class ShutdownFunctionsTest extends WebTestBase { +class ShutdownFunctionsTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Shutdown functions', @@ -2520,7 +2518,7 @@ class ShutdownFunctionsTest extends WebTestBase { /** * Tests administrative overview pages. */ -class SystemAdminTestCase extends WebTestBase { +class SystemAdminTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Administrative pages', @@ -2635,7 +2633,7 @@ class SystemAdminTestCase extends WebTestBase { * * @see Drupal\Component\Graph\Graph */ -class GraphUnitTest extends UnitTestBase { +class GraphUnitTest extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Directed acyclic graph manipulation', @@ -2820,7 +2818,7 @@ class GraphUnitTest extends UnitTestBase { /** * Tests authorize.php and related hooks. */ -class SystemAuthorizeCase extends WebTestBase { +class SystemAuthorizeCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Authorize API', @@ -2873,7 +2871,7 @@ class SystemAuthorizeCase extends WebTestBase { /** * Test the handling of requests containing 'index.php'. */ -class SystemIndexPhpTest extends WebTestBase { +class SystemIndexPhpTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Index.php handling', diff --git a/core/modules/system/tests/actions.test b/core/modules/system/tests/actions.test index 469b16e..afcb686 100644 --- a/core/modules/system/tests/actions.test +++ b/core/modules/system/tests/actions.test @@ -1,8 +1,6 @@ 'Actions configuration', @@ -68,7 +66,7 @@ class ActionsConfigurationTestCase extends WebTestBase { /** * Test actions executing in a potential loop, and make sure they abort properly. */ -class ActionLoopTestCase extends WebTestBase { +class ActionLoopTestCase extends DrupalWebTestCase { protected $aid; public static function getInfo() { diff --git a/core/modules/system/tests/ajax.test b/core/modules/system/tests/ajax.test index 69b178b..49f1632 100644 --- a/core/modules/system/tests/ajax.test +++ b/core/modules/system/tests/ajax.test @@ -1,9 +1,6 @@ 'Batch processing', @@ -281,7 +277,7 @@ class BatchProcessingTestCase extends WebTestBase { /** * Tests for the Batch API Progress page. */ -class BatchPageTestCase extends WebTestBase { +class BatchPageTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Batch progress page', @@ -320,7 +316,7 @@ class BatchPageTestCase extends WebTestBase { * Tests the function _batch_api_percentage() to make sure that the rounding * works properly in all cases. */ -class BatchPercentagesUnitTestCase extends UnitTestBase { +class BatchPercentagesUnitTestCase extends DrupalUnitTestCase { protected $testCases = array(); public static function getInfo() { diff --git a/core/modules/system/tests/bootstrap.test b/core/modules/system/tests/bootstrap.test index 098e12e..7535617 100644 --- a/core/modules/system/tests/bootstrap.test +++ b/core/modules/system/tests/bootstrap.test @@ -1,9 +1,6 @@ drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar'))); $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), t('Caching was bypassed.')); $this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, t('Vary: Cookie header was not sent.')); - $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate, post-check=0, pre-check=0', t('Cache-Control header was sent.')); + $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'must-revalidate, no-cache, post-check=0, pre-check=0, private', t('Cache-Control header was sent.')); $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', t('Expires header was sent.')); $this->assertEqual($this->drupalGetHeader('Foo'), 'bar', t('Custom header was sent.')); @@ -234,7 +231,7 @@ class BootstrapPageCacheTestCase extends WebTestBase { } } -class BootstrapVariableTestCase extends WebTestBase { +class BootstrapVariableTestCase extends DrupalWebTestCase { function setUp() { parent::setUp('system_test'); @@ -284,7 +281,7 @@ class BootstrapVariableTestCase extends WebTestBase { /** * Test hook_boot() and hook_exit(). */ -class HookBootExitTestCase extends WebTestBase { +class HookBootExitTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -339,7 +336,7 @@ class HookBootExitTestCase extends WebTestBase { /** * Test drupal_get_filename()'s availability. */ -class BootstrapGetFilenameTestCase extends UnitTestBase { +class BootstrapGetFilenameTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( @@ -381,7 +378,7 @@ class BootstrapGetFilenameTestCase extends UnitTestBase { } } -class BootstrapTimerTestCase extends UnitTestBase { +class BootstrapTimerTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( @@ -416,7 +413,7 @@ class BootstrapTimerTestCase extends UnitTestBase { /** * Test that resetting static variables works. */ -class BootstrapResettableStaticTestCase extends UnitTestBase { +class BootstrapResettableStaticTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( @@ -455,7 +452,7 @@ class BootstrapResettableStaticTestCase extends UnitTestBase { /** * Test miscellaneous functions in bootstrap.inc. */ -class BootstrapMiscTestCase extends UnitTestBase { +class BootstrapMiscTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( @@ -501,7 +498,7 @@ class BootstrapMiscTestCase extends UnitTestBase { /** * Tests for overriding server variables via the API. */ -class BootstrapOverrideServerVariablesTestCase extends UnitTestBase { +class BootstrapOverrideServerVariablesTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Overriding server variables', diff --git a/core/modules/system/tests/cache.test b/core/modules/system/tests/cache.test index b1d45cf..66778ae 100644 --- a/core/modules/system/tests/cache.test +++ b/core/modules/system/tests/cache.test @@ -1,8 +1,6 @@ 'Alter hook functionality', @@ -76,7 +73,7 @@ class CommonDrupalAlterTestCase extends WebTestBase { * url() calls module_implements(), which may issue a db query, which requires * inheriting from a web test case rather than a unit test case. */ -class CommonURLUnitTestCase extends WebTestBase { +class CommonURLUnitTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'URL generation tests', @@ -283,7 +280,7 @@ class CommonURLUnitTestCase extends WebTestBase { /** * Tests for check_plain(), filter_xss(), format_string(), and check_url(). */ -class CommonXssUnitTestCase extends UnitTestBase { +class CommonXssUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( @@ -355,7 +352,7 @@ class CommonXssUnitTestCase extends UnitTestBase { /** * Tests file size parsing and formatting functions. */ -class CommonSizeUnitTestCase extends UnitTestBase { +class CommonSizeUnitTestCase extends DrupalUnitTestCase { protected $exact_test_cases; protected $rounded_test_cases; @@ -455,7 +452,7 @@ class CommonSizeUnitTestCase extends UnitTestBase { /** * Test drupal_explode_tags() and drupal_implode_tags(). */ -class CommonAutocompleteTagsTestCase extends UnitTestBase { +class CommonAutocompleteTagsTestCase extends DrupalUnitTestCase { var $validTags = array( 'Drupal' => 'Drupal', 'Drupal with some spaces' => 'Drupal with some spaces', @@ -512,7 +509,7 @@ class CommonAutocompleteTagsTestCase extends UnitTestBase { /** * Test the Drupal CSS system. */ -class CommonCascadingStylesheetsTestCase extends WebTestBase { +class CommonCascadingStylesheetsTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Cascading stylesheets', @@ -746,7 +743,7 @@ class CommonCascadingStylesheetsTestCase extends WebTestBase { /** * Test for cleaning HTML identifiers. */ -class CommonHTMLIdentifierTestCase extends UnitTestBase { +class CommonHTMLIdentifierTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'HTML identifiers', @@ -806,7 +803,7 @@ class CommonHTMLIdentifierTestCase extends UnitTestBase { /** * CSS Unit Tests. */ -class CommonCascadingStylesheetsUnitTestCase extends UnitTestBase { +class CommonCascadingStylesheetsUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'CSS Unit Tests', @@ -858,7 +855,7 @@ class CommonCascadingStylesheetsUnitTestCase extends UnitTestBase { /** * Test drupal_http_request(). */ -class CommonDrupalHTTPRequestTestCase extends WebTestBase { +class CommonDrupalHTTPRequestTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Drupal HTTP request', @@ -990,7 +987,7 @@ class CommonDrupalHTTPRequestTestCase extends WebTestBase { /** * Tests drupal_add_region_content() and drupal_get_region_content(). */ -class CommonRegionContentTestCase extends WebTestBase { +class CommonRegionContentTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Region content', @@ -1035,7 +1032,7 @@ class CommonRegionContentTestCase extends WebTestBase { /** * Tests drupal_goto() and hook_drupal_goto_alter(). */ -class CommonDrupalGotoTestCase extends WebTestBase { +class CommonDrupalGotoTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Redirect functionality', @@ -1104,7 +1101,7 @@ class CommonDrupalGotoTestCase extends WebTestBase { /** * Tests for the JavaScript system. */ -class CommonJavaScriptTestCase extends WebTestBase { +class CommonJavaScriptTestCase extends DrupalWebTestCase { /** * Store configured value for JavaScript preprocessing. */ @@ -1561,7 +1558,7 @@ class CommonJavaScriptTestCase extends WebTestBase { /** * Tests for drupal_render(). */ -class CommonDrupalRenderTestCase extends WebTestBase { +class CommonDrupalRenderTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'drupal_render()', @@ -1837,7 +1834,7 @@ class CommonDrupalRenderTestCase extends WebTestBase { . '
' . $this->drupalGetContent() ); - // @see Drupal\simpletest\WebTestBase::xpath() + // @see DrupalWebTestCase::xpath() $xpath = $this->buildXPathQuery($xpath, $xpath_args); $element += array('#value' => NULL); $this->assertFieldByXPath($xpath, $element['#value'], t('#type @type was properly rendered.', array( @@ -1880,7 +1877,7 @@ class CommonDrupalRenderTestCase extends WebTestBase { /** * Tests URL validation by valid_url(). */ -class CommonValidUrlUnitTestCase extends UnitTestBase { +class CommonValidUrlUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'URL validation', @@ -1988,7 +1985,7 @@ class CommonValidUrlUnitTestCase extends UnitTestBase { /** * Tests number step validation by valid_number_step(). */ -class CommonValidNumberStepUnitTestCase extends UnitTestBase { +class CommonValidNumberStepUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Number step validation', @@ -2055,7 +2052,7 @@ class CommonValidNumberStepUnitTestCase extends UnitTestBase { /** * Tests writing of data records with drupal_write_record(). */ -class CommonDrupalWriteRecordTestCase extends WebTestBase { +class CommonDrupalWriteRecordTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Data record write functionality', @@ -2191,13 +2188,13 @@ class CommonDrupalWriteRecordTestCase extends WebTestBase { /** * Tests SimpleTest error and exception collector. */ -class CommonSimpleTestErrorCollectorTestCase extends WebTestBase { +class CommonSimpleTestErrorCollectorTestCase extends DrupalWebTestCase { /** * Errors triggered during the test. * * Errors are intercepted by the overriden implementation - * of Drupal\simpletest\WebTestBase::error() below. + * of DrupalWebTestCase::error below. * * @var Array */ @@ -2282,7 +2279,7 @@ class CommonSimpleTestErrorCollectorTestCase extends WebTestBase { /** * Tests the drupal_parse_info_file() API function. */ -class CommonDrupalParseInfoFileTestCase extends UnitTestBase { +class CommonDrupalParseInfoFileTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Parsing .info files', @@ -2305,7 +2302,7 @@ class CommonDrupalParseInfoFileTestCase extends UnitTestBase { /** * Tests scanning system directories in drupal_system_listing(). */ -class CommonDrupalSystemListingTestCase extends WebTestBase { +class CommonDrupalSystemListingTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Drupal system listing', @@ -2360,7 +2357,7 @@ class CommonDrupalSystemListingTestCase extends WebTestBase { /** * Tests the format_date() function. */ -class CommonFormatDateTestCase extends WebTestBase { +class CommonFormatDateTestCase extends DrupalWebTestCase { /** * Arbitrary langcode for a custom language. @@ -2489,7 +2486,7 @@ class CommonFormatDateTestCase extends WebTestBase { /** * Tests the drupal_attributes() functionality. */ -class CommonDrupalAttributesUnitTestCase extends UnitTestBase { +class CommonDrupalAttributesUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'HTML Attributes', @@ -2529,7 +2526,7 @@ class CommonDrupalAttributesUnitTestCase extends UnitTestBase { /** * Tests the various drupal_array_* helper functions. */ -class CommonDrupalArrayUnitTest extends UnitTestBase { +class CommonDrupalArrayUnitTest extends DrupalUnitTestCase { /** * Form array to check. @@ -2641,7 +2638,7 @@ class CommonDrupalArrayUnitTest extends UnitTestBase { /** * Tests the drupal_json_encode() and drupal_json_decode() functions. */ -class CommonJSONUnitTestCase extends UnitTestBase { +class CommonJSONUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'JSON', @@ -2705,7 +2702,7 @@ class CommonJSONUnitTestCase extends UnitTestBase { /** * Basic tests for drupal_add_feed(). */ -class CommonDrupalAddFeedTestCase extends WebTestBase { +class CommonDrupalAddFeedTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'drupal_add_feed() tests', diff --git a/core/modules/system/tests/database.test b/core/modules/system/tests/database.test index 889a30c..bec0c16 100644 --- a/core/modules/system/tests/database.test +++ b/core/modules/system/tests/database.test @@ -8,7 +8,6 @@ use Drupal\Core\Database\TransactionNoActiveException; use Drupal\Core\Database\Query\Merge; use Drupal\Core\Database\Query\InvalidMergeQueryException; use Drupal\Core\Database\Query\NoFieldsException; -use Drupal\simpletest\WebTestBase; /** * Dummy class for fetching into a class. @@ -25,7 +24,7 @@ class FakeRecord { } * Because all database tests share the same test data, we can centralize that * here. */ -class DatabaseTestCase extends WebTestBase { +class DatabaseTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { @@ -2959,7 +2958,7 @@ class DatabaseSerializeQueryTestCase extends DatabaseTestCase { /** * Range query tests. */ -class DatabaseRangeQueryTestCase extends WebTestBase { +class DatabaseRangeQueryTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Range query test', @@ -2990,7 +2989,7 @@ class DatabaseRangeQueryTestCase extends WebTestBase { /** * Temporary query tests. */ -class DatabaseTemporaryQueryTestCase extends WebTestBase { +class DatabaseTemporaryQueryTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Temporary query test', @@ -3748,7 +3747,7 @@ class DatabaseTransactionTestCase extends DatabaseTestCase { /** * Check the sequences API. */ -class DatabaseNextIdCase extends WebTestBase { +class DatabaseNextIdCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('Sequences API'), @@ -3775,7 +3774,7 @@ class DatabaseNextIdCase extends WebTestBase { /** * Tests the empty pseudo-statement class. */ -class DatabaseEmptyStatementTestCase extends WebTestBase { +class DatabaseEmptyStatementTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('Empty statement'), diff --git a/core/modules/system/tests/error.test b/core/modules/system/tests/error.test index a088902..e05cef4 100644 --- a/core/modules/system/tests/error.test +++ b/core/modules/system/tests/error.test @@ -3,10 +3,7 @@ /** * Tests Drupal error and exception handlers. */ - -use Drupal\simpletest\WebTestBase; - -class DrupalErrorHandlerUnitTest extends WebTestBase { +class DrupalErrorHandlerUnitTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Drupal error handlers', @@ -75,14 +72,14 @@ class DrupalErrorHandlerUnitTest extends WebTestBase { '%type' => 'Exception', '!message' => 'Drupal is awesome', '%function' => 'error_test_trigger_exception()', - '%line' => 57, + '%line' => 56, '%file' => drupal_get_path('module', 'error_test') . '/error_test.module', ); $error_pdo_exception = array( - '%type' => 'PDOException', + '%type' => 'DatabaseExceptionWrapper', '!message' => 'SELECT * FROM bananas_are_awesome', '%function' => 'error_test_trigger_pdo_exception()', - '%line' => 65, + '%line' => 64, '%file' => drupal_get_path('module', 'error_test') . '/error_test.module', ); diff --git a/core/modules/system/tests/file.test b/core/modules/system/tests/file.test index 78455e4..ab93009 100644 --- a/core/modules/system/tests/file.test +++ b/core/modules/system/tests/file.test @@ -6,8 +6,6 @@ * These include FileValidateTest and FileSaveTest. */ -use Drupal\simpletest\WebTestBase; - /** * Helper validator that returns the $errors parameter. */ @@ -48,7 +46,7 @@ function file_test_file_scan_callback_reset() { * Base class for file tests that adds some additional file specific * assertions and helper functions. */ -class FileTestCase extends WebTestBase { +class FileTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); @@ -376,7 +374,7 @@ class FileSpaceUsedTest extends FileTestCase { /** * This will run tests against the file validation functions (file_validate_*). */ -class FileValidatorTest extends WebTestBase { +class FileValidatorTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'File validator tests', @@ -2631,7 +2629,7 @@ class FileNameMungingTest extends FileTestCase { /** * Tests for file_get_mimetype(). */ -class FileMimeTypeTest extends WebTestBase { +class FileMimeTypeTest extends DrupalWebTestCase { function setUp() { parent::setUp('file_test'); } @@ -2716,7 +2714,7 @@ class FileMimeTypeTest extends WebTestBase { /** * Tests stream wrapper functions. */ -class StreamWrapperTest extends WebTestBase { +class StreamWrapperTest extends DrupalWebTestCase { protected $scheme = 'dummy'; protected $classname = 'DrupalDummyStreamWrapper'; diff --git a/core/modules/system/tests/filetransfer.test b/core/modules/system/tests/filetransfer.test index 3f88f4b..8f447d9 100644 --- a/core/modules/system/tests/filetransfer.test +++ b/core/modules/system/tests/filetransfer.test @@ -2,9 +2,8 @@ use Drupal\Core\FileTransfer\FileTransfer; use Drupal\Core\FileTransfer\FileTransferException; -use Drupal\simpletest\WebTestBase; -class FileTranferTest extends WebTestBase { +class FileTranferTest extends DrupalWebTestCase { protected $hostname = 'localhost'; protected $username = 'drupal'; protected $password = 'password'; diff --git a/core/modules/system/tests/form.test b/core/modules/system/tests/form.test index fe5f922..dbb2ff5 100644 --- a/core/modules/system/tests/form.test +++ b/core/modules/system/tests/form.test @@ -5,9 +5,7 @@ * Unit tests for the Drupal Form API. */ -use Drupal\simpletest\WebTestBase; - -class FormsTestCase extends WebTestBase { +class FormsTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -560,7 +558,7 @@ class FormsTestCase extends WebTestBase { /** * Tests building and processing of core form elements. */ -class FormElementTestCase extends WebTestBase { +class FormElementTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Element processing', @@ -641,7 +639,7 @@ class FormElementTestCase extends WebTestBase { /** * Test form alter hooks. */ -class FormAlterTestCase extends WebTestBase { +class FormAlterTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Form alter hooks', @@ -675,7 +673,7 @@ class FormAlterTestCase extends WebTestBase { /** * Test form validation handlers. */ -class FormValidationTestCase extends WebTestBase { +class FormValidationTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Form validation handlers', @@ -850,7 +848,7 @@ class FormValidationTestCase extends WebTestBase { /** * Test form element labels, required markers and associated output. */ -class FormsElementsLabelsTestCase extends WebTestBase { +class FormsElementsLabelsTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -937,7 +935,7 @@ class FormsElementsLabelsTestCase extends WebTestBase { /** * Test the tableselect form element for expected behavior. */ -class FormsElementsTableSelectFunctionalTest extends WebTestBase { +class FormsElementsTableSelectFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1163,7 +1161,7 @@ class FormsElementsTableSelectFunctionalTest extends WebTestBase { /** * Test the vertical_tabs form element for expected behavior. */ -class FormsElementsVerticalTabsFunctionalTest extends WebTestBase { +class FormsElementsVerticalTabsFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1199,7 +1197,7 @@ class FormsElementsVerticalTabsFunctionalTest extends WebTestBase { * when a validation error occurs, it makes sure that changed form element * values aren't lost due to a wrong form rebuild. */ -class FormsFormStorageTestCase extends WebTestBase { +class FormsFormStorageTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1343,7 +1341,7 @@ class FormsFormStorageTestCase extends WebTestBase { /** * Test wrapper form callbacks. */ -class FormsFormWrapperTestCase extends WebTestBase { +class FormsFormWrapperTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Form wrapper callback', @@ -1369,7 +1367,7 @@ class FormsFormWrapperTestCase extends WebTestBase { /** * Test $form_state clearance. */ -class FormStateValuesCleanTestCase extends WebTestBase { +class FormStateValuesCleanTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Form state values clearance', @@ -1417,7 +1415,7 @@ class FormStateValuesCleanTestCase extends WebTestBase { /** * Tests $form_state clearance with form elements having buttons. */ -class FormStateValuesCleanAdvancedTestCase extends WebTestBase { +class FormStateValuesCleanAdvancedTestCase extends DrupalWebTestCase { /** * An image file path for uploading. */ @@ -1464,7 +1462,7 @@ class FormStateValuesCleanAdvancedTestCase extends WebTestBase { * * @todo Add tests for other aspects of form rebuilding. */ -class FormsRebuildTestCase extends WebTestBase { +class FormsRebuildTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Form rebuilding', @@ -1558,7 +1556,7 @@ class FormsRebuildTestCase extends WebTestBase { /** * Test the programmatic form submission behavior. */ -class FormsProgrammaticTestCase extends WebTestBase { +class FormsProgrammaticTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1647,7 +1645,7 @@ class FormsProgrammaticTestCase extends WebTestBase { /** * Test that FAPI correctly determines $form_state['triggering_element']. */ -class FormsTriggeringElementTestCase extends WebTestBase { +class FormsTriggeringElementTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1745,7 +1743,7 @@ class FormsTriggeringElementTestCase extends WebTestBase { /** * Tests rebuilding of arbitrary forms by altering them. */ -class FormsArbitraryRebuildTestCase extends WebTestBase { +class FormsArbitraryRebuildTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Rebuild arbitrary forms', @@ -1811,7 +1809,7 @@ class FormsArbitraryRebuildTestCase extends WebTestBase { /** * Tests form API file inclusion. */ -class FormsFileInclusionTestCase extends WebTestBase { +class FormsFileInclusionTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1845,7 +1843,7 @@ class FormsFileInclusionTestCase extends WebTestBase { /** * Tests checkbox element. */ -class FormCheckboxTestCase extends WebTestBase { +class FormCheckboxTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1926,7 +1924,7 @@ class FormCheckboxTestCase extends WebTestBase { /** * Tests email element. */ -class FormEmailTestCase extends WebTestBase { +class FormEmailTestCase extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { @@ -1970,7 +1968,7 @@ class FormEmailTestCase extends WebTestBase { /** * Tests url element. */ -class FormUrlTestCase extends WebTestBase { +class FormUrlTestCase extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { diff --git a/core/modules/system/tests/image.test b/core/modules/system/tests/image.test index ab9eaa4..deead57 100644 --- a/core/modules/system/tests/image.test +++ b/core/modules/system/tests/image.test @@ -5,12 +5,10 @@ * Tests for core image handling API. */ -use Drupal\simpletest\WebTestBase; - /** * Base class for image manipulation testing. */ -class ImageToolkitTestCase extends WebTestBase { +class ImageToolkitTestCase extends DrupalWebTestCase { protected $toolkit; protected $file; protected $image; @@ -196,7 +194,7 @@ class ImageToolkitUnitTest extends ImageToolkitTestCase { /** * Test the core GD image manipulation functions. */ -class ImageToolkitGdTestCase extends WebTestBase { +class ImageToolkitGdTestCase extends DrupalWebTestCase { // Colors that are used in testing. protected $black = array(0, 0, 0, 0); protected $red = array(255, 0, 0, 0); diff --git a/core/modules/system/tests/installer.test b/core/modules/system/tests/installer.test index f076ba9..82e9957 100644 --- a/core/modules/system/tests/installer.test +++ b/core/modules/system/tests/installer.test @@ -5,12 +5,10 @@ * Tests for the installer. */ -use Drupal\simpletest\WebTestBase; - /** * Tests installer language detection. */ -class InstallerLanguageTestCase extends WebTestBase { +class InstallerLanguageTestCase extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/system/tests/lock.test b/core/modules/system/tests/lock.test index 65dcf80..c92846b 100644 --- a/core/modules/system/tests/lock.test +++ b/core/modules/system/tests/lock.test @@ -3,10 +3,7 @@ /** * Tests for the lock system. */ - -use Drupal\simpletest\WebTestBase; - -class LockFunctionalTest extends WebTestBase { +class LockFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/system/tests/mail.test b/core/modules/system/tests/mail.test index 38c6dc8..5d33102 100644 --- a/core/modules/system/tests/mail.test +++ b/core/modules/system/tests/mail.test @@ -6,12 +6,11 @@ */ use Drupal\Core\Mail\MailInterface; -use Drupal\simpletest\WebTestBase; /** * Defines a mail class used for testing. */ -class MailTestCase extends WebTestBase implements MailInterface { +class MailTestCase extends DrupalWebTestCase implements MailInterface { /** * The most recent message that was sent through the test case. * @@ -92,7 +91,7 @@ class MailTestCase extends WebTestBase implements MailInterface { /** * Unit tests for drupal_html_to_text(). */ -class DrupalHtmlToTextTestCase extends WebTestBase { +class DrupalHtmlToTextTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'HTML to text conversion', diff --git a/core/modules/system/tests/menu.test b/core/modules/system/tests/menu.test index dbd94a1..791cd5c 100644 --- a/core/modules/system/tests/menu.test +++ b/core/modules/system/tests/menu.test @@ -5,10 +5,7 @@ * Provides SimpleTests for menu.inc. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - -class MenuWebTestCase extends WebTestBase { +class MenuWebTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); if (isset($modules[0]) && is_array($modules[0])) { @@ -21,14 +18,13 @@ class MenuWebTestCase extends WebTestBase { * Assert that a given path shows certain breadcrumb links. * * @param string $goto - * (optional) A system path to pass to - * Drupal\simpletest\WebTestBase::drupalGet(). + * (optional) A system path to pass to DrupalWebTestCase::drupalGet(). * @param array $trail * An associative array whose keys are expected breadcrumb link paths and * whose values are expected breadcrumb link texts (not sanitized). * @param string $page_title * (optional) A page title to additionally assert via - * Drupal\simpletest\WebTestBase::assertTitle(). Without site name suffix. + * DrupalWebTestCase::assertTitle(). Without site name suffix. * @param array $tree * (optional) An associative array whose keys are link paths and whose * values are link titles (not sanitized) of an expected active trail in a @@ -125,7 +121,7 @@ class MenuWebTestCase extends WebTestBase { } } -class MenuRouterTestCase extends WebTestBase { +class MenuRouterTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Menu router', @@ -667,7 +663,7 @@ class MenuRouterTestCase extends WebTestBase { /** * Tests for menu links. */ -class MenuLinksUnitTestCase extends WebTestBase { +class MenuLinksUnitTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Menu links', @@ -883,7 +879,7 @@ class MenuLinksUnitTestCase extends WebTestBase { /** * Tests rebuilding the menu by setting 'menu_rebuild_needed.' */ -class MenuRebuildTestCase extends WebTestBase { +class MenuRebuildTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Menu rebuild test', @@ -921,7 +917,7 @@ class MenuRebuildTestCase extends WebTestBase { /** * Menu tree data related tests. */ -class MenuTreeDataTestCase extends UnitTestBase { +class MenuTreeDataTestCase extends DrupalUnitTestCase { /** * Dummy link structure acceptable for menu_tree_data(). */ @@ -976,7 +972,7 @@ class MenuTreeDataTestCase extends UnitTestBase { /** * Menu tree output related tests. */ -class MenuTreeOutputTestCase extends WebTestBase { +class MenuTreeOutputTestCase extends DrupalWebTestCase { /** * Dummy link structure acceptable for menu_tree_output(). */ diff --git a/core/modules/system/tests/module.test b/core/modules/system/tests/module.test index 761992d..564cc41 100644 --- a/core/modules/system/tests/module.test +++ b/core/modules/system/tests/module.test @@ -5,12 +5,10 @@ * Tests for the module API. */ -use Drupal\simpletest\WebTestBase; - /** * Unit tests for the module API. */ -class ModuleUnitTest extends WebTestBase { +class ModuleUnitTest extends DrupalWebTestCase { // Requires Standard profile modules/dependencies. protected $profile = 'standard'; @@ -271,7 +269,7 @@ class ModuleUnitTest extends WebTestBase { /** * Tests class loading. */ -class ModuleClassLoaderTestCase extends WebTestBase { +class ModuleClassLoaderTestCase extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { @@ -309,7 +307,7 @@ class ModuleClassLoaderTestCase extends WebTestBase { /** * Unit tests for module installation. */ -class ModuleInstallTestCase extends WebTestBase { +class ModuleInstallTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Module installation', @@ -346,7 +344,7 @@ class ModuleInstallTestCase extends WebTestBase { /** * Unit tests for module uninstallation and related hooks. */ -class ModuleUninstallTestCase extends WebTestBase { +class ModuleUninstallTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Module uninstallation', diff --git a/core/modules/system/tests/modules/error_test/error_test.info b/core/modules/system/tests/modules/error_test/error_test.info index d5db3ee..d00075d 100644 --- a/core/modules/system/tests/modules/error_test/error_test.info +++ b/core/modules/system/tests/modules/error_test/error_test.info @@ -3,4 +3,4 @@ description = "Support module for error and exception testing." package = Testing version = VERSION core = 8.x -hidden = TRUE +hidden = FALSE diff --git a/core/modules/system/tests/pager.test b/core/modules/system/tests/pager.test index 7d091f8..6fdeec5 100644 --- a/core/modules/system/tests/pager.test +++ b/core/modules/system/tests/pager.test @@ -5,12 +5,10 @@ * Tests for pager functionality. */ -use Drupal\simpletest\WebTestBase; - /** * Tests pager functionality. */ -class PagerFunctionalWebTestCase extends WebTestBase { +class PagerFunctionalWebTestCase extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { diff --git a/core/modules/system/tests/password.test b/core/modules/system/tests/password.test index 2587822..2797786 100644 --- a/core/modules/system/tests/password.test +++ b/core/modules/system/tests/password.test @@ -5,12 +5,10 @@ * Provides unit tests for password.inc. */ -use Drupal\simpletest\WebTestBase; - /** * Unit tests for password hashing API. */ -class PasswordHashingTest extends WebTestBase { +class PasswordHashingTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Password hashing', diff --git a/core/modules/system/tests/path.test b/core/modules/system/tests/path.test index 271cd91..f02a9b4 100644 --- a/core/modules/system/tests/path.test +++ b/core/modules/system/tests/path.test @@ -5,14 +5,12 @@ * Tests for path.inc. */ -use Drupal\simpletest\WebTestBase; - /** * Unit tests for the drupal_match_path() function in path.inc. * * @see drupal_match_path(). */ -class DrupalMatchPathTestCase extends WebTestBase { +class DrupalMatchPathTestCase extends DrupalWebTestCase { protected $front; public static function getInfo() { @@ -131,7 +129,7 @@ class DrupalMatchPathTestCase extends WebTestBase { /** * Tests hook_url_alter functions. */ -class UrlAlterFunctionalTest extends WebTestBase { +class UrlAlterFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('URL altering'), @@ -249,7 +247,7 @@ class UrlAlterFunctionalTest extends WebTestBase { /** * Unit test for drupal_lookup_path(). */ -class PathLookupTest extends WebTestBase { +class PathLookupTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('Path lookup'), @@ -339,7 +337,7 @@ class PathLookupTest extends WebTestBase { /** * Tests the path_save() function. */ -class PathSaveTest extends WebTestBase { +class PathSaveTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('Path save'), diff --git a/core/modules/system/tests/queue.test b/core/modules/system/tests/queue.test index 1c04677..e8f4c2c 100644 --- a/core/modules/system/tests/queue.test +++ b/core/modules/system/tests/queue.test @@ -2,12 +2,11 @@ use Drupal\Core\Queue\Memory; use Drupal\Core\Queue\System; -use Drupal\simpletest\WebTestBase; /** * Tests the basic queue functionality. */ -class QueueTestCase extends WebTestBase { +class QueueTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Queue functionality', diff --git a/core/modules/system/tests/registry.test b/core/modules/system/tests/registry.test index 7ad8326..bcd8d4e 100644 --- a/core/modules/system/tests/registry.test +++ b/core/modules/system/tests/registry.test @@ -1,8 +1,6 @@ 'Registry parse file test', @@ -47,7 +45,7 @@ CONTENTS; } -class RegistryParseFilesTestCase extends WebTestBase { +class RegistryParseFilesTestCase extends DrupalWebTestCase { protected $fileTypes = array('new', 'existing_changed'); public static function getInfo() { diff --git a/core/modules/system/tests/schema.test b/core/modules/system/tests/schema.test index f2e94ac..5a10567 100644 --- a/core/modules/system/tests/schema.test +++ b/core/modules/system/tests/schema.test @@ -1,7 +1,6 @@ 'Session tests', @@ -295,7 +293,7 @@ class SessionTestCase extends WebTestBase { /** * Ensure that when running under https two session cookies are generated. */ -class SessionHttpsTestCase extends WebTestBase { +class SessionHttpsTestCase extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/modules/system/tests/symfony.test b/core/modules/system/tests/symfony.test index 0719c7c..8a7ecb9 100644 --- a/core/modules/system/tests/symfony.test +++ b/core/modules/system/tests/symfony.test @@ -5,12 +5,10 @@ * Tests for Symfony2-related functionality. */ -use Drupal\simpletest\UnitTestBase; - /** * Tests related to Symfony class loading. */ -class SymfonyClassLoaderTestCase extends UnitTestBase { +class SymfonyClassLoaderTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Class loader', diff --git a/core/modules/system/tests/tablesort.test b/core/modules/system/tests/tablesort.test index 1dc35fe..aaea505 100644 --- a/core/modules/system/tests/tablesort.test +++ b/core/modules/system/tests/tablesort.test @@ -5,12 +5,10 @@ * Various tablesort tests. */ -use Drupal\simpletest\UnitTestBase; - /** * Test unicode handling features implemented in unicode.inc. */ -class TableSortTest extends UnitTestBase { +class TableSortTest extends DrupalUnitTestCase { /** * Storage for initial value of $_GET. diff --git a/core/modules/system/tests/theme.test b/core/modules/system/tests/theme.test index d7c6fb2..025ae8d 100644 --- a/core/modules/system/tests/theme.test +++ b/core/modules/system/tests/theme.test @@ -5,13 +5,10 @@ * Tests for the theme API. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - /** * Unit tests for the Theme API. */ -class ThemeUnitTest extends WebTestBase { +class ThemeUnitTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Theme API', @@ -175,7 +172,7 @@ class ThemeUnitTest extends WebTestBase { /** * Unit tests for theme_table(). */ -class ThemeTableUnitTest extends WebTestBase { +class ThemeTableUnitTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Theme Table', @@ -235,7 +232,7 @@ class ThemeTableUnitTest extends WebTestBase { /** * Tests for common theme functions. */ -class ThemeFunctionsTestCase extends WebTestBase { +class ThemeFunctionsTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Theme functions', @@ -493,7 +490,7 @@ class ThemeFunctionsTestCase extends WebTestBase { /** * Functional test for initialization of the theme system in hook_init(). */ -class ThemeHookInitUnitTest extends WebTestBase { +class ThemeHookInitUnitTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Theme initialization in hook_init()', @@ -522,7 +519,7 @@ class ThemeHookInitUnitTest extends WebTestBase { /** * Tests autocompletion not loading registry. */ -class ThemeFastTestCase extends WebTestBase { +class ThemeFastTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Theme fast initialization', @@ -549,7 +546,7 @@ class ThemeFastTestCase extends WebTestBase { /** * Unit tests for theme_html_tag(). */ -class ThemeHtmlTag extends UnitTestBase { +class ThemeHtmlTag extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Theme HTML Tag', @@ -575,7 +572,7 @@ class ThemeHtmlTag extends UnitTestBase { /** * Functional test for attributes of html.tpl.php. */ -class ThemeHtmlTplPhpAttributesTestCase extends WebTestBase { +class ThemeHtmlTplPhpAttributesTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'html.tpl.php html and body attributes', @@ -603,7 +600,7 @@ class ThemeHtmlTplPhpAttributesTestCase extends WebTestBase { /** * Tests for the ThemeRegistry class. */ -class ThemeRegistryTestCase extends WebTestBase { +class ThemeRegistryTestCase extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { return array( @@ -654,7 +651,7 @@ class ThemeRegistryTestCase extends WebTestBase { /** * Tests for theme_datetime(). */ -class ThemeDatetime extends WebTestBase { +class ThemeDatetime extends DrupalWebTestCase { protected $profile = 'testing'; public static function getInfo() { diff --git a/core/modules/system/tests/unicode.test b/core/modules/system/tests/unicode.test index e87ea54..c50a437 100644 --- a/core/modules/system/tests/unicode.test +++ b/core/modules/system/tests/unicode.test @@ -5,12 +5,10 @@ * Various unicode handling tests. */ -use Drupal\simpletest\UnitTestBase; - /** * Test unicode handling features implemented in unicode.inc. */ -class UnicodeUnitTest extends UnitTestBase { +class UnicodeUnitTest extends DrupalUnitTestCase { /** * Whether to run the extended version of the tests (including non latin1 characters). diff --git a/core/modules/system/tests/update.test b/core/modules/system/tests/update.test index 72bc61a..abbab47 100644 --- a/core/modules/system/tests/update.test +++ b/core/modules/system/tests/update.test @@ -5,12 +5,10 @@ * Tests for the update system. */ -use Drupal\simpletest\WebTestBase; - /** * Tests for the update dependency ordering system. */ -class UpdateDependencyOrderingTestCase extends WebTestBase { +class UpdateDependencyOrderingTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Update dependency ordering', @@ -60,7 +58,7 @@ class UpdateDependencyOrderingTestCase extends WebTestBase { /** * Tests for missing update dependencies. */ -class UpdateDependencyMissingTestCase extends WebTestBase { +class UpdateDependencyMissingTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Missing update dependencies', @@ -90,7 +88,7 @@ class UpdateDependencyMissingTestCase extends WebTestBase { /** * Tests for the invocation of hook_update_dependencies(). */ -class UpdateDependencyHookInvocationTestCase extends WebTestBase { +class UpdateDependencyHookInvocationTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Update dependency hook invocation', diff --git a/core/modules/system/tests/upgrade/upgrade.test b/core/modules/system/tests/upgrade/upgrade.test index 2f942fa..aa1ad6f 100644 --- a/core/modules/system/tests/upgrade/upgrade.test +++ b/core/modules/system/tests/upgrade/upgrade.test @@ -1,12 +1,11 @@ TRUE)) . 'core/xmlrpc.php'; + $url = $base_url . '/core/xmlrpc.php'; $methods = xmlrpc($url, array('system.listMethods' => array())); // Ensure that the minimum methods were found. @@ -47,7 +47,9 @@ class XMLRPCBasicTestCase extends WebTestBase { * Ensure that system.methodSignature returns an array of signatures. */ protected function testMethodSignature() { - $url = url(NULL, array('absolute' => TRUE)) . 'core/xmlrpc.php'; + global $base_url; + + $url = $base_url . '/core/xmlrpc.php'; $signature = xmlrpc($url, array('system.methodSignature' => array('system.listMethods'))); $this->assert(is_array($signature) && !empty($signature) && is_array($signature[0]), t('system.methodSignature returns an array of signature arrays.')); @@ -82,7 +84,7 @@ class XMLRPCBasicTestCase extends WebTestBase { } } -class XMLRPCValidator1IncTestCase extends WebTestBase { +class XMLRPCValidator1IncTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'XML-RPC validator', @@ -99,7 +101,8 @@ class XMLRPCValidator1IncTestCase extends WebTestBase { * Run validator1 tests. */ function testValidator1() { - $xml_url = url(NULL, array('absolute' => TRUE)) . 'core/xmlrpc.php'; + global $base_url; + $xml_url = $base_url . '/core/xmlrpc.php'; srand(); mt_srand(); @@ -196,7 +199,7 @@ class XMLRPCValidator1IncTestCase extends WebTestBase { } } -class XMLRPCMessagesTestCase extends WebTestBase { +class XMLRPCMessagesTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'XML-RPC message and alteration', @@ -213,7 +216,9 @@ class XMLRPCMessagesTestCase extends WebTestBase { * Make sure that XML-RPC can transfer large messages. */ function testSizedMessages() { - $xml_url = url(NULL, array('absolute' => TRUE)) . 'core/xmlrpc.php'; + global $base_url; + + $xml_url = $base_url . '/core/xmlrpc.php'; $sizes = array(8, 80, 160); foreach ($sizes as $size) { $xml_message_l = xmlrpc_test_message_sized_in_kb($size); @@ -227,10 +232,11 @@ class XMLRPCMessagesTestCase extends WebTestBase { * Ensure that hook_xmlrpc_alter() can hide even builtin methods. */ protected function testAlterListMethods() { + global $base_url; // Ensure xmlrpc_test_xmlrpc_alter() is disabled and retrieve regular list of methods. variable_set('xmlrpc_test_xmlrpc_alter', FALSE); - $url = url(NULL, array('absolute' => TRUE)) . 'core/xmlrpc.php'; + $url = $base_url . '/core/xmlrpc.php'; $methods1 = xmlrpc($url, array('system.listMethods' => array())); // Enable the alter hook and retrieve the list of methods again. diff --git a/core/modules/taxonomy/taxonomy.test b/core/modules/taxonomy/taxonomy.test index d59094c..428c8ab 100644 --- a/core/modules/taxonomy/taxonomy.test +++ b/core/modules/taxonomy/taxonomy.test @@ -6,12 +6,11 @@ */ use Drupal\field\FieldValidationException; -use Drupal\simpletest\WebTestBase; /** * Provides common helper methods for Taxonomy module tests. */ -class TaxonomyWebTestCase extends WebTestBase { +class TaxonomyWebTestCase extends DrupalWebTestCase { function setUp() { $modules = func_get_args(); @@ -768,9 +767,8 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase { $path = 'taxonomy/autocomplete/taxonomy_'; $path .= $this->vocabulary->machine_name . '/' . $input; // The result order is not guaranteed, so check each term separately. - $url = url($path, array('absolute' => TRUE)); - $result = drupal_http_request($url); - $data = drupal_json_decode($result->data); + $result = $this->drupalGet($path); + $data = drupal_json_decode($result); $this->assertEqual($data[$first_term->name], check_plain($first_term->name), 'Autocomplete returned the first matching term'); $this->assertEqual($data[$second_term->name], check_plain($second_term->name), 'Autocomplete returned the second matching term'); diff --git a/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php b/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php index 2706d3b..5e689ff 100644 --- a/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php +++ b/core/modules/tracker/lib/Drupal/tracker/Tests/TrackerTest.php @@ -7,12 +7,12 @@ namespace Drupal\tracker\Tests; -use Drupal\simpletest\WebTestBase; +use DrupalWebTestCase; /** * Defines a base class for testing tracker.module. */ -class TrackerTest extends WebTestBase { +class TrackerTest extends DrupalWebTestCase { /** * The main user for testing. diff --git a/core/modules/translation/translation.test b/core/modules/translation/translation.test index 1a0f0a0..c9b3dcb 100644 --- a/core/modules/translation/translation.test +++ b/core/modules/translation/translation.test @@ -6,12 +6,11 @@ */ use Drupal\node\Node; -use Drupal\simpletest\WebTestBase; /** * Functional tests for the Translation module. */ -class TranslationTestCase extends WebTestBase { +class TranslationTestCase extends DrupalWebTestCase { protected $profile = 'standard'; protected $book; diff --git a/core/modules/update/tests/modules/update_test/update_test.module b/core/modules/update/tests/modules/update_test/update_test.module index ff5aad5..b40f274 100644 --- a/core/modules/update/tests/modules/update_test/update_test.module +++ b/core/modules/update/tests/modules/update_test/update_test.module @@ -1,5 +1,8 @@ 'text/xml; charset=utf-8')); + } + return new StreamedResponse(function() use ($file) { + // Transfer file in 1024 byte chunks to save memory usage. + if ($fd = fopen($file, 'rb')) { + while (!feof($fd)) { + print fread($fd, 1024); + } + fclose($fd); + } + }, 200, array('Content-Type' => 'text/xml; charset=utf-8')); } /** diff --git a/core/modules/update/update.fetch.inc b/core/modules/update/update.fetch.inc index 6de781d..06fe7f7 100644 --- a/core/modules/update/update.fetch.inc +++ b/core/modules/update/update.fetch.inc @@ -142,7 +142,7 @@ function _update_process_fetch_task($project) { $project_name = $project['name']; if (empty($fail[$fetch_url_base]) || $fail[$fetch_url_base] < $max_fetch_attempts) { - $xml = drupal_http_request($url); + $xml = drupal_http_request($url, array('headers' => array('accept' => 'text/xml'))); if (!isset($xml->error) && isset($xml->data)) { $data = $xml->data; } diff --git a/core/modules/update/update.test b/core/modules/update/update.test index 0e10057..e36fa24 100644 --- a/core/modules/update/update.test +++ b/core/modules/update/update.test @@ -19,13 +19,10 @@ * initial state and availability scenario. */ -use Drupal\simpletest\WebTestBase; -use Drupal\simpletest\UnitTestBase; - /** * Base class to define some shared functions used by all update tests. */ -class UpdateTestHelper extends WebTestBase { +class UpdateTestHelper extends DrupalWebTestCase { /** * Refresh the update status based on the desired available update scenario. * @@ -728,7 +725,7 @@ class UpdateTestUploadCase extends UpdateTestHelper { } -class UpdateCoreUnitTestCase extends UnitTestBase { +class UpdateCoreUnitTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 836f101..ee2a711 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -2325,9 +2325,12 @@ function user_delete_multiple(array $uids) { * Page callback wrapper for user_view(). */ function user_view_page($account) { + if (is_object($account)) { + return user_view($account); + } // An administrator may try to view a non-existent account, // so we give them a 404 (versus a 403 for non-admins). - return is_object($account) ? user_view($account) : MENU_NOT_FOUND; + drupal_not_found(); } /** diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc index becb763..438fedb 100644 --- a/core/modules/user/user.pages.inc +++ b/core/modules/user/user.pages.inc @@ -67,7 +67,7 @@ function user_pass_validate($form, &$form_state) { form_set_value(array('#parents' => array('account')), $account, $form_state); } else { - form_set_error('name', t('Sorry, %name is not recognized as a username or an e-mail address.', array('%name' => $name))); + form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name))); } } diff --git a/core/modules/user/user.test b/core/modules/user/user.test index 7671eba..0ce6870 100644 --- a/core/modules/user/user.test +++ b/core/modules/user/user.test @@ -5,9 +5,7 @@ * Tests for user.module. */ -use Drupal\simpletest\WebTestBase; - -class UserRegistrationTestCase extends WebTestBase { +class UserRegistrationTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User registration', @@ -260,7 +258,7 @@ class UserRegistrationTestCase extends WebTestBase { } } -class UserValidationTestCase extends WebTestBase { +class UserValidationTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Username/e-mail validation', @@ -300,7 +298,7 @@ class UserValidationTestCase extends WebTestBase { /** * Functional tests for user logins, including rate limiting of login attempts. */ -class UserLoginTestCase extends WebTestBase { +class UserLoginTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User login', @@ -443,7 +441,7 @@ class UserLoginTestCase extends WebTestBase { /** * Tests resetting a user password. */ -class UserPasswordResetTestCase extends WebTestBase { +class UserPasswordResetTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -495,7 +493,7 @@ class UserPasswordResetTestCase extends WebTestBase { /** * Test cancelling a user. */ -class UserCancelTestCase extends WebTestBase { +class UserCancelTestCase extends DrupalWebTestCase { protected $profile = 'standard'; public static function getInfo() { @@ -921,7 +919,7 @@ class UserCancelTestCase extends WebTestBase { } } -class UserPictureTestCase extends WebTestBase { +class UserPictureTestCase extends DrupalWebTestCase { protected $user; protected $_directory_test; @@ -1230,7 +1228,7 @@ class UserPictureTestCase extends WebTestBase { } -class UserPermissionsTestCase extends WebTestBase { +class UserPermissionsTestCase extends DrupalWebTestCase { protected $admin_user; protected $rid; @@ -1328,7 +1326,7 @@ class UserPermissionsTestCase extends WebTestBase { } } -class UserAdminTestCase extends WebTestBase { +class UserAdminTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User administration', @@ -1417,7 +1415,7 @@ class UserAdminTestCase extends WebTestBase { /** * Tests for user-configurable time zones. */ -class UserTimeZoneFunctionalTest extends WebTestBase { +class UserTimeZoneFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User time zones', @@ -1477,7 +1475,7 @@ class UserTimeZoneFunctionalTest extends WebTestBase { /** * Test user autocompletion. */ -class UserAutocompleteTestCase extends WebTestBase { +class UserAutocompleteTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User autocompletion', @@ -1518,7 +1516,7 @@ class UserAutocompleteTestCase extends WebTestBase { /** * Test user-links in secondary menu. */ -class UserAccountLinksUnitTests extends WebTestBase { +class UserAccountLinksUnitTests extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User account links', @@ -1567,7 +1565,7 @@ class UserAccountLinksUnitTests extends WebTestBase { /** * Test user blocks. */ -class UserBlocksUnitTests extends WebTestBase { +class UserBlocksUnitTests extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User blocks', @@ -1682,7 +1680,7 @@ class UserBlocksUnitTests extends WebTestBase { /** * Tests user_save() behavior. */ -class UserSaveTestCase extends WebTestBase { +class UserSaveTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1724,7 +1722,7 @@ class UserSaveTestCase extends WebTestBase { /** * Test the create user administration page. */ -class UserCreateTestCase extends WebTestBase { +class UserCreateTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1770,7 +1768,7 @@ class UserCreateTestCase extends WebTestBase { /** * Tests the user edit form. */ -class UserEditTestCase extends WebTestBase { +class UserEditTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -1862,7 +1860,7 @@ class UserEditTestCase extends WebTestBase { /** * Test case for user signatures. */ -class UserSignatureTestCase extends WebTestBase { +class UserSignatureTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User signatures', @@ -1966,7 +1964,7 @@ class UserSignatureTestCase extends WebTestBase { /* * Test that a user, having editing their own account, can still log in. */ -class UserEditedOwnAccountTestCase extends WebTestBase { +class UserEditedOwnAccountTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -2002,7 +2000,7 @@ class UserEditedOwnAccountTestCase extends WebTestBase { /** * Test case to test adding, editing and deleting roles. */ -class UserRoleAdminTestCase extends WebTestBase { +class UserRoleAdminTestCase extends DrupalWebTestCase { public static function getInfo() { return array( @@ -2087,7 +2085,7 @@ class UserRoleAdminTestCase extends WebTestBase { /** * Test user token replacement in strings. */ -class UserTokenReplaceTestCase extends WebTestBase { +class UserTokenReplaceTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User token replacement', @@ -2152,7 +2150,7 @@ class UserTokenReplaceTestCase extends WebTestBase { /** * Test user search. */ -class UserUserSearchTestCase extends WebTestBase { +class UserUserSearchTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User search', @@ -2188,7 +2186,7 @@ class UserUserSearchTestCase extends WebTestBase { /** * Test role assignment. */ -class UserRolesAssignmentTestCase extends WebTestBase { +class UserRolesAssignmentTestCase extends DrupalWebTestCase { protected $admin_user; public static function getInfo() { @@ -2278,7 +2276,7 @@ class UserRolesAssignmentTestCase extends WebTestBase { /** * Unit test for authmap assignment. */ -class UserAuthmapAssignmentTestCase extends WebTestBase { +class UserAuthmapAssignmentTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => t('Authmap assignment'), @@ -2337,7 +2335,7 @@ class UserAuthmapAssignmentTestCase extends WebTestBase { /** * Tests user_validate_current_pass on a custom form. */ -class UserValidateCurrentPassCustomForm extends WebTestBase { +class UserValidateCurrentPassCustomForm extends DrupalWebTestCase { public static function getInfo() { return array( @@ -2382,7 +2380,7 @@ class UserValidateCurrentPassCustomForm extends WebTestBase { /** * Test user entity callbacks. */ -class UserEntityCallbacksTestCase extends WebTestBase { +class UserEntityCallbacksTestCase extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User entity callback tests', @@ -2422,7 +2420,7 @@ class UserEntityCallbacksTestCase extends WebTestBase { /** * Functional tests for a user's ability to change their default language. */ -class UserLanguageFunctionalTest extends WebTestBase { +class UserLanguageFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'User language settings', @@ -2487,7 +2485,7 @@ class UserLanguageFunctionalTest extends WebTestBase { /** * Functional test for language handling during user creation. */ -class UserLanguageCreationTest extends WebTestBase { +class UserLanguageCreationTest extends DrupalWebTestCase { public static function getInfo() { return array( diff --git a/core/update.php b/core/update.php index 9797833..ab050a8 100644 --- a/core/update.php +++ b/core/update.php @@ -14,6 +14,9 @@ * back to its original state! */ +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + // Change the directory to the Drupal root. chdir('..'); @@ -391,11 +394,24 @@ $default = language_default(); drupal_container()->register(LANGUAGE_TYPE_INTERFACE, 'Drupal\\Core\\Language\\Language') ->addMethodCall('extend', array($default)); +// A request object from the HTTPFoundation to tell us about the request. +// @todo These two lines were copied from index.php which has its own todo about +// a change required here. Revisit this when that change has been made. +$request = Request::createFromGlobals(); +request($request); + +// There can be conflicting 'op' parameters because both update and batch use +// this parameter name. We need the 'op' coming from a POST request to trump +// that coming from a GET request. +$op = $request->request->get('op'); +if (is_null($op)) { + $op = $request->query->get('op'); +} + // Only allow the requirements check to proceed if the current user has access // to run updates (since it may expose sensitive information about the site's // configuration). -$op = isset($_REQUEST['op']) ? $_REQUEST['op'] : ''; -if (empty($op) && update_access_allowed()) { +if (is_null($op) && update_access_allowed()) { require_once DRUPAL_ROOT . '/core/includes/install.inc'; require_once DRUPAL_ROOT . '/core/modules/system/system.install'; @@ -423,23 +439,16 @@ if (empty($op) && update_access_allowed()) { install_goto('core/update.php?op=info'); } -// update_fix_d8_requirements() needs to run before bootstrapping beyond path. -// So bootstrap to DRUPAL_BOOTSTRAP_LANGUAGE then include unicode.inc. - -drupal_bootstrap(DRUPAL_BOOTSTRAP_LANGUAGE); -include_once DRUPAL_ROOT . '/core/includes/unicode.inc'; - -update_fix_d8_requirements(); - -// Now proceed with a full bootstrap. - +// Bootstrap, fix requirements, and set the maintenance theme. drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); +update_fix_d8_requirements(); drupal_maintenance_theme(); // Turn error reporting back on. From now on, only fatal errors (which are // not passed through the error handler) will cause a message to be printed. ini_set('display_errors', TRUE); + // Only proceed with updates if the user is allowed to run them. if (update_access_allowed()) { @@ -453,27 +462,29 @@ if (update_access_allowed()) { // no errors, skip reporting them if the user has provided a URL parameter // acknowledging the warnings and indicating a desire to continue anyway. See // drupal_requirements_url(). - $skip_warnings = !empty($_GET['continue']); + $continue = $request->query->get('continue'); + $skip_warnings = !empty($continue); update_check_requirements($skip_warnings); - $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : ''; switch ($op) { // update.php ops. case 'selection': - if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) { + $token = $request->query->get('token'); + if (isset($token) && drupal_valid_token($token, 'update')) { $output = update_selection_page(); break; } case 'Apply pending updates': - if (isset($_GET['token']) && $_GET['token'] == drupal_get_token('update')) { + $token = $request->query->get('token'); + if (isset($token) && drupal_valid_token($token, 'update')) { // Generate absolute URLs for the batch processing (using $base_root), // since the batch API will pass them to url() which does not handle // update.php correctly by default. $batch_url = $base_root . drupal_current_script_url(); $redirect_url = $base_root . drupal_current_script_url(array('op' => 'results')); - update_batch($_POST['start'], $redirect_url, $batch_url); + update_batch($request->request->get('start'), $redirect_url, $batch_url); break; } @@ -500,5 +511,11 @@ if (isset($output) && $output) { drupal_session_start(); // We defer the display of messages until all updates are done. $progress_page = ($batch = batch_get()) && isset($batch['running']); - print theme('update_page', array('content' => $output, 'show_messages' => !$progress_page)); + if ($output instanceof Response) { + $output->send(); + } + else { + print theme('update_page', array('content' => $output, 'show_messages' => !$progress_page)); + } + } diff --git a/index.php b/index.php index b91fb1e..8e2c882 100644 --- a/index.php +++ b/index.php @@ -11,11 +11,34 @@ * See COPYRIGHT.txt and LICENSE.txt files in the "core" directory. */ +use Drupal\Core\DrupalKernel; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\HttpKernel\Controller\ControllerResolver; + /** * Root directory of Drupal installation. */ define('DRUPAL_ROOT', getcwd()); - +// Bootstrap the lowest level of what we need. require_once DRUPAL_ROOT . '/core/includes/bootstrap.inc'; -drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); -menu_execute_active_handler(); +drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); + +// Create a request object from the HTTPFoundation. +$request = Request::createFromGlobals(); + +// Set the global $request object. This is a temporary measure to keep legacy +// utility functions working. It should be moved to a dependency injection +// container at some point. +request($request); + +drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); + +$dispatcher = new EventDispatcher(); +$resolver = new ControllerResolver(); + +$kernel = new DrupalKernel($dispatcher, $resolver); +$response = $kernel->handle($request); +$response->prepare($request); +$response->send(); +$kernel->terminate($request, $response); diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.test b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.test index e4c8694..198c1d8 100644 --- a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.test +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.test @@ -1,12 +1,9 @@