diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 0f54a52bb8..a7dbc08e0c 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -238,6 +238,20 @@ class DeprecationErrorHandler } } + public static function collectDeprecations($outputFile) + { + $deprecations = array(); + $previousErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, &$previousErrorHandler) { + if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) { + return $previousErrorHandler ? $previousErrorHandler($type, $msg, $file, $line, $context) : false; + } + $deprecations[] = array(error_reporting(), $msg); + }); + register_shutdown_function(function () use ($outputFile, &$deprecations) { + file_put_contents($outputFile, serialize($deprecations)); + }); + } + private static function hasColorSupport() { if ('\\' === DIRECTORY_SEPARATOR) { diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index b561c8f2f5..166c44a3f8 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -39,6 +39,7 @@ class SymfonyTestsListenerTrait private $testsWithWarnings; private $reportUselessTests; private $error; + private $runsInSeparateProcess = false; /** * @param array $mockedNamespaces List of namespaces, indexed by mocked features (time-sensitive or dns-sensitive) @@ -183,6 +184,12 @@ class SymfonyTestsListenerTrait $this->reportUselessTests = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything(); } + // This event is triggered before the test is re-run in isolation + if ($this->willBeIsolated($test)) { + $this->runsInSeparateProcess = tempnam(sys_get_temp_dir(), 'deprec'); + putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$this->runsInSeparateProcess); + } + if (class_exists('PHPUnit_Util_Blacklist', false)) { $Test = 'PHPUnit_Util_Test'; $AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError'; @@ -192,12 +199,14 @@ class SymfonyTestsListenerTrait } $groups = $Test::getGroups(get_class($test), $test->getName(false)); - if (in_array('time-sensitive', $groups, true)) { - ClockMock::register(get_class($test)); - ClockMock::withClockMock(true); - } - if (in_array('dns-sensitive', $groups, true)) { - DnsMock::register(get_class($test)); + if (!$this->runsInSeparateProcess) { + if (in_array('time-sensitive', $groups, true)) { + ClockMock::register(get_class($test)); + ClockMock::withClockMock(true); + } + if (in_array('dns-sensitive', $groups, true)) { + DnsMock::register(get_class($test)); + } } $annotations = $Test::parseTestMethodAnnotations(get_class($test), $test->getName(false)); @@ -245,17 +254,22 @@ class SymfonyTestsListenerTrait $this->reportUselessTests = null; } - $errored = false; - - if (null !== $this->error) { - if ($BaseTestRunner::STATUS_PASSED === $test->getStatus()) { - $test->getTestResultObject()->addError($test, $this->error, 0); - $errored = true; - } - + if ($errored = null !== $this->error) { + $test->getTestResultObject()->addError($test, $this->error, 0); $this->error = null; } + if ($this->runsInSeparateProcess) { + foreach (unserialize(file_get_contents($this->runsInSeparateProcess)) as $deprecation) { + if ($deprecation[0]) { + trigger_error($deprecation[1], E_USER_DEPRECATED); + } else { + @trigger_error($deprecation[1], E_USER_DEPRECATED); + } + } + $this->runsInSeparateProcess = false; + } + if ($this->expectedDeprecations) { if (!in_array($test->getStatus(), array($BaseTestRunner::STATUS_SKIPPED, $BaseTestRunner::STATUS_INCOMPLETE), true)) { $test->addToAssertionCount(count($this->expectedDeprecations)); @@ -277,7 +291,7 @@ class SymfonyTestsListenerTrait $this->expectedDeprecations = $this->gatheredDeprecations = array(); $this->previousErrorHandler = null; } - if (-2 < $this->state && ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { + if (!$this->runsInSeparateProcess && -2 < $this->state && ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) { if (in_array('time-sensitive', $groups, true)) { ClockMock::withClockMock(false); } @@ -315,4 +329,21 @@ class SymfonyTestsListenerTrait } $this->gatheredDeprecations[] = $msg; } + + /** + * @param Test $test + * + * @return bool + */ + private function willBeIsolated($test) + { + if ($test->isInIsolation()) { + return false; + } + + $r = new \ReflectionProperty($test, 'runTestInSeparateProcess'); + $r->setAccessible(true); + + return $r->getValue($test); + } } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php new file mode 100644 index 0000000000..d8677097e5 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php @@ -0,0 +1,23 @@ +