diff --git a/core/tests/Drupal/Tests/Listeners/AfterSymfonyListener.php b/core/tests/Drupal/Tests/Listeners/AfterSymfonyListener.php new file mode 100644 index 0000000000000000000000000000000000000000..121d0d2db24677474ba0059defc56f6a5ed61382 --- /dev/null +++ b/core/tests/Drupal/Tests/Listeners/AfterSymfonyListener.php @@ -0,0 +1,33 @@ +<?php + +namespace Drupal\Tests\Listeners; + +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestListener; +use PHPUnit\Framework\TestListenerDefaultImplementation; + +if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) { + class_alias('Drupal\Tests\Listeners\Legacy\AfterSymfonyListener', 'Drupal\Tests\Listeners\AfterSymfonyListener'); + // Using an early return instead of an else does not work when using the + // PHPUnit phar due to some weird PHP behavior (the class gets defined without + // executing the code before it and so the definition is not properly + // conditional). +} +else { + /** + * Listens to PHPUnit test runs. + * + * @internal + */ + class AfterSymfonyListener implements TestListener { + use TestListenerDefaultImplementation; + + /** + * {@inheritdoc} + */ + public function endTest(Test $test, $time) { + restore_error_handler(); + } + + } +} diff --git a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php index c67d7068d6b0c0670d81cc6b02db541d7dd98fe2..ef1d94d578ebb7fbdb280b6d1764a49c841441c0 100644 --- a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php +++ b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php @@ -13,10 +13,21 @@ * fixed. */ trait DeprecationListenerTrait { + use ExpectDeprecationTrait; + /** + * The previous error handler. + * + * @var callable + */ + private $previousHandler; + protected function deprecationStartTest($test) { if ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase) { + if ('disabled' !== getenv('SYMFONY_DEPRECATIONS_HELPER')) { + $this->registerErrorHandler($test); + } if ($this->willBeIsolated($test)) { putenv('DRUPAL_EXPECTED_DEPRECATIONS_SERIALIZE=' . tempnam(sys_get_temp_dir(), 'exdep')); } @@ -126,6 +137,8 @@ public static function getSkippedDeprecations() { // is a Windows only deprecation. Remove when core no longer uses // WinCacheClassLoader in \Drupal\Core\DrupalKernel::initializeSettings(). 'The Symfony\Component\ClassLoader\WinCacheClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use `composer install --apcu-autoloader` instead.', + // The following deprecation message is skipped for testing purposes. + '\Drupal\Tests\SkippedDeprecationTest deprecation', // These deprecations are triggered by symfony/psr-http-message-factory // 1.2, which can be installed if you update dependencies on php 7 or // higher @@ -134,4 +147,40 @@ public static function getSkippedDeprecations() { ]; } + /** + * Registers an error handler that wraps Symfony's DeprecationErrorHandler. + * + * @see \Symfony\Bridge\PhpUnit\DeprecationErrorHandler + * @see \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait + */ + protected function registerErrorHandler($test) { + $deprecation_handler = function ($type, $msg, $file, $line, $context = []) { + // Skip listed deprecations. + if ($type === E_USER_DEPRECATED && in_array($msg, self::getSkippedDeprecations(), TRUE)) { + return; + } + return call_user_func($this->previousHandler, $type, $msg, $file, $line, $context); + }; + + if ($this->previousHandler) { + set_error_handler($deprecation_handler); + return; + } + $this->previousHandler = set_error_handler($deprecation_handler); + + // Register another listener so that we can remove the error handler before + // Symfony's DeprecationErrorHandler checks that it is the currently + // registered handler. Note this is done like this to ensure the error + // handler is removed after SymfonyTestsListenerTrait::endTest() is called. + // SymfonyTestsListenerTrait has its own error handler that needs to be + // removed before this one. + $test_result_object = $test->getTestResultObject(); + $reflection_class = new \ReflectionClass($test_result_object); + $reflection_property = $reflection_class->getProperty('listeners'); + $reflection_property->setAccessible(TRUE); + $listeners = $reflection_property->getValue($test_result_object); + $listeners[] = new AfterSymfonyListener(); + $reflection_property->setValue($test_result_object, $listeners); + } + } diff --git a/core/tests/Drupal/Tests/Listeners/Legacy/AfterSymfonyListener.php b/core/tests/Drupal/Tests/Listeners/Legacy/AfterSymfonyListener.php new file mode 100644 index 0000000000000000000000000000000000000000..fec2d78264d609993a3e7445bec623e0c9ce2660 --- /dev/null +++ b/core/tests/Drupal/Tests/Listeners/Legacy/AfterSymfonyListener.php @@ -0,0 +1,19 @@ +<?php + +namespace Drupal\Tests\Listeners\Legacy; + +/** + * Listens to PHPUnit test runs. + * + * @internal + */ +class AfterSymfonyListener extends \PHPUnit_Framework_BaseTestListener { + + /** + * {@inheritdoc} + */ + public function endTest(\PHPUnit_Framework_Test $test, $time) { + restore_error_handler(); + } + +} diff --git a/core/tests/Drupal/Tests/SkippedDeprecationTest.php b/core/tests/Drupal/Tests/SkippedDeprecationTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b65bdd22e3a19d69efe460bd027f8b1219b74bd8 --- /dev/null +++ b/core/tests/Drupal/Tests/SkippedDeprecationTest.php @@ -0,0 +1,30 @@ +<?php + +namespace Drupal\Tests; + +/** + * @group Test + */ +class SkippedDeprecationTest extends UnitTestCase { + + /** + * Tests skipping deprecations in unit tests. + * + * @see \Drupal\Tests\Listeners\DeprecationListenerTrait::getSkippedDeprecations() + */ + public function testSkippingDeprecations() { + @trigger_error('\Drupal\Tests\SkippedDeprecationTest deprecation', E_USER_DEPRECATED); + $this->addToAssertionCount(1); + } + + /** + * Tests skipping deprecations in unit tests multiple times. + * + * @see \Drupal\Tests\Listeners\DeprecationListenerTrait::getSkippedDeprecations() + */ + public function testSkippingDeprecationsAgain() { + @trigger_error('\Drupal\Tests\SkippedDeprecationTest deprecation', E_USER_DEPRECATED); + $this->addToAssertionCount(1); + } + +}