From 75f9e432813c0069062bff230d63430cb10b14ca Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Mon, 15 Jan 2018 08:54:44 +1000
Subject: [PATCH] Issue #2935755 by alexpott, Wim Leers: Add a trait to allow
 dynamic setting of expected deprecations

---
 .../Drupal/Tests/ExpectDeprecationTest.php    | 24 +++++
 .../Tests/Traits/ExpectDeprecationTrait.php   | 90 +++++++++++++++++++
 2 files changed, 114 insertions(+)
 create mode 100644 core/tests/Drupal/Tests/ExpectDeprecationTest.php
 create mode 100644 core/tests/Drupal/Tests/Traits/ExpectDeprecationTrait.php

diff --git a/core/tests/Drupal/Tests/ExpectDeprecationTest.php b/core/tests/Drupal/Tests/ExpectDeprecationTest.php
new file mode 100644
index 000000000000..8ebf3b5a210d
--- /dev/null
+++ b/core/tests/Drupal/Tests/ExpectDeprecationTest.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\Tests;
+
+use Drupal\Tests\Traits\ExpectDeprecationTrait;
+
+/**
+ * @coversDefaultClass \Drupal\Tests\Traits\ExpectDeprecationTrait
+ *
+ * @group Test
+ * @group legacy
+ */
+class ExpectDeprecationTest extends UnitTestCase {
+  use ExpectDeprecationTrait;
+
+  /**
+   * @covers ::expectDeprecation
+   */
+  public function testExpectDeprecation() {
+    $this->expectDeprecation('Test deprecation');
+    @trigger_error('Test deprecation', E_USER_DEPRECATED);
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Traits/ExpectDeprecationTrait.php b/core/tests/Drupal/Tests/Traits/ExpectDeprecationTrait.php
new file mode 100644
index 000000000000..279612e94369
--- /dev/null
+++ b/core/tests/Drupal/Tests/Traits/ExpectDeprecationTrait.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Drupal\Tests\Traits;
+
+use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListener as LegacySymfonyTestsListener;
+use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
+
+/**
+ * Adds the ability to dynamically set expected deprecation messages in tests.
+ *
+ * @internal
+ *   This class should only be used by Drupal core and will be removed once
+ *   https://github.com/symfony/symfony/pull/25757 is resolved.
+ *
+ * @todo Remove once https://github.com/symfony/symfony/pull/25757 is resolved.
+ */
+trait ExpectDeprecationTrait {
+
+  /**
+   * Sets an expected deprecation message.
+   *
+   * @param string $msg
+   *   The expected deprecation message.
+   */
+  protected function expectDeprecation($msg) {
+    // Ensure the class or method is in the legacy group.
+    if (class_exists('PHPUnit_Util_Test', FALSE)) {
+      $test_util = 'PHPUnit_Util_Test';
+      $assertion_failed_error = 'PHPUnit_Framework_AssertionFailedError';
+    }
+    else {
+      $test_util = 'PHPUnit\Util\Test';
+      $assertion_failed_error = 'PHPUnit\Framework\AssertionFailedError';
+    }
+    $groups = $test_util::getGroups(get_class($this), $this->getName(FALSE));
+    if (!in_array('legacy', $groups, TRUE)) {
+      throw new $assertion_failed_error('Only tests with the `@group legacy` annotation can call `setExpectedDeprecation()`.');
+    }
+
+    if ($trait = $this->getSymfonyTestListenerTrait()) {
+      // If setting an expected deprecation there is no need to be strict about
+      // testing nothing as this is an assertion.
+      $this->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything(FALSE);
+
+      // Add the expected deprecation message to the class property.
+      $reflection_class = new \ReflectionClass($trait);
+      $expected_deprecations_property = $reflection_class->getProperty('expectedDeprecations');
+      $expected_deprecations_property->setAccessible(TRUE);
+      $expected_deprecations = $expected_deprecations_property->getValue($trait);
+      $expected_deprecations[] = $msg;
+      $expected_deprecations_property->setValue($trait, $expected_deprecations);
+
+      // Register the error handler if necessary.
+      $previous_error_handler_property = $reflection_class->getProperty('previousErrorHandler');
+      $previous_error_handler_property->setAccessible(TRUE);
+      $previous_error_handler = $previous_error_handler_property->getValue($trait);
+      if (!$previous_error_handler) {
+        $previous_error_handler = set_error_handler([$trait, 'handleError']);
+        $previous_error_handler_property->setValue($trait, $previous_error_handler);
+      }
+    }
+    else {
+      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.');
+    }
+  }
+
+  /**
+   * Gets the SymfonyTestsListenerTrait.
+   *
+   * @return \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait|null
+   *   The SymfonyTestsListenerTrait object or NULL is a Symfony test listener
+   *   is not present.
+   */
+  private function getSymfonyTestListenerTrait() {
+    $test_result_object = $this->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);
+    foreach ($listeners as $listener) {
+      if ($listener instanceof SymfonyTestsListener || $listener instanceof LegacySymfonyTestsListener) {
+        $reflection_class = new \ReflectionClass($listener);
+        $reflection_property = $reflection_class->getProperty('trait');
+        $reflection_property->setAccessible(TRUE);
+        return $reflection_property->getValue($listener);
+      }
+    }
+  }
+
+}
-- 
GitLab