From 6f67db84764f5c17fd54a6005ade48c6361c906b Mon Sep 17 00:00:00 2001 From: Wim Leers <44946-wimleers@users.noreply.drupalcode.org> Date: Mon, 3 Apr 2023 16:31:28 +0000 Subject: [PATCH] Issue #3348441 by kunal.sachdev, phenaproxima, Wim Leers: Many callers of ValidationResult::createError() violate its interface due to lack of strict typing --- package_manager/src/ValidationResult.php | 20 ++++++++++++++----- .../Validator/EnvironmentSupportValidator.php | 7 ++++--- .../src/Validator/StagedDBUpdateValidator.php | 1 + .../Validator/SupportedReleaseValidator.php | 3 +-- .../Kernel/ComposerPatchesValidatorTest.php | 2 +- .../src/Kernel/DiskSpaceValidatorTest.php | 6 +++--- .../Kernel/DuplicateInfoFileValidatorTest.php | 16 +++++++-------- .../EnvironmentSupportValidatorTest.php | 6 +++--- .../Kernel/PendingUpdatesValidatorTest.php | 2 +- .../Kernel/SupportedReleaseValidatorTest.php | 2 +- .../WritableFileSystemValidatorTest.php | 4 ++-- .../tests/src/Unit/ValidationResultTest.php | 16 +++++++++++++++ .../ScaffoldFilePermissionsValidator.php | 2 +- .../StagedDatabaseUpdateValidator.php | 1 + .../StatusCheck/CronServerValidatorTest.php | 2 +- .../ScaffoldFilePermissionsValidatorTest.php | 1 + 16 files changed, 60 insertions(+), 31 deletions(-) diff --git a/package_manager/src/ValidationResult.php b/package_manager/src/ValidationResult.php index d6e2a16b63..aafd42a239 100644 --- a/package_manager/src/ValidationResult.php +++ b/package_manager/src/ValidationResult.php @@ -4,6 +4,7 @@ declare(strict_types = 1); namespace Drupal\package_manager; +use Drupal\Component\Assertion\Inspector; use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\system\SystemManager; @@ -21,9 +22,18 @@ final class ValidationResult { * @param \Drupal\Core\StringTranslation\TranslatableMarkup[]|string[] $messages * The error messages. * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $summary - * The errors summary. + * A summary of the result messages. + * @param bool $assert_translatable + * Whether to assert the messages are translatable. Internal use only. + * + * @throws \InvalidArgumentException + * Thrown if $messages is empty, or if it has 2 or more items but $summary + * is NULL. */ - private function __construct(protected int $severity, protected array $messages, protected ?TranslatableMarkup $summary = NULL) { + private function __construct(protected int $severity, protected array $messages, protected ?TranslatableMarkup $summary, bool $assert_translatable) { + if ($assert_translatable) { + assert(Inspector::assertAll(fn ($message) => $message instanceof TranslatableMarkup, $messages)); + } if (empty($messages)) { throw new \InvalidArgumentException('At least one message is required.'); } @@ -43,7 +53,7 @@ final class ValidationResult { * @return static */ public static function createErrorFromThrowable(\Throwable $throwable, ?TranslatableMarkup $summary = NULL): self { - return new static(SystemManager::REQUIREMENT_ERROR, [$throwable->getMessage()], $summary); + return new static(SystemManager::REQUIREMENT_ERROR, [$throwable->getMessage()], $summary, FALSE); } /** @@ -57,7 +67,7 @@ final class ValidationResult { * @return static */ public static function createError(array $messages, ?TranslatableMarkup $summary = NULL): self { - return new static(SystemManager::REQUIREMENT_ERROR, $messages, $summary); + return new static(SystemManager::REQUIREMENT_ERROR, $messages, $summary, TRUE); } /** @@ -71,7 +81,7 @@ final class ValidationResult { * @return static */ public static function createWarning(array $messages, ?TranslatableMarkup $summary = NULL): self { - return new static(SystemManager::REQUIREMENT_WARNING, $messages, $summary); + return new static(SystemManager::REQUIREMENT_WARNING, $messages, $summary, TRUE); } /** diff --git a/package_manager/src/Validator/EnvironmentSupportValidator.php b/package_manager/src/Validator/EnvironmentSupportValidator.php index bef02f2e44..3cd6cd5bfb 100644 --- a/package_manager/src/Validator/EnvironmentSupportValidator.php +++ b/package_manager/src/Validator/EnvironmentSupportValidator.php @@ -4,7 +4,6 @@ declare(strict_types = 1); namespace Drupal\package_manager\Validator; -use Drupal\Core\Link; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\package_manager\Event\PreOperationStageEvent; use Drupal\Core\Url; @@ -49,8 +48,10 @@ final class EnvironmentSupportValidator implements EventSubscriberInterface { // If the URL is not parseable, catch the exception that Url::fromUri() // would generate. try { - $message = Link::fromTextAndUrl($message, Url::fromUri($help_url)) - ->toString(); + $message = $this->t('<a href=":url">@message</a>', [ + ':url' => Url::fromUri($help_url)->toString(), + '@message' => $message, + ]); } catch (\InvalidArgumentException) { // No need to do anything here. The message just won't be a link. diff --git a/package_manager/src/Validator/StagedDBUpdateValidator.php b/package_manager/src/Validator/StagedDBUpdateValidator.php index b6f37fa965..79545027c3 100644 --- a/package_manager/src/Validator/StagedDBUpdateValidator.php +++ b/package_manager/src/Validator/StagedDBUpdateValidator.php @@ -57,6 +57,7 @@ class StagedDBUpdateValidator implements EventSubscriberInterface { $extensions_with_updates = $this->getExtensionsWithDatabaseUpdates($stage_dir); if ($extensions_with_updates) { + $extensions_with_updates = array_map($this->t(...), $extensions_with_updates); $event->addWarning($extensions_with_updates, $this->t('Possible database updates have been detected in the following extensions.')); } } diff --git a/package_manager/src/Validator/SupportedReleaseValidator.php b/package_manager/src/Validator/SupportedReleaseValidator.php index c821081c23..bf9dddc6bd 100644 --- a/package_manager/src/Validator/SupportedReleaseValidator.php +++ b/package_manager/src/Validator/SupportedReleaseValidator.php @@ -4,7 +4,6 @@ declare(strict_types = 1); namespace Drupal\package_manager\Validator; -use Drupal\Component\Render\FormattableMarkup; use Drupal\package_manager\ComposerInspector; use Drupal\package_manager\PathLocator; use Drupal\package_manager\ProjectInfo; @@ -104,7 +103,7 @@ final class SupportedReleaseValidator implements EventSubscriberInterface { } $semantic_version = $staged_package->version; if (!$this->isSupportedRelease($project_name, $semantic_version)) { - $unsupported_packages[] = new FormattableMarkup('@project_name (@package_name) @version', [ + $unsupported_packages[] = $this->t('@project_name (@package_name) @version', [ '@project_name' => $project_name, '@package_name' => $package_name, '@version' => $semantic_version, diff --git a/package_manager/tests/src/Kernel/ComposerPatchesValidatorTest.php b/package_manager/tests/src/Kernel/ComposerPatchesValidatorTest.php index ab7fbd362e..9a842d67b6 100644 --- a/package_manager/tests/src/Kernel/ComposerPatchesValidatorTest.php +++ b/package_manager/tests/src/Kernel/ComposerPatchesValidatorTest.php @@ -281,7 +281,7 @@ class ComposerPatchesValidatorTest extends PackageManagerKernelTestBase { ->toString(); // Reformat the provided results so that they all have the link to the // online documentation appended to them. - $messages[$message_index] = $message . ' See <a href="' . $url . '">the help page</a> for information on how to resolve the problem.'; + $messages[$message_index] = t('@message See <a href=":url">the help page</a> for information on how to resolve the problem.', ['@message' => $message, ':url' => $url]); } } $expected_results[$result_index] = ValidationResult::createError($messages, $result->getSummary()); diff --git a/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php b/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php index bf06f77ddd..a541b615e4 100644 --- a/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php +++ b/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php @@ -28,9 +28,9 @@ class DiskSpaceValidatorTest extends PackageManagerKernelTestBase { $root = '<PROJECT_ROOT>'; $vendor = '<VENDOR_DIR>'; - $root_insufficient = "Drupal root filesystem \"$root\" has insufficient space. There must be at least 1024 megabytes free."; - $vendor_insufficient = "Vendor filesystem \"$vendor\" has insufficient space. There must be at least 1024 megabytes free."; - $temp_insufficient = 'Directory "temp" has insufficient space. There must be at least 1024 megabytes free.'; + $root_insufficient = t('Drupal root filesystem "<PROJECT_ROOT>" has insufficient space. There must be at least 1024 megabytes free.'); + $vendor_insufficient = t('Vendor filesystem "<VENDOR_DIR>" has insufficient space. There must be at least 1024 megabytes free.'); + $temp_insufficient = t('Directory "temp" has insufficient space. There must be at least 1024 megabytes free.'); $summary = t("There is not enough disk space to create a stage directory."); return [ diff --git a/package_manager/tests/src/Kernel/DuplicateInfoFileValidatorTest.php b/package_manager/tests/src/Kernel/DuplicateInfoFileValidatorTest.php index c17377524a..43da1afd87 100644 --- a/package_manager/tests/src/Kernel/DuplicateInfoFileValidatorTest.php +++ b/package_manager/tests/src/Kernel/DuplicateInfoFileValidatorTest.php @@ -34,7 +34,7 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase { ], [ ValidationResult::createError([ - 'The stage directory has 2 instances of module.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 2 instances of module.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.'), ]), ], ], @@ -98,7 +98,7 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase { ], [ ValidationResult::createError([ - 'The stage directory has 2 instances of module.info.yml. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 2 instances of module.info.yml. This likely indicates that a duplicate extension was installed.'), ]), ], ], @@ -137,10 +137,10 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase { ], [ ValidationResult::createError([ - 'The stage directory has 3 instances of module2.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 3 instances of module2.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.'), ]), ValidationResult::createError([ - 'The stage directory has 2 instances of module1.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 2 instances of module1.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.'), ]), ], ], @@ -155,10 +155,10 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase { ], [ ValidationResult::createError([ - 'The stage directory has 3 instances of module2.info.yml. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 3 instances of module2.info.yml. This likely indicates that a duplicate extension was installed.'), ]), ValidationResult::createError([ - 'The stage directory has 2 instances of module1.info.yml. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 2 instances of module1.info.yml. This likely indicates that a duplicate extension was installed.'), ]), ], ], @@ -175,10 +175,10 @@ class DuplicateInfoFileValidatorTest extends PackageManagerKernelTestBase { ], [ ValidationResult::createError([ - 'The stage directory has 3 instances of module2.info.yml. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 3 instances of module2.info.yml. This likely indicates that a duplicate extension was installed.'), ]), ValidationResult::createError([ - 'The stage directory has 2 instances of module1.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.', + t('The stage directory has 2 instances of module1.info.yml as compared to 1 in the active directory. This likely indicates that a duplicate extension was installed.'), ]), ], ], diff --git a/package_manager/tests/src/Kernel/EnvironmentSupportValidatorTest.php b/package_manager/tests/src/Kernel/EnvironmentSupportValidatorTest.php index 328839bb95..806f1b0a26 100644 --- a/package_manager/tests/src/Kernel/EnvironmentSupportValidatorTest.php +++ b/package_manager/tests/src/Kernel/EnvironmentSupportValidatorTest.php @@ -42,7 +42,7 @@ class EnvironmentSupportValidatorTest extends PackageManagerKernelTestBase { }); $result = ValidationResult::createError([ - 'Package Manager is not supported by your environment.', + t('Package Manager is not supported by your environment.'), ]); $this->assertEventPropagationStopped(PreApplyEvent::class, [$this->container->get(EnvironmentSupportValidator::class), 'validate']); @@ -57,7 +57,7 @@ class EnvironmentSupportValidatorTest extends PackageManagerKernelTestBase { putenv(EnvironmentSupportValidator::VARIABLE_NAME . '=' . $url); $result = ValidationResult::createError([ - '<a href="' . $url . '">Package Manager is not supported by your environment.</a>', + t('<a href=":url">Package Manager is not supported by your environment.</a>', [':url' => $url]), ]); $this->assertStatusCheckResults([$result]); $this->assertResults([$result], PreCreateEvent::class); @@ -73,7 +73,7 @@ class EnvironmentSupportValidatorTest extends PackageManagerKernelTestBase { }); $result = ValidationResult::createError([ - '<a href="' . $url . '">Package Manager is not supported by your environment.</a>', + t('<a href=":url">Package Manager is not supported by your environment.</a>', [':url' => $url]), ]); $this->assertResults([$result], PreApplyEvent::class); } diff --git a/package_manager/tests/src/Kernel/PendingUpdatesValidatorTest.php b/package_manager/tests/src/Kernel/PendingUpdatesValidatorTest.php index bf4c160057..2c3cb64f4c 100644 --- a/package_manager/tests/src/Kernel/PendingUpdatesValidatorTest.php +++ b/package_manager/tests/src/Kernel/PendingUpdatesValidatorTest.php @@ -75,7 +75,7 @@ class PendingUpdatesValidatorTest extends PackageManagerKernelTestBase { // will think it's pending. require_once __DIR__ . '/../../fixtures/post_update.php'; $result = ValidationResult::createError([ - 'Some modules have database schema updates to install. You should run the <a href="/update.php">database update script</a> immediately.', + t('Some modules have database schema updates to install. You should run the <a href="/update.php">database update script</a> immediately.'), ]); try { $stage->apply(); diff --git a/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php b/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php index 754234ad3a..87f15c57de 100644 --- a/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php +++ b/package_manager/tests/src/Kernel/SupportedReleaseValidatorTest.php @@ -163,7 +163,7 @@ class SupportedReleaseValidatorTest extends PackageManagerKernelTestBase { 'type' => 'drupal-theme', ], [ - ValidationResult::createError(['package_manager_theme (drupal/package_manager_theme) 8.2.0'], $summary), + ValidationResult::createError([t('package_manager_theme (drupal/package_manager_theme) 8.2.0')], $summary), ], ], // For modules that don't start with 'drupal/' will not have update XML diff --git a/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php b/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php index 3b31104e18..ec5f13f4ae 100644 --- a/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php +++ b/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php @@ -141,14 +141,14 @@ class WritableFileSystemValidatorTest extends PackageManagerKernelTestBase { 'write-protected stage root exists' => [ $non_writable_permission, [ - ValidationResult::createError(['The stage root directory "<STAGE_ROOT>" is not writable.'], $summary), + ValidationResult::createError([t('The stage root directory "<STAGE_ROOT>" is not writable.')], $summary), ], FALSE, ], 'stage root directory does not exist, parent directory not writable' => [ $non_writable_permission, [ - ValidationResult::createError(['The stage root directory will not able to be created at "<STAGE_ROOT_PARENT>".'], $summary), + ValidationResult::createError([t('The stage root directory will not able to be created at "<STAGE_ROOT_PARENT>".')], $summary), ], TRUE, ], diff --git a/package_manager/tests/src/Unit/ValidationResultTest.php b/package_manager/tests/src/Unit/ValidationResultTest.php index b64f3fbc77..3651c4d926 100644 --- a/package_manager/tests/src/Unit/ValidationResultTest.php +++ b/package_manager/tests/src/Unit/ValidationResultTest.php @@ -91,6 +91,22 @@ class ValidationResultTest extends UnitTestCase { ValidationResult::createError($messages, NULL); } + /** + * Tests that the messages are asserted to be translatable. + * + * @testWith ["createError"] + * ["createWarning"] + */ + public function testMessagesMustBeTranslatable(string $method): void { + // When creating an error from a throwable, the message does not need to be + // translatable. + ValidationResult::createErrorFromThrowable(new \Exception('Burn it down.')); + + $this->expectException(\AssertionError::class); + $this->expectExceptionMessageMatches('/instanceof TranslatableMarkup/'); + ValidationResult::$method(['Not translatable!']); + } + /** * Data provider for test methods that test create exceptions. * diff --git a/src/Validator/ScaffoldFilePermissionsValidator.php b/src/Validator/ScaffoldFilePermissionsValidator.php index 72f7957d13..90ddef01b8 100644 --- a/src/Validator/ScaffoldFilePermissionsValidator.php +++ b/src/Validator/ScaffoldFilePermissionsValidator.php @@ -83,7 +83,7 @@ final class ScaffoldFilePermissionsValidator implements EventSubscriberInterface if ($non_writable_files) { // Re-key the messages in order to prevent false negative comparisons in // tests. - $non_writable_files = array_values($non_writable_files); + $non_writable_files = array_map($this->t(...), array_values($non_writable_files)); $event->addError($non_writable_files, $this->t('The following paths must be writable in order to update default site configuration files.')); } } diff --git a/src/Validator/StagedDatabaseUpdateValidator.php b/src/Validator/StagedDatabaseUpdateValidator.php index 2662c40666..90c3d5018f 100644 --- a/src/Validator/StagedDatabaseUpdateValidator.php +++ b/src/Validator/StagedDatabaseUpdateValidator.php @@ -45,6 +45,7 @@ class StagedDatabaseUpdateValidator implements EventSubscriberInterface { $invalid_extensions = $this->stagedDBUpdateValidator->getExtensionsWithDatabaseUpdates($stage->getStageDirectory()); if ($invalid_extensions) { + $invalid_extensions = array_map($this->t(...), $invalid_extensions); $event->addError($invalid_extensions, $this->t('The update cannot proceed because possible database updates have been detected in the following extensions.')); } } diff --git a/tests/src/Kernel/StatusCheck/CronServerValidatorTest.php b/tests/src/Kernel/StatusCheck/CronServerValidatorTest.php index 5383df65fb..3926a38c9d 100644 --- a/tests/src/Kernel/StatusCheck/CronServerValidatorTest.php +++ b/tests/src/Kernel/StatusCheck/CronServerValidatorTest.php @@ -225,7 +225,7 @@ class CronServerValidatorTest extends AutomaticUpdatesKernelTestBase { foreach ($expected_results as $i => $result) { $messages = []; foreach ($result->getMessages() as $message) { - $messages[] = "$message See <a href=\"$url\">the Automatic Updates help page</a> for more information on how to resolve this."; + $messages[] = t('@message See <a href=":url">the Automatic Updates help page</a> for more information on how to resolve this.', ['@message' => $message, ':url' => $url]); } $expected_results[$i] = ValidationResult::createError($messages); } diff --git a/tests/src/Kernel/StatusCheck/ScaffoldFilePermissionsValidatorTest.php b/tests/src/Kernel/StatusCheck/ScaffoldFilePermissionsValidatorTest.php index 4fad511771..08148333c2 100644 --- a/tests/src/Kernel/StatusCheck/ScaffoldFilePermissionsValidatorTest.php +++ b/tests/src/Kernel/StatusCheck/ScaffoldFilePermissionsValidatorTest.php @@ -52,6 +52,7 @@ class ScaffoldFilePermissionsValidatorTest extends AutomaticUpdatesKernelTestBas // Prepend the active directory to every path listed in the error result, // and add the expected summary. $messages = array_map($map, $result->getMessages()); + $messages = array_map(t(...), $messages); $expected_results[$i] = ValidationResult::createError($messages, t('The following paths must be writable in order to update default site configuration files.')); } parent::assertValidationResultsEqual($expected_results, $actual_results, $path_locator); -- GitLab