diff --git a/core/lib/Drupal/Core/Config/InstallStorage.php b/core/lib/Drupal/Core/Config/InstallStorage.php index 6a97b31..5d86271 100644 --- a/core/lib/Drupal/Core/Config/InstallStorage.php +++ b/core/lib/Drupal/Core/Config/InstallStorage.php @@ -197,10 +197,17 @@ public function getComponentNames(array $list) { // We don't have to use ExtensionDiscovery here because our list of // extensions was already obtained through an ExtensionDiscovery scan. $directory = $this->getComponentFolder($extension_object); - if (file_exists($directory)) { - $files = new \GlobIterator(\Drupal::root() . '/' . $directory . '/*' . $extension); + if (is_dir($directory)) { + // glob() directly calls into libc glob(), which is not aware of PHP stream + // wrappers. Same for \GlobIterator (which additionally requires an absolute + // realpath() on Windows). + // @see https://github.com/mikey179/vfsStream/issues/2 + $files = scandir($directory); + foreach ($files as $file) { - $folders[$file->getBasename($extension)] = $directory; + if ($file[0] !== '.' && fnmatch('*' . $extension, $file)) { + $folders[basename($file, $extension)] = $directory; + } } } } @@ -217,10 +224,17 @@ public function getCoreNames() { $extension = '.' . $this->getFileExtension(); $folders = array(); $directory = $this->getCoreFolder(); - if (file_exists($directory)) { - $files = new \GlobIterator(\Drupal::root() . '/' . $directory . '/*' . $extension); + if (is_dir($directory)) { + // glob() directly calls into libc glob(), which is not aware of PHP stream + // wrappers. Same for \GlobIterator (which additionally requires an absolute + // realpath() on Windows). + // @see https://github.com/mikey179/vfsStream/issues/2 + $files = scandir($directory); + foreach ($files as $file) { - $folders[$file->getBasename($extension)] = $directory; + if ($file[0] !== '.' && fnmatch('*' . $extension, $file)) { + $folders[basename($file, $extension)] = $directory; + } } } return $folders; diff --git a/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php b/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php index 9de7e71..cb6a27d 100644 --- a/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php +++ b/core/lib/Drupal/Core/DependencyInjection/DependencySerializationTrait.php @@ -49,10 +49,9 @@ public function __sleep() { * {@inheritdoc} */ public function __wakeup() { - if ($container = \Drupal::getContainer()) { - foreach ($this->_serviceIds as $key => $service_id) { - $this->$key = $container->get($service_id); - } + $container = \Drupal::getContainer(); + foreach ($this->_serviceIds as $key => $service_id) { + $this->$key = $container->get($service_id); } $this->_serviceIds = array(); } diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php index d18de88..5dbc3fd 100644 --- a/core/lib/Drupal/Core/DrupalKernel.php +++ b/core/lib/Drupal/Core/DrupalKernel.php @@ -472,6 +472,13 @@ public function getContainer() { * {@inheritdoc} */ public function setContainer(ContainerInterface $container = NULL) { + if (isset($this->container)) { + throw new \Exception('The container should not override an existing container.'); + } + if ($this->booted) { + throw new \Exception('The container cannot be set after a booted kernel.'); + } + $this->container = $container; return $this; } @@ -571,7 +578,7 @@ public function discoverServiceProviders() { // Add site-specific service providers. if (!empty($GLOBALS['conf']['container_service_providers'])) { foreach ($GLOBALS['conf']['container_service_providers'] as $class) { - if ((is_object($class) && ($class instanceof ServiceProviderInterface || $class instanceof ServiceModifierInterface)) || class_exists($class)) { + if ((is_string($class) && class_exists($class)) || (is_object($class) && ($class instanceof ServiceProviderInterface || $class instanceof ServiceModifierInterface))) { $this->serviceProviderClasses['site'][] = $class; } } diff --git a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php index 3f1a8fc..fb8e715 100644 --- a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php +++ b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php @@ -130,7 +130,8 @@ protected function getLocalPath($uri = NULL) { // In PHPUnit tests, the base path for local streams may be a virtual // filesystem stream wrapper URI, in which case this local stream acts like - // a proxy. realpath() is (obviously) not supported by vfsStream. + // a proxy. realpath() is not supported by vfsStream, because a virtual + // file system does not have a real filepath. if (strpos($path, 'vfs://') === 0) { return $path; } diff --git a/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php b/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php index 949c8e5..b13dec6 100644 --- a/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php +++ b/core/modules/ckeditor/src/Plugin/Editor/CKEditor.php @@ -319,10 +319,12 @@ public function getLangcodes() { if (empty($langcodes)) { $langcodes = array(); // Collect languages included with CKEditor based on file listing. - $ckeditor_languages = new \GlobIterator(\Drupal::root() . '/core/assets/vendor/ckeditor/lang/*.js'); - foreach ($ckeditor_languages as $language_file) { - $langcode = $language_file->getBasename('.js'); - $langcodes[$langcode] = $langcode; + $files = scandir('core/assets/vendor/ckeditor/lang'); + foreach ($files as $file) { + if ($file[0] !== '.' && fnmatch('*.js', $file)) { + $langcode = basename($file, 'js'); + $langcodes[$langcode] = $langcode; + } } \Drupal::cache()->set('ckeditor.langcodes', $langcodes); } diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php index aaa2942..a64b5d8 100644 --- a/core/modules/simpletest/src/TestBase.php +++ b/core/modules/simpletest/src/TestBase.php @@ -28,8 +28,6 @@ abstract class TestBase { use SessionTestTrait; - - use RandomGeneratorTrait; /** @@ -1415,118 +1413,6 @@ protected function settingsSet($name, $value) { } /** - * Generates a pseudo-random string of ASCII characters of codes 32 to 126. - * - * Do not use this method when special characters are not possible (e.g., in - * machine or file names that have already been validated); instead, use - * \Drupal\simpletest\TestBase::randomMachineName(). If $length is greater - * than 2 the random string will include at least one ampersand ('&') - * character to ensure coverage for special characters and avoid the - * introduction of random test failures. - * - * @param int $length - * Length of random string to generate. - * - * @return string - * Pseudo-randomly generated unique string including special characters. - * - * @see \Drupal\Component\Utility\Random::string() - */ - public function randomString($length = 8) { - if ($length < 3) { - return $this->getRandomGenerator()->string($length, TRUE, array($this, 'randomStringValidate')); - } - - // To prevent the introduction of random test failures, ensure that the - // returned string contains a character that needs to be escaped in HTML by - // injecting an ampersand into it. - $replacement_pos = floor($length / 2); - // Remove 1 from the length to account for the ampersand character. - $string = $this->getRandomGenerator()->string($length - 1, TRUE, array($this, 'randomStringValidate')); - return substr_replace($string, '&', $replacement_pos, 0); - } - - /** - * Callback for random string validation. - * - * @see \Drupal\Component\Utility\Random::string() - * - * @param string $string - * The random string to validate. - * - * @return bool - * TRUE if the random string is valid, FALSE if not. - */ - public function randomStringValidate($string) { - // Consecutive spaces causes issues for - // Drupal\simpletest\WebTestBase::assertLink(). - if (preg_match('/\s{2,}/', $string)) { - return FALSE; - } - - // Starting with a space means that length might not be what is expected. - // Starting with an @ sign causes CURL to fail if used in conjunction with a - // file upload. See https://www.drupal.org/node/2174997. - if (preg_match('/^(\s|@)/', $string)) { - return FALSE; - } - - // Ending with a space means that length might not be what is expected. - if (preg_match('/\s$/', $string)) { - return FALSE; - } - - return TRUE; - } - - /** - * Generates a unique random string containing letters and numbers. - * - * Do not use this method when testing unvalidated user input. Instead, use - * \Drupal\simpletest\TestBase::randomString(). - * - * @param int $length - * Length of random string to generate. - * - * @return string - * Randomly generated unique string. - * - * @see \Drupal\Component\Utility\Random::name() - */ - public function randomMachineName($length = 8) { - return $this->getRandomGenerator()->name($length, TRUE); - } - - /** - * Generates a random PHP object. - * - * @param int $size - * The number of random keys to add to the object. - * - * @return \stdClass - * The generated object, with the specified number of random keys. Each key - * has a random string value. - * - * @see \Drupal\Component\Utility\Random::object() - */ - public function randomObject($size = 4) { - return $this->getRandomGenerator()->object($size); - } - - /** - * Gets the random generator for the utility methods. - * - * @return \Drupal\Component\Utility\Random - * The random generator - */ - protected function getRandomGenerator() { - if (!is_object($this->randomGenerator)) { - $this->randomGenerator = new Random(); - } - return $this->randomGenerator; - } - - /** * Converts a list of possible parameters into a stack of permutations. * * Takes a list of parameters containing possible values, and converts all of diff --git a/core/tests/Drupal/Tests/KernelTestBase.php b/core/tests/Drupal/Tests/KernelTestBase.php index 81bb858..4408485 100644 --- a/core/tests/Drupal/Tests/KernelTestBase.php +++ b/core/tests/Drupal/Tests/KernelTestBase.php @@ -192,7 +192,16 @@ public static function setUpBeforeClass() { parent::setUpBeforeClass(); // Change the current dir to DRUPAL_ROOT. - chdir(__DIR__ . '/../../../../'); + chdir(static::getDrupalRoot()); + } + + /** + * Returns the drupal root directory. + * + * @return string + */ + protected static function getDrupalRoot() { + return dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)))); } /** @@ -201,7 +210,7 @@ public static function setUpBeforeClass() { protected function setUp() { parent::setUp(); - $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)))); + $this->root = static::getDrupalRoot(); $this->bootEnvironment(); $this->bootKernel(); } @@ -225,10 +234,15 @@ protected function bootEnvironment() { require_once $this->root . '/core/includes/bootstrap.inc'; // Set up virtual filesystem. - // Uses a random ID, since created test files may be processed by file - // discovery/parser services that are using a static cache to avoid parsing - // the identical files multiple times. - $suffix = mt_rand(100000, 999999); + // Ensure that the generated test site directory does not exist already, + // which may happen with a large amount of concurrent threads and + // long-running tests. + do { + $suffix = mt_rand(100000, 999999); + $this->siteDirectory = 'sites/simpletest/' . $suffix; + $this->databasePrefix = 'simpletest' . $suffix; + } while (is_dir($this->root . '/' . $this->siteDirectory)); + $this->vfsRoot = vfsStream::setup('root', NULL, array( 'sites' => array( 'simpletest' => array( @@ -269,47 +283,6 @@ protected function bootEnvironment() { } /** - * Parses a database URL into a connection info array. - * - * @param string $db_url - * The database URL. - * - * @return array - * The database connection info. - */ - protected function parseDbUrl($db_url) { - $info = parse_url($db_url); - if (!isset($info['scheme'], $info['host'], $info['path'])) { - throw new \InvalidArgumentException('Invalid dburl, . Minimum requirement: driver://host/database'); - } - $info += [ - 'user' => '', - 'pass' => '', - 'fragment' => '', - ]; - if ($info['path'][0] === '/') { - $info['path'] = substr($info['path'], 1); - } - if ($info['scheme'] === 'sqlite' && $info['path'][0] !== '/') { - $info['path'] = $this->root . '/' . $info['path']; - } - $db_info = [ - 'driver' => $info['scheme'], - 'username' => $info['user'], - 'password' => $info['pass'], - 'host' => $info['host'], - 'database' => $info['path'], - 'prefix' => [ - 'default' => $info['fragment'], - ], - ]; - if (isset($info['port'])) { - $db_info['port'] = $info['port']; - } - return $db_info; - } - - /** * Bootstraps a kernel for a test. */ private function bootKernel() { @@ -597,6 +570,7 @@ public function register(ContainerBuilder $container) { * @see \Drupal\Tests\KernelTestBase::register() */ public function containerBuild(ContainerBuilder $container) { + trigger_error('Use ::register() instead', E_USER_DEPRECATED); } /** @@ -1057,7 +1031,7 @@ public function __get($name) { 'translation_files_directory', ))) { // @comment it in again. - // $this->triggerDeprecated(sprintf("KernelTestBase::\$%s no longer exists. Use the regular API method to retrieve it instead (e.g., Settings).", $name)); + trigger_error(sprintf("KernelTestBase::\$%s no longer exists. Use the regular API method to retrieve it instead (e.g., Settings).", $name), E_USER_DEPRECATED); switch ($name) { case 'public_files_directory': return Settings::get('file_public_path', conf_path() . '/files'); @@ -1105,20 +1079,4 @@ public function __get($name) { } } - /** - * BC: Trigger warnings/exceptions for former KernelTestBase class properties. - * - * This is just an extra safety net. Legacy tests are only reading the former - * KernelTestBase properties. Drupal core is not aware of any tests that are - * trying to set or change them. - * - * Test authors should follow the provided instructions and adjust their tests - * accordingly. - * - * @deprecated in Drupal 8.0.x, will be removed before Drupal 8.0.0. - */ - public function __set($name, $value) { - $this->__get($name); - } - }