Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Symfony/Bridge/PhpUnit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.1
---

* Add option `ignoreFile` to configure a file that lists deprecation messages to ignore

6.0
---

Expand Down
3 changes: 3 additions & 0 deletions src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ public function handleError($type, $msg, $file, $line, $context = [])
if ($deprecation->isMuted()) {
return null;
}
if ($this->getConfiguration()->isIgnoredDeprecation($deprecation)) {
return null;
}
if ($this->getConfiguration()->isBaselineDeprecation($deprecation)) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ class Configuration
*/
private $verboseOutput;

/**
* @var string[]
*/
private $ignoreDeprecationPatterns = [];

/**
* @var bool
*/
Expand All @@ -60,11 +65,12 @@ class Configuration
* @param int[] $thresholds A hash associating groups to thresholds
* @param string $regex Will be matched against messages, to decide whether to display a stack trace
* @param bool[] $verboseOutput Keyed by groups
* @param string $ignoreFile The path to the ignore deprecation patterns file
* @param bool $generateBaseline Whether to generate or update the baseline file
* @param string $baselineFile The path to the baseline file
* @param string|null $logFile The path to the log file
*/
private function __construct(array $thresholds = [], $regex = '', $verboseOutput = [], $generateBaseline = false, $baselineFile = '', $logFile = null)
private function __construct(array $thresholds = [], $regex = '', $verboseOutput = [], $ignoreFile = '', $generateBaseline = false, $baselineFile = '', $logFile = null)
{
$groups = ['total', 'indirect', 'direct', 'self'];

Expand Down Expand Up @@ -110,6 +116,25 @@ private function __construct(array $thresholds = [], $regex = '', $verboseOutput
$this->verboseOutput[$group] = $status;
}

if ($ignoreFile) {
if (!is_file($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));
});
try {
foreach (file($ignoreFile) as $line => $pattern) {
if ('#' !== trim($line)[0] ?? '#') {
preg_match($pattern, '');
$this->ignoreDeprecationPatterns[] = $pattern;
}
}
} finally {
restore_error_handler();
}
}

if ($generateBaseline && !$baselineFile) {
throw new \InvalidArgumentException('You cannot use the "generateBaseline" configuration option without providing a "baselineFile" configuration option.');
}
Expand Down Expand Up @@ -165,6 +190,19 @@ public function tolerates(array $deprecationGroups)
return true;
}

public function isIgnoredDeprecation(Deprecation $deprecation): bool
{
if (!$this->ignoreDeprecationPatterns) {
return false;
}
$result = @preg_filter($this->ignoreDeprecationPatterns, '$0', $deprecation->getMessage());
if (\PREG_NO_ERROR !== preg_last_error()) {
throw new \RuntimeException(preg_last_error_msg());
}

return (bool) $result;
}

/**
* @return bool
*/
Expand Down Expand Up @@ -266,7 +304,7 @@ public static function fromUrlEncodedString($serializedConfiguration)
{
parse_str($serializedConfiguration, $normalizedConfiguration);
foreach (array_keys($normalizedConfiguration) as $key) {
if (!\in_array($key, ['max', 'disabled', 'verbose', 'quiet', 'generateBaseline', 'baselineFile', 'logFile'], true)) {
if (!\in_array($key, ['max', 'disabled', 'verbose', 'quiet', 'ignoreFile', 'generateBaseline', 'baselineFile', 'logFile'], true)) {
throw new \InvalidArgumentException(sprintf('Unknown configuration option "%s".', $key));
}
}
Expand All @@ -276,6 +314,7 @@ public static function fromUrlEncodedString($serializedConfiguration)
'disabled' => false,
'verbose' => true,
'quiet' => [],
'ignoreFile' => '',
'generateBaseline' => false,
'baselineFile' => '',
'logFile' => null,
Expand All @@ -300,6 +339,7 @@ public static function fromUrlEncodedString($serializedConfiguration)
$normalizedConfiguration['max'] ?? [],
'',
$verboseOutput,
$normalizedConfiguration['ignoreFile'],
filter_var($normalizedConfiguration['generateBaseline'], \FILTER_VALIDATE_BOOLEAN),
$normalizedConfiguration['baselineFile'],
$normalizedConfiguration['logFile']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,62 @@ public function testBaselineFileWriteError()
$configuration->writeBaseline();
}

public function testExistingIgnoreFile()
{
$filename = $this->createFile();
$ignorePatterns = [
'/Test message .*/',
'/^\d* occurrences/',
];
file_put_contents($filename, implode("\n", $ignorePatterns));

$configuration = Configuration::fromUrlEncodedString('ignoreFile='.urlencode($filename));
$trace = debug_backtrace();
$this->assertTrue($configuration->isIgnoredDeprecation(new Deprecation('Test message 1', $trace, '')));
$this->assertTrue($configuration->isIgnoredDeprecation(new Deprecation('Test message 2', $trace, '')));
$this->assertFalse($configuration->isIgnoredDeprecation(new Deprecation('Test mexxage 3', $trace, '')));
$this->assertTrue($configuration->isIgnoredDeprecation(new Deprecation('1 occurrences', $trace, '')));
$this->assertTrue($configuration->isIgnoredDeprecation(new Deprecation('1200 occurrences and more', $trace, '')));
$this->assertFalse($configuration->isIgnoredDeprecation(new Deprecation('Many occurrences', $trace, '')));
}

public function testIgnoreFilePatternInvalid()
{
$filename = $this->createFile();
$ignorePatterns = [
'/Test message (.*/',
];
file_put_contents($filename, implode("\n", $ignorePatterns));

$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('missing closing parenthesis');
$configuration = Configuration::fromUrlEncodedString('ignoreFile='.urlencode($filename));
}

public function testIgnoreFilePatternException()
{
$filename = $this->createFile();
$ignorePatterns = [
'/(?:\D+|<\d+>)*[!?]/',
];
file_put_contents($filename, implode("\n", $ignorePatterns));

$configuration = Configuration::fromUrlEncodedString('ignoreFile='.urlencode($filename));
$trace = debug_backtrace();
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessageMatches('/[Bb]acktrack limit exhausted/');
$configuration->isIgnoredDeprecation(new Deprecation('foobar foobar foobar', $trace, ''));
}

public function testIgnoreFileException()
{
$filename = $this->createFile();
unlink($filename);
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf('The ignoreFile "%s" does not exist.', $filename));
Configuration::fromUrlEncodedString('ignoreFile='.urlencode($filename));
}

protected function setUp(): void
{
$this->files = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
--TEST--
Test DeprecationErrorHandler with an ignoreFile
--FILE--
<?php
$filename = tempnam(sys_get_temp_dir(), 'sf-');
$ignorePatterns = [
'/^ignored .* deprecation/',
];
file_put_contents($filename, implode("\n", $ignorePatterns));

$k = 'SYMFONY_DEPRECATIONS_HELPER';
unset($_SERVER[$k], $_ENV[$k]);
putenv($k.'='.$_SERVER[$k] = $_ENV[$k] = 'ignoreFile=' . urlencode($filename));
putenv('ANSICON');
putenv('ConEmuANSI');
putenv('TERM');

$vendor = __DIR__;
while (!file_exists($vendor.'/vendor')) {
$vendor = dirname($vendor);
}
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
require_once __DIR__.'/../../bootstrap.php';

@trigger_error('root deprecation', E_USER_DEPRECATED);
@trigger_error('ignored root deprecation', E_USER_DEPRECATED);

eval(<<<'EOPHP'
namespace PHPUnit\Util;

class Test
{
public static function getGroups()
{
return array();
}
}
EOPHP
);

class PHPUnit_Util_Test
{
public static function getGroups()
{
return array();
}
}

class FooTestCase
{
public function testLegacyFoo()
{
@trigger_error('ignored foo deprecation', E_USER_DEPRECATED);
@trigger_error('not ignored foo deprecation', E_USER_DEPRECATED);
}

public function testNonLegacyBar()
{
@trigger_error('ignored bar deprecation', E_USER_DEPRECATED);
@trigger_error('not ignored bar deprecation', E_USER_DEPRECATED);
}
}

$foo = new FooTestCase();
$foo->testLegacyFoo();
$foo->testNonLegacyBar();
?>
--EXPECTF--
Legacy deprecation notices (1)

Other deprecation notices (2)

1x: root deprecation

1x: not ignored bar deprecation
1x in FooTestCase::testNonLegacyBar