From d4c57876e97dd3e739009804622317ff90ac00cf Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 20 Jun 2024 17:52:34 +0200 Subject: [PATCH 01/13] Prefix all sprintf() calls --- DeprecationErrorHandler.php | 8 ++++---- DeprecationErrorHandler/Configuration.php | 14 +++++++------- DeprecationErrorHandler/Deprecation.php | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/DeprecationErrorHandler.php b/DeprecationErrorHandler.php index 13c9efd..1cf8950 100644 --- a/DeprecationErrorHandler.php +++ b/DeprecationErrorHandler.php @@ -300,7 +300,7 @@ private function displayDeprecations(array $groups, Configuration $configuration if ($configuration->shouldWriteToLogFile()) { if (false === $handle = @fopen($file = $configuration->getLogFile(), 'a')) { - throw new \InvalidArgumentException(sprintf('The configured log file "%s" is not writeable.', $file)); + throw new \InvalidArgumentException(\sprintf('The configured log file "%s" is not writeable.', $file)); } } else { $handle = fopen('php://output', 'w'); @@ -308,7 +308,7 @@ private function displayDeprecations(array $groups, Configuration $configuration foreach ($groups as $group) { if ($this->deprecationGroups[$group]->count()) { - $deprecationGroupMessage = sprintf( + $deprecationGroupMessage = \sprintf( '%s deprecation notices (%d)', \in_array($group, ['direct', 'indirect', 'self'], true) ? "Remaining $group" : ucfirst($group), $this->deprecationGroups[$group]->count() @@ -327,7 +327,7 @@ private function displayDeprecations(array $groups, Configuration $configuration uasort($notices, $cmp); foreach ($notices as $msg => $notice) { - fwrite($handle, sprintf("\n %sx: %s\n", $notice->count(), $msg)); + fwrite($handle, \sprintf("\n %sx: %s\n", $notice->count(), $msg)); $countsByCaller = $notice->getCountsByCaller(); arsort($countsByCaller); @@ -339,7 +339,7 @@ private function displayDeprecations(array $groups, Configuration $configuration fwrite($handle, " ...\n"); break; } - fwrite($handle, sprintf(" %dx in %s\n", $count, preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method))); + fwrite($handle, \sprintf(" %dx in %s\n", $count, preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method))); } } } diff --git a/DeprecationErrorHandler/Configuration.php b/DeprecationErrorHandler/Configuration.php index 000deca..32b120e 100644 --- a/DeprecationErrorHandler/Configuration.php +++ b/DeprecationErrorHandler/Configuration.php @@ -76,10 +76,10 @@ private function __construct(array $thresholds = [], string $regex = '', array $ foreach ($thresholds as $group => $threshold) { if (!\in_array($group, $groups, true)) { - throw new \InvalidArgumentException(sprintf('Unrecognized threshold "%s", expected one of "%s".', $group, implode('", "', $groups))); + throw new \InvalidArgumentException(\sprintf('Unrecognized threshold "%s", expected one of "%s".', $group, implode('", "', $groups))); } if (!is_numeric($threshold)) { - throw new \InvalidArgumentException(sprintf('Threshold for group "%s" has invalid value "%s".', $group, $threshold)); + throw new \InvalidArgumentException(\sprintf('Threshold for group "%s" has invalid value "%s".', $group, $threshold)); } $this->thresholds[$group] = (int) $threshold; } @@ -111,17 +111,17 @@ private function __construct(array $thresholds = [], string $regex = '', array $ foreach ($verboseOutput as $group => $status) { if (!isset($this->verboseOutput[$group])) { - throw new \InvalidArgumentException(sprintf('Unsupported verbosity group "%s", expected one of "%s".', $group, implode('", "', array_keys($this->verboseOutput)))); + throw new \InvalidArgumentException(\sprintf('Unsupported verbosity group "%s", expected one of "%s".', $group, implode('", "', array_keys($this->verboseOutput)))); } $this->verboseOutput[$group] = $status; } if ($ignoreFile) { if (!is_file($ignoreFile)) { - throw new \InvalidArgumentException(sprintf('The ignoreFile "%s" does not exist.', $ignoreFile)); + throw new \InvalidArgumentException(\sprintf('The ignoreFile "%s" does not exist.', $ignoreFile)); } set_error_handler(static function ($t, $m) use ($ignoreFile, &$line) { - throw new \RuntimeException(sprintf('Invalid pattern found in "%s" on line "%d"', $ignoreFile, 1 + $line).substr($m, 12)); + throw new \RuntimeException(\sprintf('Invalid pattern found in "%s" on line "%d"', $ignoreFile, 1 + $line).substr($m, 12)); }); try { foreach (file($ignoreFile) as $line => $pattern) { @@ -147,7 +147,7 @@ private function __construct(array $thresholds = [], string $regex = '', array $ $this->baselineDeprecations[$baseline_deprecation->location][$baseline_deprecation->message] = $baseline_deprecation->count; } } else { - throw new \InvalidArgumentException(sprintf('The baselineFile "%s" does not exist.', $this->baselineFile)); + throw new \InvalidArgumentException(\sprintf('The baselineFile "%s" does not exist.', $this->baselineFile)); } } @@ -312,7 +312,7 @@ public static function fromUrlEncodedString(string $serializedConfiguration): se parse_str($serializedConfiguration, $normalizedConfiguration); foreach (array_keys($normalizedConfiguration) as $key) { if (!\in_array($key, ['max', 'disabled', 'verbose', 'quiet', 'ignoreFile', 'generateBaseline', 'baselineFile', 'logFile'], true)) { - throw new \InvalidArgumentException(sprintf('Unknown configuration option "%s".', $key)); + throw new \InvalidArgumentException(\sprintf('Unknown configuration option "%s".', $key)); } } diff --git a/DeprecationErrorHandler/Deprecation.php b/DeprecationErrorHandler/Deprecation.php index 2d65648..7ea4a34 100644 --- a/DeprecationErrorHandler/Deprecation.php +++ b/DeprecationErrorHandler/Deprecation.php @@ -313,7 +313,7 @@ private function getPackage(string $path): string } } - throw new \RuntimeException(sprintf('No vendors found for path "%s".', $path)); + throw new \RuntimeException(\sprintf('No vendors found for path "%s".', $path)); } /** From 79631684592b3d4ca8e2f0d444b9be110c594f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 1 Jul 2024 02:16:34 +0200 Subject: [PATCH 02/13] Remove useless uniqid in tempnam calls --- Tests/DeprecationErrorHandler/log_file.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/DeprecationErrorHandler/log_file.phpt b/Tests/DeprecationErrorHandler/log_file.phpt index 7f114ab..0a64337 100644 --- a/Tests/DeprecationErrorHandler/log_file.phpt +++ b/Tests/DeprecationErrorHandler/log_file.phpt @@ -2,7 +2,7 @@ Test DeprecationErrorHandler with log file --FILE-- Date: Sat, 6 Jul 2024 09:57:16 +0200 Subject: [PATCH 03/13] Update .gitattributes --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 84c7add..14c3c35 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore +/.git* export-ignore From ca07fb9d9b60c627e571414eb7ccc4be7d3c3b74 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 13 Apr 2024 14:18:00 +0200 Subject: [PATCH 04/13] [PhpUnitBridge] Add ExpectUserDeprecationMessageTrait --- CHANGELOG.md | 5 +++++ ExpectUserDeprecationMessageTrait.php | 30 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 ExpectUserDeprecationMessageTrait.php diff --git a/CHANGELOG.md b/CHANGELOG.md index a8be658..d28ee0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Add `ExpectUserDeprecationMessageTrait` with a polyfill of PHPUnit's `expectUserDeprecationMessage()` + 6.4 --- diff --git a/ExpectUserDeprecationMessageTrait.php b/ExpectUserDeprecationMessageTrait.php new file mode 100644 index 0000000..ede0bdb --- /dev/null +++ b/ExpectUserDeprecationMessageTrait.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit; + +use PHPUnit\Runner\Version; + +if (version_compare(Version::id(), '11.0.0', '<')) { + trait ExpectUserDeprecationMessageTrait + { + use ExpectDeprecationTrait; + + final protected function expectUserDeprecationMessage(string $expectedUserDeprecationMessage): void + { + $this->expectDeprecation($expectedUserDeprecationMessage); + } + } +} else { + trait ExpectUserDeprecationMessageTrait + { + } +} From 6cc75e58830ab9b558ff0d98b1e3f66b6b47e7b7 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 31 Jul 2024 16:13:26 +0200 Subject: [PATCH 05/13] Remove unused code and unnecessary `else` branches --- DeprecationErrorHandler/Deprecation.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/DeprecationErrorHandler/Deprecation.php b/DeprecationErrorHandler/Deprecation.php index 7ea4a34..822e980 100644 --- a/DeprecationErrorHandler/Deprecation.php +++ b/DeprecationErrorHandler/Deprecation.php @@ -149,8 +149,6 @@ public function __construct(string $message, array $trace, string $file, bool $l if (($test instanceof TestCase || $test instanceof TestSuite) && ('trigger_error' !== $trace[$i - 2]['function'] || isset($trace[$i - 2]['class']))) { $this->originClass = \get_class($test); $this->originMethod = $test->getName(); - - return; } } From c085e7ad607d1e911e22764074318ba7141c64d3 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 5 Aug 2024 09:12:25 +0200 Subject: [PATCH 06/13] Fix multiple CS errors --- ClockMock.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ClockMock.php b/ClockMock.php index 95cfc6a..4cca8fc 100644 --- a/ClockMock.php +++ b/ClockMock.php @@ -72,7 +72,7 @@ public static function microtime($asFloat = false) return self::$now; } - return sprintf('%0.6f00 %d', self::$now - (int) self::$now, (int) self::$now); + return \sprintf('%0.6f00 %d', self::$now - (int) self::$now, (int) self::$now); } public static function date($format, $timestamp = null): string @@ -101,7 +101,7 @@ public static function hrtime($asNumber = false) $ns = (self::$now - (int) self::$now) * 1000000000; if ($asNumber) { - $number = sprintf('%d%d', (int) self::$now, $ns); + $number = \sprintf('%d%d', (int) self::$now, $ns); return \PHP_INT_SIZE === 8 ? (int) $number : (float) $number; } From ed423587d2d70ecf0fd3a3a32373c085117dae64 Mon Sep 17 00:00:00 2001 From: Artfaith Date: Fri, 19 Jul 2024 15:07:04 +0200 Subject: [PATCH 07/13] [PhpUnitBridge][Console][VarDumper] Add support for `FORCE_COLOR` environment variable --- DeprecationErrorHandler.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DeprecationErrorHandler.php b/DeprecationErrorHandler.php index 6ad4fbb..b715ecd 100644 --- a/DeprecationErrorHandler.php +++ b/DeprecationErrorHandler.php @@ -411,6 +411,11 @@ private static function hasColorSupport(): bool return false; } + // Follow https://force-color.org/ + if ('' !== (($_SERVER['FORCE_COLOR'] ?? getenv('FORCE_COLOR'))[0] ?? '')) { + return true; + } + // Detect msysgit/mingw and assume this is a tty because detection // does not work correctly, see https://github.com/composer/composer/issues/9690 if (!@stream_isatty(\STDOUT) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { From d8e704a7079bfc3ae014c30db59d7ab4b0d5c14d Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sat, 31 Aug 2024 00:31:12 +0200 Subject: [PATCH 08/13] CS: re-apply `trailing_comma_in_multiline` --- Tests/DeprecationErrorHandler/ConfigurationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/DeprecationErrorHandler/ConfigurationTest.php b/Tests/DeprecationErrorHandler/ConfigurationTest.php index a2259fc..5bbf714 100644 --- a/Tests/DeprecationErrorHandler/ConfigurationTest.php +++ b/Tests/DeprecationErrorHandler/ConfigurationTest.php @@ -474,7 +474,7 @@ public function testBaselineGenerationWithDeprecationTriggeredByDebugClassLoader $trace[2] = [ 'class' => DebugClassLoader::class, 'function' => 'testBaselineGenerationWithDeprecationTriggeredByDebugClassLoader', - 'args' => [self::class] + 'args' => [self::class], ]; $deprecation = new Deprecation('Deprecation by debug class loader', $trace, ''); From f0c3d51538c1ff34c963607847fd1bf4f773e652 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 19 Sep 2024 10:46:54 +0200 Subject: [PATCH 09/13] Only allow exact matches in expectUserDeprecationMessage() --- ExpectUserDeprecationMessageTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExpectUserDeprecationMessageTrait.php b/ExpectUserDeprecationMessageTrait.php index ede0bdb..ed94c84 100644 --- a/ExpectUserDeprecationMessageTrait.php +++ b/ExpectUserDeprecationMessageTrait.php @@ -20,7 +20,7 @@ trait ExpectUserDeprecationMessageTrait final protected function expectUserDeprecationMessage(string $expectedUserDeprecationMessage): void { - $this->expectDeprecation($expectedUserDeprecationMessage); + $this->expectDeprecation(str_replace('%', '%%', $expectedUserDeprecationMessage)); } } } else { From 676fcfa36435afb2f1a98a8bff46894cc4370ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 8 Oct 2024 16:40:20 +0200 Subject: [PATCH 10/13] [PhpUnitBridge] Use 'total' for asserting deprecation count when a group is not defined --- CHANGELOG.md | 1 + DeprecationErrorHandler/Configuration.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d28ee0c..a2dc7bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add `ExpectUserDeprecationMessageTrait` with a polyfill of PHPUnit's `expectUserDeprecationMessage()` + * Use `total` for asserting deprecation count when a group is not defined 6.4 --- diff --git a/DeprecationErrorHandler/Configuration.php b/DeprecationErrorHandler/Configuration.php index 32b120e..c984b73 100644 --- a/DeprecationErrorHandler/Configuration.php +++ b/DeprecationErrorHandler/Configuration.php @@ -96,7 +96,7 @@ private function __construct(array $thresholds = [], string $regex = '', array $ } foreach ($groups as $group) { if (!isset($this->thresholds[$group])) { - $this->thresholds[$group] = 999999; + $this->thresholds[$group] = $this->thresholds['total'] ?? 999999; } } $this->regex = $regex; From 2faee18aedff4c02af670992c5659f250e4cc544 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 15 Oct 2024 12:42:42 +0200 Subject: [PATCH 11/13] do not patch the TestCase class with PHPUnit 11+ The PHPUnit\TextUI\Command class was removed in PHPUnit 10. Since the sole purpose of the class extended the base Command class is to register a the Symfony test listener we can completely stop patching it as support for the listener-based event system was also removed in PHPUnit 10. --- bin/simple-phpunit.php | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/bin/simple-phpunit.php b/bin/simple-phpunit.php index bd07a21..0472e8c 100644 --- a/bin/simple-phpunit.php +++ b/bin/simple-phpunit.php @@ -109,6 +109,11 @@ $PHPUNIT_VERSION = $MAX_PHPUNIT_VERSION; } +if (version_compare($PHPUNIT_VERSION, '10.0', '>=') && version_compare($PHPUNIT_VERSION, '11.0', '<')) { + fwrite(STDERR, 'This script does not work with PHPUnit 10.'.\PHP_EOL); + exit(1); +} + $PHPUNIT_REMOVE_RETURN_TYPEHINT = filter_var($getEnvVar('SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT', '0'), \FILTER_VALIDATE_BOOLEAN); $COMPOSER_JSON = getenv('COMPOSER') ?: 'composer.json'; @@ -143,7 +148,7 @@ } } -if ('disabled' === $getEnvVar('SYMFONY_DEPRECATIONS_HELPER')) { +if ('disabled' === $getEnvVar('SYMFONY_DEPRECATIONS_HELPER') || version_compare($PHPUNIT_VERSION, '11.0', '>=')) { putenv('SYMFONY_DEPRECATIONS_HELPER=disabled'); } @@ -273,19 +278,20 @@ } // Mutate TestCase code - $alteredCode = file_get_contents($alteredFile = './src/Framework/TestCase.php'); - if ($PHPUNIT_REMOVE_RETURN_TYPEHINT) { - $alteredCode = preg_replace('/^ ((?:protected|public)(?: static)? function \w+\(\)): void/m', ' $1', $alteredCode); - } - $alteredCode = preg_replace('/abstract class TestCase[^\{]+\{/', '$0 '.\PHP_EOL." use \Symfony\Bridge\PhpUnit\Legacy\PolyfillTestCaseTrait;", $alteredCode, 1); - file_put_contents($alteredFile, $alteredCode); + if (version_compare($PHPUNIT_VERSION, '11.0', '<')) { + $alteredCode = file_get_contents($alteredFile = './src/Framework/TestCase.php'); + if ($PHPUNIT_REMOVE_RETURN_TYPEHINT) { + $alteredCode = preg_replace('/^ ((?:protected|public)(?: static)? function \w+\(\)): void/m', ' $1', $alteredCode); + } + $alteredCode = preg_replace('/abstract class TestCase[^\{]+\{/', '$0 '.\PHP_EOL." use \Symfony\Bridge\PhpUnit\Legacy\PolyfillTestCaseTrait;", $alteredCode, 1); + file_put_contents($alteredFile, $alteredCode); - // Mutate Assert code - $alteredCode = file_get_contents($alteredFile = './src/Framework/Assert.php'); - $alteredCode = preg_replace('/abstract class Assert[^\{]+\{/', '$0 '.\PHP_EOL." use \Symfony\Bridge\PhpUnit\Legacy\PolyfillAssertTrait;", $alteredCode, 1); - file_put_contents($alteredFile, $alteredCode); + // Mutate Assert code + $alteredCode = file_get_contents($alteredFile = './src/Framework/Assert.php'); + $alteredCode = preg_replace('/abstract class Assert[^\{]+\{/', '$0 '.\PHP_EOL." use \Symfony\Bridge\PhpUnit\Legacy\PolyfillAssertTrait;", $alteredCode, 1); + file_put_contents($alteredFile, $alteredCode); - file_put_contents('phpunit', <<<'EOPHP' + file_put_contents('phpunit', <<<'EOPHP' Date: Thu, 3 Oct 2024 11:01:15 +0200 Subject: [PATCH 12/13] support ClockMock and DnsMock with PHPUnit 10+ --- CHANGELOG.md | 1 + Extension/DisableClockMockSubscriber.php | 39 +++ Extension/DisableDnsMockSubscriber.php | 39 +++ Extension/EnableClockMockSubscriber.php | 39 +++ Extension/RegisterClockMockSubscriber.php | 39 +++ Extension/RegisterDnsMockSubscriber.php | 39 +++ SymfonyExtension.php | 52 +++ Tests/CoverageListenerTest.php | 3 + .../ConfigurationTest.php | 3 + Tests/DeprecationErrorHandler/log_file.phpt | 2 + Tests/ExpectDeprecationTraitTest.php | 3 + Tests/ExpectedDeprecationAnnotationTest.php | 3 + .../ExpectDeprecationTraitTestFail.php | 2 + Tests/FailTests/NoAssertionsTestNotRisky.php | 2 + Tests/FailTests/NoAssertionsTestRisky.php | 2 + .../phpunit-with-extension.xml.dist | 29 ++ .../phpunit-without-extension.xml.dist | 22 ++ .../src/ClassExtendingFinalClass.php | 16 + .../symfonyextension/src/FinalClass.php | 19 ++ .../symfonyextension/tests/bootstrap.php | 34 ++ Tests/ProcessIsolationTest.php | 2 + Tests/SymfonyExtension.php | 140 +++++++++ Tests/expectdeprecationfail.phpt | 2 + Tests/expectnotrisky.phpt | 4 +- Tests/expectrisky.phpt | 4 +- Tests/symfonyextension.phpt | 19 ++ Tests/symfonyextensionnotregistered.phpt | 296 ++++++++++++++++++ 27 files changed, 853 insertions(+), 2 deletions(-) create mode 100644 Extension/DisableClockMockSubscriber.php create mode 100644 Extension/DisableDnsMockSubscriber.php create mode 100644 Extension/EnableClockMockSubscriber.php create mode 100644 Extension/RegisterClockMockSubscriber.php create mode 100644 Extension/RegisterDnsMockSubscriber.php create mode 100644 SymfonyExtension.php create mode 100644 Tests/Fixtures/symfonyextension/phpunit-with-extension.xml.dist create mode 100644 Tests/Fixtures/symfonyextension/phpunit-without-extension.xml.dist create mode 100644 Tests/Fixtures/symfonyextension/src/ClassExtendingFinalClass.php create mode 100644 Tests/Fixtures/symfonyextension/src/FinalClass.php create mode 100644 Tests/Fixtures/symfonyextension/tests/bootstrap.php create mode 100644 Tests/SymfonyExtension.php create mode 100644 Tests/symfonyextension.phpt create mode 100644 Tests/symfonyextensionnotregistered.phpt diff --git a/CHANGELOG.md b/CHANGELOG.md index a2dc7bd..3c74702 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 7.2 --- + * Add a PHPUnit extension that registers the clock mock and DNS mock and the `DebugClassLoader` from the ErrorHandler component if present * Add `ExpectUserDeprecationMessageTrait` with a polyfill of PHPUnit's `expectUserDeprecationMessage()` * Use `total` for asserting deprecation count when a group is not defined diff --git a/Extension/DisableClockMockSubscriber.php b/Extension/DisableClockMockSubscriber.php new file mode 100644 index 0000000..885e6ea --- /dev/null +++ b/Extension/DisableClockMockSubscriber.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Extension; + +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +use PHPUnit\Metadata\Group; +use Symfony\Bridge\PhpUnit\ClockMock; + +/** + * @internal + */ +class DisableClockMockSubscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $test = $event->test(); + + if (!$test instanceof TestMethod) { + return; + } + + foreach ($test->metadata() as $metadata) { + if ($metadata instanceof Group && 'time-sensitive' === $metadata->groupName()) { + ClockMock::withClockMock(false); + } + } + } +} diff --git a/Extension/DisableDnsMockSubscriber.php b/Extension/DisableDnsMockSubscriber.php new file mode 100644 index 0000000..fc3e754 --- /dev/null +++ b/Extension/DisableDnsMockSubscriber.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Extension; + +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; +use PHPUnit\Metadata\Group; +use Symfony\Bridge\PhpUnit\DnsMock; + +/** + * @internal + */ +class DisableDnsMockSubscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $test = $event->test(); + + if (!$test instanceof TestMethod) { + return; + } + + foreach ($test->metadata() as $metadata) { + if ($metadata instanceof Group && 'dns-sensitive' === $metadata->groupName()) { + DnsMock::withMockedHosts([]); + } + } + } +} diff --git a/Extension/EnableClockMockSubscriber.php b/Extension/EnableClockMockSubscriber.php new file mode 100644 index 0000000..c10c5dc --- /dev/null +++ b/Extension/EnableClockMockSubscriber.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Extension; + +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Test\PreparationStarted; +use PHPUnit\Event\Test\PreparationStartedSubscriber; +use PHPUnit\Metadata\Group; +use Symfony\Bridge\PhpUnit\ClockMock; + +/** + * @internal + */ +class EnableClockMockSubscriber implements PreparationStartedSubscriber +{ + public function notify(PreparationStarted $event): void + { + $test = $event->test(); + + if (!$test instanceof TestMethod) { + return; + } + + foreach ($test->metadata() as $metadata) { + if ($metadata instanceof Group && 'time-sensitive' === $metadata->groupName()) { + ClockMock::withClockMock(true); + } + } + } +} diff --git a/Extension/RegisterClockMockSubscriber.php b/Extension/RegisterClockMockSubscriber.php new file mode 100644 index 0000000..e2955fe --- /dev/null +++ b/Extension/RegisterClockMockSubscriber.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Extension; + +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\TestSuite\Loaded; +use PHPUnit\Event\TestSuite\LoadedSubscriber; +use PHPUnit\Metadata\Group; +use Symfony\Bridge\PhpUnit\ClockMock; + +/** + * @internal + */ +class RegisterClockMockSubscriber implements LoadedSubscriber +{ + public function notify(Loaded $event): void + { + foreach ($event->testSuite()->tests() as $test) { + if (!$test instanceof TestMethod) { + continue; + } + + foreach ($test->metadata() as $metadata) { + if ($metadata instanceof Group && 'time-sensitive' === $metadata->groupName()) { + ClockMock::register($test->className()); + } + } + } + } +} diff --git a/Extension/RegisterDnsMockSubscriber.php b/Extension/RegisterDnsMockSubscriber.php new file mode 100644 index 0000000..81382d5 --- /dev/null +++ b/Extension/RegisterDnsMockSubscriber.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Extension; + +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\TestSuite\Loaded; +use PHPUnit\Event\TestSuite\LoadedSubscriber; +use PHPUnit\Metadata\Group; +use Symfony\Bridge\PhpUnit\DnsMock; + +/** + * @internal + */ +class RegisterDnsMockSubscriber implements LoadedSubscriber +{ + public function notify(Loaded $event): void + { + foreach ($event->testSuite()->tests() as $test) { + if (!$test instanceof TestMethod) { + continue; + } + + foreach ($test->metadata() as $metadata) { + if ($metadata instanceof Group && 'dns-sensitive' === $metadata->groupName()) { + DnsMock::register($test->className()); + } + } + } + } +} diff --git a/SymfonyExtension.php b/SymfonyExtension.php new file mode 100644 index 0000000..1df4f20 --- /dev/null +++ b/SymfonyExtension.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; +use Symfony\Bridge\PhpUnit\Extension\DisableClockMockSubscriber; +use Symfony\Bridge\PhpUnit\Extension\DisableDnsMockSubscriber; +use Symfony\Bridge\PhpUnit\Extension\EnableClockMockSubscriber; +use Symfony\Bridge\PhpUnit\Extension\RegisterClockMockSubscriber; +use Symfony\Bridge\PhpUnit\Extension\RegisterDnsMockSubscriber; +use Symfony\Component\ErrorHandler\DebugClassLoader; + +class SymfonyExtension implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + if (class_exists(DebugClassLoader::class)) { + DebugClassLoader::enable(); + } + + if ($parameters->has('clock-mock-namespaces')) { + foreach (explode(',', $parameters->get('clock-mock-namespaces')) as $namespace) { + ClockMock::register($namespace.'\DummyClass'); + } + } + + $facade->registerSubscriber(new RegisterClockMockSubscriber()); + $facade->registerSubscriber(new EnableClockMockSubscriber()); + $facade->registerSubscriber(new DisableClockMockSubscriber()); + + if ($parameters->has('dns-mock-namespaces')) { + foreach (explode(',', $parameters->get('dns-mock-namespaces')) as $namespace) { + DnsMock::register($namespace.'\DummyClass'); + } + } + + $facade->registerSubscriber(new RegisterDnsMockSubscriber()); + $facade->registerSubscriber(new DisableDnsMockSubscriber()); + } +} diff --git a/Tests/CoverageListenerTest.php b/Tests/CoverageListenerTest.php index 22f3565..99d4a4b 100644 --- a/Tests/CoverageListenerTest.php +++ b/Tests/CoverageListenerTest.php @@ -13,6 +13,9 @@ use PHPUnit\Framework\TestCase; +/** + * @requires PHPUnit < 10 + */ class CoverageListenerTest extends TestCase { public function test() diff --git a/Tests/DeprecationErrorHandler/ConfigurationTest.php b/Tests/DeprecationErrorHandler/ConfigurationTest.php index 5bbf714..7eec029 100644 --- a/Tests/DeprecationErrorHandler/ConfigurationTest.php +++ b/Tests/DeprecationErrorHandler/ConfigurationTest.php @@ -463,6 +463,9 @@ public function testExistingBaselineAndGeneration() $this->assertEquals(json_encode($expected, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES), file_get_contents($filename)); } + /** + * @requires PHPUnit < 10 + */ public function testBaselineGenerationWithDeprecationTriggeredByDebugClassLoader() { $filename = $this->createFile(); diff --git a/Tests/DeprecationErrorHandler/log_file.phpt b/Tests/DeprecationErrorHandler/log_file.phpt index 0a64337..fe14db7 100644 --- a/Tests/DeprecationErrorHandler/log_file.phpt +++ b/Tests/DeprecationErrorHandler/log_file.phpt @@ -1,5 +1,7 @@ --TEST-- Test DeprecationErrorHandler with log file +--SKIPIF-- +=')) die('Skipping on PHPUnit 10+'); --FILE-- + + + + tests + + + + + + src + + + + + + + + + + diff --git a/Tests/Fixtures/symfonyextension/phpunit-without-extension.xml.dist b/Tests/Fixtures/symfonyextension/phpunit-without-extension.xml.dist new file mode 100644 index 0000000..843be2f --- /dev/null +++ b/Tests/Fixtures/symfonyextension/phpunit-without-extension.xml.dist @@ -0,0 +1,22 @@ + + + + + tests + + + + + + src + + + diff --git a/Tests/Fixtures/symfonyextension/src/ClassExtendingFinalClass.php b/Tests/Fixtures/symfonyextension/src/ClassExtendingFinalClass.php new file mode 100644 index 0000000..e3377aa --- /dev/null +++ b/Tests/Fixtures/symfonyextension/src/ClassExtendingFinalClass.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Tests\Fixtures\symfonyextension\src; + +class ClassExtendingFinalClass extends FinalClass +{ +} diff --git a/Tests/Fixtures/symfonyextension/src/FinalClass.php b/Tests/Fixtures/symfonyextension/src/FinalClass.php new file mode 100644 index 0000000..8a320dd --- /dev/null +++ b/Tests/Fixtures/symfonyextension/src/FinalClass.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Tests\Fixtures\symfonyextension\src; + +/** + * @final + */ +class FinalClass +{ +} diff --git a/Tests/Fixtures/symfonyextension/tests/bootstrap.php b/Tests/Fixtures/symfonyextension/tests/bootstrap.php new file mode 100644 index 0000000..95dcc78 --- /dev/null +++ b/Tests/Fixtures/symfonyextension/tests/bootstrap.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bridge\PhpUnit\Tests\Fixtures\symfonyextension\src\ClassExtendingFinalClass; +use Symfony\Bridge\PhpUnit\Tests\Fixtures\symfonyextension\src\FinalClass; + +spl_autoload_register(function ($class) { + if (FinalClass::class === $class) { + require __DIR__.'/../src/FinalClass.php'; + } elseif (ClassExtendingFinalClass::class === $class) { + require __DIR__.'/../src/ClassExtendingFinalClass.php'; + } +}); + +require __DIR__.'/../../../../SymfonyExtension.php'; +require __DIR__.'/../../../../Extension/DisableClockMockSubscriber.php'; +require __DIR__.'/../../../../Extension/DisableDnsMockSubscriber.php'; +require __DIR__.'/../../../../Extension/EnableClockMockSubscriber.php'; +require __DIR__.'/../../../../Extension/RegisterClockMockSubscriber.php'; +require __DIR__.'/../../../../Extension/RegisterDnsMockSubscriber.php'; + +if (file_exists(__DIR__.'/../../../../vendor/autoload.php')) { + require __DIR__.'/../../../../vendor/autoload.php'; +} elseif (file_exists(__DIR__.'/../../../..//../../../../vendor/autoload.php')) { + require __DIR__.'/../../../../../../../../vendor/autoload.php'; +} diff --git a/Tests/ProcessIsolationTest.php b/Tests/ProcessIsolationTest.php index 04bf6ec..07fb9a2 100644 --- a/Tests/ProcessIsolationTest.php +++ b/Tests/ProcessIsolationTest.php @@ -19,6 +19,8 @@ * @group legacy * * @runTestsInSeparateProcesses + * + * @requires PHPUnit < 10 */ class ProcessIsolationTest extends TestCase { diff --git a/Tests/SymfonyExtension.php b/Tests/SymfonyExtension.php new file mode 100644 index 0000000..ac2d907 --- /dev/null +++ b/Tests/SymfonyExtension.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Tests; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\Tests\Fixtures\symfonyextension\src\ClassExtendingFinalClass; +use Symfony\Bridge\PhpUnit\Tests\Fixtures\symfonyextension\src\FinalClass; + +class SymfonyExtension extends TestCase +{ + public function testExtensionOfFinalClass() + { + $this->expectUserDeprecationMessage(\sprintf('The "%s" class is considered final. It may change without further notice as of its next major version. You should not extend it from "%s".', FinalClass::class, ClassExtendingFinalClass::class)); + + new ClassExtendingFinalClass(); + } + + #[DataProvider('mockedNamespaces')] + #[Group('time-sensitive')] + public function testTimeMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\time', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('time-sensitive')] + public function testMicrotimeMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\microtime', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('time-sensitive')] + public function testSleepMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\sleep', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('time-sensitive')] + public function testUsleepMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\usleep', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('time-sensitive')] + public function testDateMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\date', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('time-sensitive')] + public function testGmdateMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\gmdate', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('time-sensitive')] + public function testHrtimeMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\hrtime', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testCheckdnsrrMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\checkdnsrr', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testDnsCheckRecordMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\dns_check_record', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testGetmxrrMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\getmxrr', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testDnsGetMxMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\dns_get_mx', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testGethostbyaddrMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\gethostbyaddr', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testGethostbynameMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\gethostbyname', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testGethostbynamelMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\gethostbynamel', $namespace))); + } + + #[DataProvider('mockedNamespaces')] + #[Group('dns-sensitive')] + public function testDnsGetRecordMockIsRegistered(string $namespace) + { + $this->assertTrue(\function_exists(\sprintf('%s\dns_get_record', $namespace))); + } + + public static function mockedNamespaces(): iterable + { + yield 'test class namespace' => [__NAMESPACE__]; + yield 'namespace derived from test namespace' => ['Symfony\Bridge\PhpUnit']; + yield 'explicitly configured namespace' => ['App']; + } +} diff --git a/Tests/expectdeprecationfail.phpt b/Tests/expectdeprecationfail.phpt index f968cd1..6181146 100644 --- a/Tests/expectdeprecationfail.phpt +++ b/Tests/expectdeprecationfail.phpt @@ -1,5 +1,7 @@ --TEST-- Test ExpectDeprecationTrait failing tests +--SKIPIF-- +=')) die('Skipping on PHPUnit 10+'); --FILE-- =')) die('Skipping on PHPUnit 10+'); --FILE-- =')) die('Skipping on PHPUnit 10+'); --FILE-- Date: Sun, 27 Oct 2024 07:46:44 +0100 Subject: [PATCH 13/13] Don't use `die()` in PHPT `--SKIPIF--` Unlocks a performance optimization in PHPUnit 11.x see https://staabm.github.io/2024/10/19/phpunit-codesprint-munich.html --- Tests/DeprecationErrorHandler/log_file.phpt | 2 +- Tests/expectdeprecationfail.phpt | 2 +- Tests/expectnotrisky.phpt | 4 ++-- Tests/expectrisky.phpt | 4 ++-- Tests/symfonyextension.phpt | 2 +- Tests/symfonyextensionnotregistered.phpt | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Tests/DeprecationErrorHandler/log_file.phpt b/Tests/DeprecationErrorHandler/log_file.phpt index fe14db7..12f9ed4 100644 --- a/Tests/DeprecationErrorHandler/log_file.phpt +++ b/Tests/DeprecationErrorHandler/log_file.phpt @@ -1,7 +1,7 @@ --TEST-- Test DeprecationErrorHandler with log file --SKIPIF-- -=')) die('Skipping on PHPUnit 10+'); +=')) echo 'Skipping on PHPUnit 10+'; --FILE-- =')) die('Skipping on PHPUnit 10+'); +=')) echo 'Skipping on PHPUnit 10+'; --FILE-- =')) die('Skipping on PHPUnit 10+'); +if ('\\' === DIRECTORY_SEPARATOR && !extension_loaded('mbstring')) echo 'Skipping on Windows without mbstring'; +if (!getenv('SYMFONY_PHPUNIT_VERSION') || version_compare(getenv('SYMFONY_PHPUNIT_VERSION'), '10.0', '>=')) echo 'Skipping on PHPUnit 10+'; --FILE-- =')) die('Skipping on PHPUnit 10+'); +if ('\\' === DIRECTORY_SEPARATOR && !extension_loaded('mbstring')) echo 'Skipping on Windows without mbstring'; +if (!getenv('SYMFONY_PHPUNIT_VERSION') || version_compare(getenv('SYMFONY_PHPUNIT_VERSION'), '10.0', '>=')) echo 'Skipping on PHPUnit 10+'; --FILE-- pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy