Issue #3391776 by alexpott, smustgrave, catch: InfoParser returns an empty array if passed a non-existing file
parent
184f22eef0
commit
5ef2211afc
|
@ -37,68 +37,68 @@ class InfoParserDynamic implements InfoParserInterface {
|
|||
*/
|
||||
public function parse($filename) {
|
||||
if (!file_exists($filename)) {
|
||||
$parsed_info = [];
|
||||
throw new InfoParserException("Unable to parse $filename as it does not exist");
|
||||
}
|
||||
else {
|
||||
try {
|
||||
$parsed_info = Yaml::decode(file_get_contents($filename));
|
||||
}
|
||||
catch (InvalidDataTypeException $e) {
|
||||
throw new InfoParserException("Unable to parse $filename " . $e->getMessage());
|
||||
}
|
||||
$missing_keys = array_diff($this->getRequiredKeys(), array_keys($parsed_info));
|
||||
if (!empty($missing_keys)) {
|
||||
throw new InfoParserException('Missing required keys (' . implode(', ', $missing_keys) . ') in ' . $filename);
|
||||
}
|
||||
if (!isset($parsed_info['core_version_requirement'])) {
|
||||
if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . '/core/')) {
|
||||
// Core extensions do not need to specify core compatibility: they are
|
||||
// by definition compatible so a sensible default is used. Core
|
||||
// modules are allowed to provide these for testing purposes.
|
||||
$parsed_info['core_version_requirement'] = \Drupal::VERSION;
|
||||
}
|
||||
elseif (isset($parsed_info['package']) && $parsed_info['package'] === 'Testing') {
|
||||
// Modules in the testing package are exempt as well. This makes it
|
||||
// easier for contrib to use test modules.
|
||||
$parsed_info['core_version_requirement'] = \Drupal::VERSION;
|
||||
}
|
||||
else {
|
||||
// Non-core extensions must specify core compatibility.
|
||||
throw new InfoParserException("The 'core_version_requirement' key must be present in " . $filename);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if the extension is compatible with the current version of
|
||||
// Drupal core.
|
||||
try {
|
||||
$parsed_info['core_incompatible'] = !Semver::satisfies(\Drupal::VERSION, $parsed_info['core_version_requirement']);
|
||||
try {
|
||||
$parsed_info = Yaml::decode(file_get_contents($filename));
|
||||
}
|
||||
catch (InvalidDataTypeException $e) {
|
||||
throw new InfoParserException("Unable to parse $filename " . $e->getMessage());
|
||||
}
|
||||
$missing_keys = array_diff($this->getRequiredKeys(), array_keys($parsed_info));
|
||||
if (!empty($missing_keys)) {
|
||||
throw new InfoParserException('Missing required keys (' . implode(', ', $missing_keys) . ') in ' . $filename);
|
||||
}
|
||||
if (!isset($parsed_info['core_version_requirement'])) {
|
||||
if (str_starts_with($filename, 'core/') || str_starts_with($filename, $this->root . '/core/')) {
|
||||
// Core extensions do not need to specify core compatibility: they are
|
||||
// by definition compatible so a sensible default is used. Core
|
||||
// modules are allowed to provide these for testing purposes.
|
||||
$parsed_info['core_version_requirement'] = \Drupal::VERSION;
|
||||
}
|
||||
catch (\UnexpectedValueException $exception) {
|
||||
throw new InfoParserException("The 'core_version_requirement' constraint ({$parsed_info['core_version_requirement']}) is not a valid value in $filename");
|
||||
elseif (isset($parsed_info['package']) && $parsed_info['package'] === 'Testing') {
|
||||
// Modules in the testing package are exempt as well. This makes it
|
||||
// easier for contrib to use test modules.
|
||||
$parsed_info['core_version_requirement'] = \Drupal::VERSION;
|
||||
}
|
||||
if (isset($parsed_info['version']) && $parsed_info['version'] === 'VERSION') {
|
||||
$parsed_info['version'] = \Drupal::VERSION;
|
||||
}
|
||||
$parsed_info += [ExtensionLifecycle::LIFECYCLE_IDENTIFIER => ExtensionLifecycle::STABLE];
|
||||
$lifecycle = $parsed_info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER];
|
||||
if (!ExtensionLifecycle::isValid($lifecycle)) {
|
||||
$valid_values = [
|
||||
ExtensionLifecycle::EXPERIMENTAL,
|
||||
ExtensionLifecycle::STABLE,
|
||||
ExtensionLifecycle::DEPRECATED,
|
||||
ExtensionLifecycle::OBSOLETE,
|
||||
];
|
||||
throw new InfoParserException("'lifecycle: {$lifecycle}' is not valid in $filename. Valid values are: '" . implode("', '", $valid_values) . "'.");
|
||||
}
|
||||
if (in_array($lifecycle, [ExtensionLifecycle::DEPRECATED, ExtensionLifecycle::OBSOLETE], TRUE)) {
|
||||
if (empty($parsed_info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER])) {
|
||||
throw new InfoParserException(sprintf("Extension %s (%s) has 'lifecycle: %s' but is missing a '%s' entry.", $parsed_info['name'], $filename, $lifecycle, ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER));
|
||||
}
|
||||
if (!filter_var($parsed_info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER], FILTER_VALIDATE_URL)) {
|
||||
throw new InfoParserException(sprintf("Extension %s (%s) has a '%s' entry that is not a valid URL.", $parsed_info['name'], $filename, ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER));
|
||||
}
|
||||
else {
|
||||
// Non-core extensions must specify core compatibility.
|
||||
throw new InfoParserException("The 'core_version_requirement' key must be present in " . $filename);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if the extension is compatible with the current version of
|
||||
// Drupal core.
|
||||
try {
|
||||
$parsed_info['core_incompatible'] = !Semver::satisfies(\Drupal::VERSION, $parsed_info['core_version_requirement']);
|
||||
}
|
||||
catch (\UnexpectedValueException $exception) {
|
||||
throw new InfoParserException("The 'core_version_requirement' constraint ({$parsed_info['core_version_requirement']}) is not a valid value in $filename");
|
||||
}
|
||||
if (isset($parsed_info['version']) && $parsed_info['version'] === 'VERSION') {
|
||||
$parsed_info['version'] = \Drupal::VERSION;
|
||||
}
|
||||
$parsed_info += [ExtensionLifecycle::LIFECYCLE_IDENTIFIER => ExtensionLifecycle::STABLE];
|
||||
$lifecycle = $parsed_info[ExtensionLifecycle::LIFECYCLE_IDENTIFIER];
|
||||
if (!ExtensionLifecycle::isValid($lifecycle)) {
|
||||
$valid_values = [
|
||||
ExtensionLifecycle::EXPERIMENTAL,
|
||||
ExtensionLifecycle::STABLE,
|
||||
ExtensionLifecycle::DEPRECATED,
|
||||
ExtensionLifecycle::OBSOLETE,
|
||||
];
|
||||
throw new InfoParserException("'lifecycle: {$lifecycle}' is not valid in $filename. Valid values are: '" . implode("', '", $valid_values) . "'.");
|
||||
}
|
||||
if (in_array($lifecycle, [ExtensionLifecycle::DEPRECATED, ExtensionLifecycle::OBSOLETE], TRUE)) {
|
||||
if (empty($parsed_info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER])) {
|
||||
throw new InfoParserException(sprintf("Extension %s (%s) has 'lifecycle: %s' but is missing a '%s' entry.", $parsed_info['name'], $filename, $lifecycle, ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER));
|
||||
}
|
||||
if (!filter_var($parsed_info[ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER], FILTER_VALIDATE_URL)) {
|
||||
throw new InfoParserException(sprintf("Extension %s (%s) has a '%s' entry that is not a valid URL.", $parsed_info['name'], $filename, ExtensionLifecycle::LIFECYCLE_LINK_IDENTIFIER));
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed_info;
|
||||
}
|
||||
|
||||
|
|
|
@ -633,8 +633,6 @@ trait FunctionalTestSetupTrait {
|
|||
$this->classLoader = require __DIR__ . '/../../../../../autoload.php';
|
||||
$request = Request::createFromGlobals();
|
||||
$kernel = TestRunnerKernel::createFromRequest($request, $this->classLoader);
|
||||
// TestRunnerKernel expects the working directory to be DRUPAL_ROOT.
|
||||
chdir(DRUPAL_ROOT);
|
||||
$kernel->boot();
|
||||
$kernel->preHandle($request);
|
||||
$this->prepareDatabasePrefix();
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
namespace Drupal\KernelTests\Core\Theme;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Extension\ExtensionDiscovery;
|
||||
use Drupal\Core\Extension\InfoParserException;
|
||||
use Drupal\Core\Extension\ThemeExtensionList;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
|
||||
/**
|
||||
* Tests the behavior of a theme when base_theme info key is missing.
|
||||
|
@ -34,80 +31,23 @@ class BaseThemeMissingTest extends KernelTestBase {
|
|||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// Add a directory to extension discovery to find the theme with a missing
|
||||
// base class.
|
||||
// @see \Drupal\Core\Extension\ExtensionDiscovery::scan()
|
||||
$settings = Settings::getAll();
|
||||
$settings['test_parent_site'] = 'core/tests/fixtures/test_missing_base_theme';
|
||||
new Settings($settings);
|
||||
|
||||
$this->themeInstaller = $this->container->get('theme_installer');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function register(ContainerBuilder $container) {
|
||||
parent::register($container);
|
||||
|
||||
$container->getDefinition('extension.list.theme')
|
||||
->setClass(VfsThemeExtensionList::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpFilesystem() {
|
||||
parent::setUpFilesystem();
|
||||
|
||||
$vfs_root = vfsStream::setup('core');
|
||||
vfsStream::create([
|
||||
'themes' => [
|
||||
'test_missing_base_theme' => [
|
||||
'test_missing_base_theme.info.yml' => file_get_contents(DRUPAL_ROOT . '/core/tests/fixtures/test_missing_base_theme/test_missing_base_theme.info.yml'),
|
||||
'test_missing_base_theme.theme' => file_get_contents(DRUPAL_ROOT . '/core/tests/fixtures/test_missing_base_theme/test_missing_base_theme.theme'),
|
||||
],
|
||||
],
|
||||
], $vfs_root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests exception is thrown.
|
||||
*/
|
||||
public function testMissingBaseThemeException() {
|
||||
$this->container->get('extension.list.theme')
|
||||
->setExtensionDiscovery(new ExtensionDiscovery('vfs://core'));
|
||||
|
||||
$this->expectException(InfoParserException::class);
|
||||
$this->expectExceptionMessage('Missing required key ("base theme") in themes/test_missing_base_theme/test_missing_base_theme.info.yml, see https://www.drupal.org/node/3066038');
|
||||
$this->expectExceptionMessage('Missing required key ("base theme") in core/tests/fixtures/test_missing_base_theme/test_missing_base_theme.info.yml, see https://www.drupal.org/node/3066038');
|
||||
$this->themeInstaller->install(['test_missing_base_theme']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test theme extension list class.
|
||||
*/
|
||||
class VfsThemeExtensionList extends ThemeExtensionList {
|
||||
|
||||
/**
|
||||
* The extension discovery for this extension list.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ExtensionDiscovery
|
||||
*/
|
||||
protected $extensionDiscovery;
|
||||
|
||||
/**
|
||||
* Sets the extension discovery.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ExtensionDiscovery $discovery
|
||||
* The extension discovery.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setExtensionDiscovery(ExtensionDiscovery $discovery) {
|
||||
$this->extensionDiscovery = $discovery;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getExtensionDiscovery() {
|
||||
return $this->extensionDiscovery;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -241,9 +241,6 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
|
|||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
VarDumper::setHandler(TestVarDumper::class . '::cliHandler');
|
||||
|
||||
// Change the current dir to DRUPAL_ROOT.
|
||||
chdir(static::getDrupalRoot());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,6 +30,8 @@ class TestSiteReleaseLocksCommand extends Command {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$root = dirname(__DIR__, 5);
|
||||
chdir($root);
|
||||
TestDatabase::releaseAllTestLocks();
|
||||
$output->writeln('<info>Successfully released all the test database locks</info>');
|
||||
return 0;
|
||||
|
|
|
@ -38,6 +38,8 @@ class TestSiteTearDownCommand extends Command {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$root = dirname(__DIR__, 5);
|
||||
chdir($root);
|
||||
$db_prefix = $input->getArgument('db-prefix');
|
||||
// Validate the db_prefix argument.
|
||||
try {
|
||||
|
|
|
@ -247,11 +247,6 @@ class CssOptimizerUnitTest extends UnitTestCase {
|
|||
$original_base_path = $base_path;
|
||||
$base_path = '/';
|
||||
|
||||
// \Drupal\Core\Asset\CssOptimizer::loadFile() relies on the current working
|
||||
// directory being the one that is used when index.php is the entry point.
|
||||
// Note: PHPUnit automatically restores the original working directory.
|
||||
chdir(realpath(__DIR__ . '/../../../../../../'));
|
||||
|
||||
$this->assertEquals($expected, $this->optimizer->optimize($css_asset), 'Group of file CSS assets optimized correctly.');
|
||||
|
||||
$base_path = $original_base_path;
|
||||
|
|
|
@ -54,7 +54,6 @@ class QuickStartTest extends TestCase {
|
|||
$php_executable_finder = new PhpExecutableFinder();
|
||||
$this->php = $php_executable_finder->find();
|
||||
$this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);
|
||||
chdir($this->root);
|
||||
if (!is_writable("{$this->root}/sites/simpletest")) {
|
||||
$this->markTestSkipped('This test requires a writable sites/simpletest directory');
|
||||
}
|
||||
|
|
|
@ -21,16 +21,6 @@ use Drupal\Tests\UnitTestCase;
|
|||
*/
|
||||
class UrlConversionTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->root = dirname(__FILE__, 7);
|
||||
// This unit test relies on reading files relative to Drupal root.
|
||||
chdir($this->root);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::convertDbUrlToConnectionInfo
|
||||
*
|
||||
|
|
|
@ -45,8 +45,9 @@ class InfoParserUnitTest extends UnitTestCase {
|
|||
*/
|
||||
public function testInfoParserNonExisting() {
|
||||
vfsStream::setup('modules');
|
||||
$info = $this->infoParser->parse(vfsStream::url('modules') . '/does_not_exist.info.txt');
|
||||
$this->assertEmpty($info, 'Non existing info.yml returns empty array.');
|
||||
$this->expectException('\Drupal\Core\Extension\InfoParserException');
|
||||
$this->expectExceptionMessage('Unable to parse vfs://modules/does_not_exist.info.txt as it does not exist');
|
||||
$this->infoParser->parse(vfsStream::url('modules') . '/does_not_exist.info.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,7 +42,6 @@ class TestSiteApplicationTest extends UnitTestCase {
|
|||
parent::setUp();
|
||||
$php_executable_finder = new PhpExecutableFinder();
|
||||
$this->php = $php_executable_finder->find();
|
||||
$this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -179,3 +179,7 @@ if (getenv('SYMFONY_DEPRECATIONS_HELPER') === FALSE) {
|
|||
$deprecation_ignore_filename = realpath(__DIR__ . "/../.deprecation-ignore.txt");
|
||||
putenv("SYMFONY_DEPRECATIONS_HELPER=ignoreFile=$deprecation_ignore_filename");
|
||||
}
|
||||
|
||||
// Drupal expects to be run from its root directory. This ensures all test types
|
||||
// are consistent.
|
||||
chdir(dirname(__DIR__, 2));
|
||||
|
|
Loading…
Reference in New Issue