clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
use PHPUnit\TextUI\Command as BaseCommand;
use PHPUnit\TextUI\TestRunner as BaseRunner;
use PHPUnit\Util\Configuration;
use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
/**
* @internal
*/
class CommandForV7 extends BaseCommand
{
protected function createRunner(): BaseRunner
{
$this->arguments['listeners'] ?? $this->arguments['listeners'] = [];
$registeredLocally = false;
foreach ($this->arguments['listeners'] as $registeredListener) {
if ($registeredListener instanceof SymfonyTestsListener) {
$registeredListener->globalListenerDisabled();
$registeredLocally = true;
break;
}
}
if (isset($this->arguments['configuration'])) {
$configuration = $this->arguments['configuration'];
if (!$configuration instanceof Configuration) {
$configuration = Configuration::getInstance($this->arguments['configuration']);
}
foreach ($configuration->getListenerConfiguration() as $registeredListener) {
if ('Symfony\Bridge\PhpUnit\SymfonyTestsListener' === ltrim($registeredListener['class'], '\\')) {
$registeredLocally = true;
break;
}
}
}
if (!$registeredLocally) {
$this->arguments['listeners'][] = new SymfonyTestsListener();
}
return parent::createRunner();
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
use PHPUnit\TextUI\Command as BaseCommand;
use PHPUnit\TextUI\Configuration\Configuration as LegacyConfiguration;
use PHPUnit\TextUI\Configuration\Registry;
use PHPUnit\TextUI\TestRunner as BaseRunner;
use PHPUnit\TextUI\XmlConfiguration\Configuration;
use PHPUnit\TextUI\XmlConfiguration\Loader;
use Symfony\Bridge\PhpUnit\SymfonyTestsListener;
/**
* @internal
*/
class CommandForV9 extends BaseCommand
{
protected function createRunner(): BaseRunner
{
$this->arguments['listeners'] ?? $this->arguments['listeners'] = [];
$registeredLocally = false;
foreach ($this->arguments['listeners'] as $registeredListener) {
if ($registeredListener instanceof SymfonyTestsListener) {
$registeredListener->globalListenerDisabled();
$registeredLocally = true;
break;
}
}
if (isset($this->arguments['configuration'])) {
$configuration = $this->arguments['configuration'];
if (!class_exists(Configuration::class) && !$configuration instanceof LegacyConfiguration) {
$configuration = Registry::getInstance()->get($this->arguments['configuration']);
} elseif (class_exists(Configuration::class) && !$configuration instanceof Configuration) {
$configuration = (new Loader())->load($this->arguments['configuration']);
}
foreach ($configuration->listeners() as $registeredListener) {
if ('Symfony\Bridge\PhpUnit\SymfonyTestsListener' === ltrim($registeredListener->className(), '\\')) {
$registeredLocally = true;
break;
}
}
}
if (!$registeredLocally) {
$this->arguments['listeners'][] = new SymfonyTestsListener();
}
return parent::createRunner();
}
}

View File

@@ -0,0 +1,62 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
/**
* @internal
*/
trait ConstraintLogicTrait
{
private function doEvaluate($other, $description, $returnResult)
{
$success = false;
if ($this->matches($other)) {
$success = true;
}
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description);
}
return null;
}
private function doAdditionalFailureDescription($other): string
{
return '';
}
private function doCount(): int
{
return 1;
}
private function doFailureDescription($other): string
{
return $this->exporter()->export($other).' '.$this->toString();
}
private function doMatches($other): bool
{
return false;
}
private function doToString(): string
{
return '';
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
use SebastianBergmann\Exporter\Exporter;
/**
* @internal
*/
trait ConstraintTraitForV7
{
use ConstraintLogicTrait;
/**
* @return bool|null
*/
public function evaluate($other, $description = '', $returnResult = false)
{
return $this->doEvaluate($other, $description, $returnResult);
}
public function count(): int
{
return $this->doCount();
}
public function toString(): string
{
return $this->doToString();
}
protected function additionalFailureDescription($other): string
{
return $this->doAdditionalFailureDescription($other);
}
protected function exporter(): Exporter
{
if (null === $this->exporter) {
$this->exporter = new Exporter();
}
return $this->exporter;
}
protected function failureDescription($other): string
{
return $this->doFailureDescription($other);
}
protected function matches($other): bool
{
return $this->doMatches($other);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
/**
* @internal
*/
trait ConstraintTraitForV8
{
use ConstraintLogicTrait;
/**
* @return bool|null
*/
public function evaluate($other, $description = '', $returnResult = false)
{
return $this->doEvaluate($other, $description, $returnResult);
}
public function count(): int
{
return $this->doCount();
}
public function toString(): string
{
return $this->doToString();
}
protected function additionalFailureDescription($other): string
{
return $this->doAdditionalFailureDescription($other);
}
protected function failureDescription($other): string
{
return $this->doFailureDescription($other);
}
protected function matches($other): bool
{
return $this->doMatches($other);
}
}

View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
/**
* @internal
*/
trait ConstraintTraitForV9
{
use ConstraintLogicTrait;
public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{
return $this->doEvaluate($other, $description, $returnResult);
}
public function count(): int
{
return $this->doCount();
}
public function toString(): string
{
return $this->doToString();
}
protected function additionalFailureDescription($other): string
{
return $this->doAdditionalFailureDescription($other);
}
protected function failureDescription($other): string
{
return $this->doFailureDescription($other);
}
protected function matches($other): bool
{
return $this->doMatches($other);
}
}

View File

@@ -0,0 +1,45 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
/**
* @internal, use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait instead.
*/
trait ExpectDeprecationTraitBeforeV8_4
{
/**
* @param string $message
*/
protected function expectDeprecation($message): void
{
// Expected deprecations set by isolated tests need to be written to a file
// so that the test running process can take account of them.
if ($file = getenv('SYMFONY_EXPECTED_DEPRECATIONS_SERIALIZE')) {
$this->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything(false);
$expectedDeprecations = file_get_contents($file);
if ($expectedDeprecations) {
$expectedDeprecations = array_merge(unserialize($expectedDeprecations), [$message]);
} else {
$expectedDeprecations = [$message];
}
file_put_contents($file, serialize($expectedDeprecations));
return;
}
if (!SymfonyTestsListenerTrait::$previousErrorHandler) {
SymfonyTestsListenerTrait::$previousErrorHandler = set_error_handler([SymfonyTestsListenerTrait::class, 'handleError']);
}
SymfonyTestsListenerTrait::$expectedDeprecations[] = $message;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
/**
* @internal use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait instead
*/
trait ExpectDeprecationTraitForV8_4
{
/**
* @param string $message
*/
public function expectDeprecation(): void
{
if (1 > \func_num_args() || !\is_string($message = func_get_arg(0))) {
throw new \InvalidArgumentException(sprintf('The "%s()" method requires the string $message argument.', __FUNCTION__));
}
// Expected deprecations set by isolated tests need to be written to a file
// so that the test running process can take account of them.
if ($file = getenv('SYMFONY_EXPECTED_DEPRECATIONS_SERIALIZE')) {
$this->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything(false);
$expectedDeprecations = file_get_contents($file);
if ($expectedDeprecations) {
$expectedDeprecations = array_merge(unserialize($expectedDeprecations), [$message]);
} else {
$expectedDeprecations = [$message];
}
file_put_contents($file, serialize($expectedDeprecations));
return;
}
if (!SymfonyTestsListenerTrait::$previousErrorHandler) {
SymfonyTestsListenerTrait::$previousErrorHandler = set_error_handler([SymfonyTestsListenerTrait::class, 'handleError']);
}
SymfonyTestsListenerTrait::$expectedDeprecations[] = $message;
}
/**
* @internal use expectDeprecation() instead
*/
public function expectDeprecationMessage(string $message): void
{
throw new \BadMethodCallException(sprintf('The "%s()" method is not supported by Symfony\'s PHPUnit Bridge ExpectDeprecationTrait, pass the message to expectDeprecation() instead.', __FUNCTION__));
}
/**
* @internal use expectDeprecation() instead
*/
public function expectDeprecationMessageMatches(string $regularExpression): void
{
throw new \BadMethodCallException(sprintf('The "%s()" method is not supported by Symfony\'s PHPUnit Bridge ExpectDeprecationTrait.', __FUNCTION__));
}
}

View File

@@ -0,0 +1,157 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
use PHPUnit\Framework\Constraint\LogicalNot;
use PHPUnit\Framework\Constraint\TraversableContains;
/**
* This trait is @internal.
*/
trait PolyfillAssertTrait
{
/**
* @param iterable $haystack
* @param string $message
*
* @return void
*/
public static function assertContainsEquals($needle, $haystack, $message = '')
{
$constraint = new TraversableContains($needle, false, false);
static::assertThat($haystack, $constraint, $message);
}
/**
* @param iterable $haystack
* @param string $message
*
* @return void
*/
public static function assertNotContainsEquals($needle, $haystack, $message = '')
{
$constraint = new LogicalNot(new TraversableContains($needle, false, false));
static::assertThat($haystack, $constraint, $message);
}
/**
* @param string $filename
* @param string $message
*
* @return void
*/
public static function assertIsNotReadable($filename, $message = '')
{
static::assertNotIsReadable($filename, $message);
}
/**
* @param string $filename
* @param string $message
*
* @return void
*/
public static function assertIsNotWritable($filename, $message = '')
{
static::assertNotIsWritable($filename, $message);
}
/**
* @param string $directory
* @param string $message
*
* @return void
*/
public static function assertDirectoryDoesNotExist($directory, $message = '')
{
static::assertDirectoryNotExists($directory, $message);
}
/**
* @param string $directory
* @param string $message
*
* @return void
*/
public static function assertDirectoryIsNotReadable($directory, $message = '')
{
static::assertDirectoryNotIsReadable($directory, $message);
}
/**
* @param string $directory
* @param string $message
*
* @return void
*/
public static function assertDirectoryIsNotWritable($directory, $message = '')
{
static::assertDirectoryNotIsWritable($directory, $message);
}
/**
* @param string $filename
* @param string $message
*
* @return void
*/
public static function assertFileDoesNotExist($filename, $message = '')
{
static::assertFileNotExists($filename, $message);
}
/**
* @param string $filename
* @param string $message
*
* @return void
*/
public static function assertFileIsNotReadable($filename, $message = '')
{
static::assertFileNotIsReadable($filename, $message);
}
/**
* @param string $filename
* @param string $message
*
* @return void
*/
public static function assertFileIsNotWritable($filename, $message = '')
{
static::assertFileNotIsWritable($filename, $message);
}
/**
* @param string $pattern
* @param string $string
* @param string $message
*
* @return void
*/
public static function assertMatchesRegularExpression($pattern, $string, $message = '')
{
static::assertRegExp($pattern, $string, $message);
}
/**
* @param string $pattern
* @param string $string
* @param string $message
*
* @return void
*/
public static function assertDoesNotMatchRegularExpression($pattern, $string, $message = '')
{
static::assertNotRegExp($pattern, $string, $message);
}
}

View File

@@ -0,0 +1,116 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
use PHPUnit\Framework\Error\Error;
use PHPUnit\Framework\Error\Notice;
use PHPUnit\Framework\Error\Warning;
/**
* This trait is @internal.
*/
trait PolyfillTestCaseTrait
{
/**
* @param string $messageRegExp
*
* @return void
*/
public function expectExceptionMessageMatches($messageRegExp)
{
$this->expectExceptionMessageRegExp($messageRegExp);
}
/**
* @return void
*/
public function expectNotice()
{
$this->expectException(Notice::class);
}
/**
* @param string $message
*
* @return void
*/
public function expectNoticeMessage($message)
{
$this->expectExceptionMessage($message);
}
/**
* @param string $regularExpression
*
* @return void
*/
public function expectNoticeMessageMatches($regularExpression)
{
$this->expectExceptionMessageMatches($regularExpression);
}
/**
* @return void
*/
public function expectWarning()
{
$this->expectException(Warning::class);
}
/**
* @param string $message
*
* @return void
*/
public function expectWarningMessage($message)
{
$this->expectExceptionMessage($message);
}
/**
* @param string $regularExpression
*
* @return void
*/
public function expectWarningMessageMatches($regularExpression)
{
$this->expectExceptionMessageMatches($regularExpression);
}
/**
* @return void
*/
public function expectError()
{
$this->expectException(Error::class);
}
/**
* @param string $message
*
* @return void
*/
public function expectErrorMessage($message)
{
$this->expectExceptionMessage($message);
}
/**
* @param string $regularExpression
*
* @return void
*/
public function expectErrorMessageMatches($regularExpression)
{
$this->expectExceptionMessageMatches($regularExpression);
}
}

View File

@@ -0,0 +1,61 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestListenerDefaultImplementation;
use PHPUnit\Framework\TestSuite;
/**
* Collects and replays skipped tests.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class SymfonyTestsListenerForV7 implements TestListener
{
use TestListenerDefaultImplementation;
private $trait;
public function __construct(array $mockedNamespaces = [])
{
$this->trait = new SymfonyTestsListenerTrait($mockedNamespaces);
}
public function globalListenerDisabled()
{
$this->trait->globalListenerDisabled();
}
public function startTestSuite(TestSuite $suite): void
{
$this->trait->startTestSuite($suite);
}
public function addSkippedTest(Test $test, \Throwable $t, float $time): void
{
$this->trait->addSkippedTest($test, $t, $time);
}
public function startTest(Test $test): void
{
$this->trait->startTest($test);
}
public function endTest(Test $test, float $time): void
{
$this->trait->endTest($test, $time);
}
}

View File

@@ -0,0 +1,364 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\PhpUnit\Legacy;
use Doctrine\Common\Annotations\AnnotationRegistry;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\DataProviderTestSuite;
use PHPUnit\Framework\RiskyTestError;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\BaseTestRunner;
use PHPUnit\Util\Blacklist;
use PHPUnit\Util\ExcludeList;
use PHPUnit\Util\Test;
use Symfony\Bridge\PhpUnit\ClockMock;
use Symfony\Bridge\PhpUnit\DnsMock;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
use Symfony\Component\ErrorHandler\DebugClassLoader;
/**
* PHP 5.3 compatible trait-like shared implementation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class SymfonyTestsListenerTrait
{
public static $expectedDeprecations = [];
public static $previousErrorHandler;
private static $gatheredDeprecations = [];
private static $globallyEnabled = false;
private $state = -1;
private $skippedFile = false;
private $wasSkipped = [];
private $isSkipped = [];
private $runsInSeparateProcess = false;
private $checkNumAssertions = false;
/**
* @param array $mockedNamespaces List of namespaces, indexed by mocked features (time-sensitive or dns-sensitive)
*/
public function __construct(array $mockedNamespaces = [])
{
setlocale(\LC_ALL, $_ENV['SYMFONY_PHPUNIT_LOCALE'] ?? 'C');
if (class_exists(ExcludeList::class)) {
(new ExcludeList())->getExcludedDirectories();
ExcludeList::addDirectory(\dirname((new \ReflectionClass(__CLASS__))->getFileName(), 2));
} elseif (method_exists(Blacklist::class, 'addDirectory')) {
(new BlackList())->getBlacklistedDirectories();
Blacklist::addDirectory(\dirname((new \ReflectionClass(__CLASS__))->getFileName(), 2));
} else {
Blacklist::$blacklistedClassNames[__CLASS__] = 2;
}
$enableDebugClassLoader = class_exists(DebugClassLoader::class);
foreach ($mockedNamespaces as $type => $namespaces) {
if (!\is_array($namespaces)) {
$namespaces = [$namespaces];
}
if ('time-sensitive' === $type) {
foreach ($namespaces as $ns) {
ClockMock::register($ns.'\DummyClass');
}
}
if ('dns-sensitive' === $type) {
foreach ($namespaces as $ns) {
DnsMock::register($ns.'\DummyClass');
}
}
if ('debug-class-loader' === $type) {
$enableDebugClassLoader = $namespaces && $namespaces[0];
}
}
if ($enableDebugClassLoader) {
DebugClassLoader::enable();
}
if (self::$globallyEnabled) {
$this->state = -2;
} else {
self::$globallyEnabled = true;
}
}
public function __sleep()
{
throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
}
public function __wakeup()
{
throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
}
public function __destruct()
{
if (0 < $this->state) {
file_put_contents($this->skippedFile, '<?php return '.var_export($this->isSkipped, true).';');
}
}
public function globalListenerDisabled(): void
{
self::$globallyEnabled = false;
$this->state = -1;
}
public function startTestSuite($suite): void
{
$suiteName = $suite->getName();
foreach ($suite->tests() as $test) {
if (!$test instanceof TestCase) {
continue;
}
if (null === Test::getPreserveGlobalStateSettings(\get_class($test), $test->getName(false))) {
$test->setPreserveGlobalState(false);
}
}
if (-1 === $this->state) {
echo "Testing $suiteName\n";
$this->state = 0;
if (!class_exists(AnnotationRegistry::class, false) && class_exists(AnnotationRegistry::class)) {
if (method_exists(AnnotationRegistry::class, 'registerUniqueLoader')) {
AnnotationRegistry::registerUniqueLoader('class_exists');
} elseif (method_exists(AnnotationRegistry::class, 'registerLoader')) {
AnnotationRegistry::registerLoader('class_exists');
}
}
if ($this->skippedFile = getenv('SYMFONY_PHPUNIT_SKIPPED_TESTS')) {
$this->state = 1;
if (file_exists($this->skippedFile)) {
$this->state = 2;
if (!$this->wasSkipped = require $this->skippedFile) {
echo "All tests already ran successfully.\n";
$suite->setTests([]);
}
}
}
$testSuites = [$suite];
for ($i = 0; isset($testSuites[$i]); ++$i) {
foreach ($testSuites[$i]->tests() as $test) {
if ($test instanceof TestSuite) {
if (!class_exists($test->getName(), false)) {
$testSuites[] = $test;
continue;
}
$groups = Test::getGroups($test->getName());
if (\in_array('time-sensitive', $groups, true)) {
ClockMock::register($test->getName());
}
if (\in_array('dns-sensitive', $groups, true)) {
DnsMock::register($test->getName());
}
}
}
}
} elseif (2 === $this->state) {
$suites = [$suite];
$skipped = [];
while ($s = array_shift($suites)) {
foreach ($s->tests() as $test) {
if ($test instanceof TestSuite) {
$suites[] = $test;
continue;
}
if ($test instanceof TestCase
&& isset($this->wasSkipped[\get_class($test)][$test->getName()])
) {
$skipped[] = $test;
}
}
}
$suite->setTests($skipped);
}
}
public function addSkippedTest($test, \Exception $e, $time): void
{
if (0 < $this->state) {
if ($test instanceof DataProviderTestSuite) {
foreach ($test->tests() as $testWithDataProvider) {
$this->isSkipped[\get_class($testWithDataProvider)][$testWithDataProvider->getName()] = 1;
}
} else {
$this->isSkipped[\get_class($test)][$test->getName()] = 1;
}
}
}
public function startTest($test): void
{
if (-2 < $this->state && $test instanceof TestCase) {
// 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);
putenv('SYMFONY_EXPECTED_DEPRECATIONS_SERIALIZE='.tempnam(sys_get_temp_dir(), 'expectdeprec'));
}
$groups = Test::getGroups(\get_class($test), $test->getName(false));
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));
}
}
if (!$test->getTestResultObject()) {
return;
}
$annotations = Test::parseTestMethodAnnotations(\get_class($test), $test->getName(false));
if (isset($annotations['class']['expectedDeprecation'])) {
$test->getTestResultObject()->addError($test, new AssertionFailedError('"@expectedDeprecation" annotations are not allowed at the class level.'), 0);
}
if (isset($annotations['method']['expectedDeprecation']) || $this->checkNumAssertions = method_exists($test, 'expectDeprecation') && (new \ReflectionMethod($test, 'expectDeprecation'))->getFileName() === (new \ReflectionMethod(ExpectDeprecationTrait::class, 'expectDeprecation'))->getFileName()) {
if (isset($annotations['method']['expectedDeprecation'])) {
self::$expectedDeprecations = $annotations['method']['expectedDeprecation'];
self::$previousErrorHandler = set_error_handler([self::class, 'handleError']);
@trigger_error('Since symfony/phpunit-bridge 5.1: Using "@expectedDeprecation" annotations in tests is deprecated, use the "ExpectDeprecationTrait::expectDeprecation()" method instead.', \E_USER_DEPRECATED);
}
if ($this->checkNumAssertions) {
$this->checkNumAssertions = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything();
}
$test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything(false);
}
}
}
public function endTest($test, $time): void
{
if ($file = getenv('SYMFONY_EXPECTED_DEPRECATIONS_SERIALIZE')) {
putenv('SYMFONY_EXPECTED_DEPRECATIONS_SERIALIZE');
$expectedDeprecations = file_get_contents($file);
if ($expectedDeprecations) {
self::$expectedDeprecations = array_merge(self::$expectedDeprecations, unserialize($expectedDeprecations));
if (!self::$previousErrorHandler) {
self::$previousErrorHandler = set_error_handler([self::class, 'handleError']);
}
}
}
if (class_exists(DebugClassLoader::class, false)) {
DebugClassLoader::checkClasses();
}
$className = \get_class($test);
$groups = Test::getGroups($className, $test->getName(false));
if ($this->checkNumAssertions) {
$assertions = \count(self::$expectedDeprecations) + $test->getNumAssertions();
if ($test->doesNotPerformAssertions() && $assertions > 0) {
$test->getTestResultObject()->addFailure($test, new RiskyTestError(sprintf('This test is annotated with "@doesNotPerformAssertions", but performed %s assertions', $assertions)), $time);
} elseif ($assertions === 0 && !$test->doesNotPerformAssertions() && $test->getTestResultObject()->noneSkipped()) {
$test->getTestResultObject()->addFailure($test, new RiskyTestError('This test did not perform any assertions'), $time);
}
$this->checkNumAssertions = false;
}
if ($this->runsInSeparateProcess) {
$deprecations = file_get_contents($this->runsInSeparateProcess);
unlink($this->runsInSeparateProcess);
putenv('SYMFONY_DEPRECATIONS_SERIALIZE');
foreach ($deprecations ? unserialize($deprecations) : [] as $deprecation) {
$error = serialize(['deprecation' => $deprecation[1], 'class' => $className, 'method' => $test->getName(false), 'triggering_file' => $deprecation[2] ?? null, 'files_stack' => $deprecation[3] ?? []]);
if ($deprecation[0]) {
// unsilenced on purpose
trigger_error($error, \E_USER_DEPRECATED);
} else {
@trigger_error($error, \E_USER_DEPRECATED);
}
}
$this->runsInSeparateProcess = false;
}
if (self::$expectedDeprecations) {
if (!\in_array($test->getStatus(), [BaseTestRunner::STATUS_SKIPPED, BaseTestRunner::STATUS_INCOMPLETE], true)) {
$test->addToAssertionCount(\count(self::$expectedDeprecations));
}
restore_error_handler();
if (!\in_array('legacy', $groups, true)) {
$test->getTestResultObject()->addError($test, new AssertionFailedError('Only tests with the "@group legacy" annotation can expect a deprecation.'), 0);
} elseif (!\in_array($test->getStatus(), [BaseTestRunner::STATUS_SKIPPED, BaseTestRunner::STATUS_INCOMPLETE, BaseTestRunner::STATUS_FAILURE, BaseTestRunner::STATUS_ERROR], true)) {
try {
$prefix = "@expectedDeprecation:\n";
$test->assertStringMatchesFormat($prefix.'%A '.implode("\n%A ", self::$expectedDeprecations)."\n%A", $prefix.' '.implode("\n ", self::$gatheredDeprecations)."\n");
} catch (AssertionFailedError $e) {
$test->getTestResultObject()->addFailure($test, $e, $time);
}
}
self::$expectedDeprecations = self::$gatheredDeprecations = [];
self::$previousErrorHandler = null;
}
if (!$this->runsInSeparateProcess && -2 < $this->state && $test instanceof TestCase) {
if (\in_array('time-sensitive', $groups, true)) {
ClockMock::withClockMock(false);
}
if (\in_array('dns-sensitive', $groups, true)) {
DnsMock::withMockedHosts([]);
}
}
}
public static function handleError($type, $msg, $file, $line, $context = [])
{
if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) {
$h = self::$previousErrorHandler;
return $h ? $h($type, $msg, $file, $line, $context) : false;
}
// If the message is serialized we need to extract the message. This occurs when the error is triggered by
// by the isolated test path in \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest().
$parsedMsg = @unserialize($msg);
if (\is_array($parsedMsg)) {
$msg = $parsedMsg['deprecation'];
}
if (error_reporting() & $type) {
$msg = 'Unsilenced deprecation: '.$msg;
}
self::$gatheredDeprecations[] = $msg;
return true;
}
private function willBeIsolated(TestCase $test): bool
{
if ($test->isInIsolation()) {
return false;
}
$r = new \ReflectionProperty($test, 'runTestInSeparateProcess');
$r->setAccessible(true);
return $r->getValue($test) ?? false;
}
}