3 namespace Drupal\Tests\Traits;
5 use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener as LegacySymfonyTestsListener;
6 use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
7 use PHPUnit\Framework\TestCase;
10 * Adds the ability to dynamically set expected deprecation messages in tests.
13 * This class should only be used by Drupal core and will be removed once
14 * https://github.com/symfony/symfony/pull/25757 is resolved.
16 * @todo Remove once https://github.com/symfony/symfony/pull/25757 is resolved.
18 trait ExpectDeprecationTrait {
21 * Sets an expected deprecation message.
23 * @param string $message
24 * The expected deprecation message.
26 protected function expectDeprecation($message) {
27 $this->expectedDeprecations([$message]);
31 * Sets expected deprecation messages.
33 * @param string[] $messages
34 * The expected deprecation messages.
36 public function expectedDeprecations(array $messages) {
37 if (class_exists('PHPUnit_Util_Test', FALSE)) {
38 $test_util = 'PHPUnit_Util_Test';
39 $assertion_failed_error = 'PHPUnit_Framework_AssertionFailedError';
42 $test_util = 'PHPUnit\Util\Test';
43 $assertion_failed_error = 'PHPUnit\Framework\AssertionFailedError';
45 if ($this instanceof \PHPUnit_Framework_TestCase || $this instanceof TestCase) {
46 // Ensure the class or method is in the legacy group.
47 $groups = $test_util::getGroups(get_class($this), $this->getName(FALSE));
48 if (!in_array('legacy', $groups, TRUE)) {
49 throw new $assertion_failed_error('Only tests with the `@group legacy` annotation can call `setExpectedDeprecation()`.');
52 // If setting an expected deprecation there is no need to be strict about
53 // testing nothing as this is an assertion.
54 $this->getTestResultObject()
55 ->beStrictAboutTestsThatDoNotTestAnything(FALSE);
57 if ($trait = $this->getSymfonyTestListenerTrait()) {
58 // Add the expected deprecation message to the class property.
59 $reflection_class = new \ReflectionClass($trait);
60 $expected_deprecations_property = $reflection_class->getProperty('expectedDeprecations');
61 $expected_deprecations_property->setAccessible(TRUE);
62 $expected_deprecations = $expected_deprecations_property->getValue($trait);
63 $expected_deprecations = array_merge($expected_deprecations, $messages);
64 $expected_deprecations_property->setValue($trait, $expected_deprecations);
66 // Register the error handler if necessary.
67 $previous_error_handler_property = $reflection_class->getProperty('previousErrorHandler');
68 $previous_error_handler_property->setAccessible(TRUE);
69 $previous_error_handler = $previous_error_handler_property->getValue($trait);
70 if (!$previous_error_handler) {
71 $previous_error_handler = set_error_handler([$trait, 'handleError']);
72 $previous_error_handler_property->setValue($trait, $previous_error_handler);
78 // Expected deprecations set by isolated tests need to be written to a file
79 // so that the test running process can take account of them.
80 if ($file = getenv('DRUPAL_EXPECTED_DEPRECATIONS_SERIALIZE')) {
81 $expected_deprecations = file_get_contents($file);
82 if ($expected_deprecations) {
83 $expected_deprecations = array_merge(unserialize($expected_deprecations), $messages);
86 $expected_deprecations = $messages;
88 file_put_contents($file, serialize($expected_deprecations));
92 throw new $assertion_failed_error('Can not set an expected deprecation message because the Symfony\Bridge\PhpUnit\SymfonyTestsListener is not registered as a PHPUnit test listener.');
96 * Gets the SymfonyTestsListenerTrait.
98 * @return \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait|null
99 * The SymfonyTestsListenerTrait object or NULL is a Symfony test listener
102 private function getSymfonyTestListenerTrait() {
103 $test_result_object = $this->getTestResultObject();
104 $reflection_class = new \ReflectionClass($test_result_object);
105 $reflection_property = $reflection_class->getProperty('listeners');
106 $reflection_property->setAccessible(TRUE);
107 $listeners = $reflection_property->getValue($test_result_object);
108 foreach ($listeners as $listener) {
109 if ($listener instanceof SymfonyTestsListener || $listener instanceof LegacySymfonyTestsListener) {
110 $reflection_class = new \ReflectionClass($listener);
111 $reflection_property = $reflection_class->getProperty('trait');
112 $reflection_property->setAccessible(TRUE);
113 return $reflection_property->getValue($listener);