feature #35271 [PHPUnitBridge] Improved deprecations display (greg0ire)
This PR was squashed before being merged into the 5.1-dev branch (closes #35271).
Discussion
----------
[PHPUnitBridge] Improved deprecations display
| Q | A
| ------------- | ---
| Branch? | master for features
| Bug fix? | no
| New feature? | yes <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets | n/a
| License | MIT
| Doc PR | todo
- [x] Ignore verbose when the build fails because of deprecations
- [x] Add per-group verbosity : it is now possible to make the report a lot quieter, by specifying which groups should become quiet, like this: `quiet[]=indirect&quiet[]=direct`
Might add more improvements to that branch if people suggest some.
Commits
-------
c55a89e4ff
[PHPUnitBridge] Improved deprecations display
This commit is contained in:
commit
7ecb5aad8e
@ -1,6 +1,12 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
5.1.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
* ignore verbosity settings when the build fails because of deprecations
|
||||||
|
* added per-group verbosity
|
||||||
|
|
||||||
5.0.0
|
5.0.0
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ use PHPUnit\Framework\TestResult;
|
|||||||
use PHPUnit\Util\ErrorHandler;
|
use PHPUnit\Util\ErrorHandler;
|
||||||
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration;
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration;
|
||||||
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
|
||||||
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\DeprecationGroup;
|
||||||
use Symfony\Component\ErrorHandler\DebugClassLoader;
|
use Symfony\Component\ErrorHandler\DebugClassLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,24 +31,20 @@ class DeprecationErrorHandler
|
|||||||
|
|
||||||
private $mode;
|
private $mode;
|
||||||
private $configuration;
|
private $configuration;
|
||||||
private $deprecations = [
|
|
||||||
'unsilencedCount' => 0,
|
/**
|
||||||
'remaining selfCount' => 0,
|
* @var DeprecationGroup[]
|
||||||
'legacyCount' => 0,
|
*/
|
||||||
'otherCount' => 0,
|
private $deprecationGroups = [];
|
||||||
'remaining directCount' => 0,
|
|
||||||
'remaining indirectCount' => 0,
|
|
||||||
'unsilenced' => [],
|
|
||||||
'remaining self' => [],
|
|
||||||
'legacy' => [],
|
|
||||||
'other' => [],
|
|
||||||
'remaining direct' => [],
|
|
||||||
'remaining indirect' => [],
|
|
||||||
];
|
|
||||||
|
|
||||||
private static $isRegistered = false;
|
private static $isRegistered = false;
|
||||||
private static $isAtLeastPhpUnit83;
|
private static $isAtLeastPhpUnit83;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->resetDeprecationGroups();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers and configures the deprecation handler.
|
* Registers and configures the deprecation handler.
|
||||||
*
|
*
|
||||||
@ -135,9 +132,9 @@ class DeprecationErrorHandler
|
|||||||
$group = 'legacy';
|
$group = 'legacy';
|
||||||
} else {
|
} else {
|
||||||
$group = [
|
$group = [
|
||||||
Deprecation::TYPE_SELF => 'remaining self',
|
Deprecation::TYPE_SELF => 'self',
|
||||||
Deprecation::TYPE_DIRECT => 'remaining direct',
|
Deprecation::TYPE_DIRECT => 'direct',
|
||||||
Deprecation::TYPE_INDIRECT => 'remaining indirect',
|
Deprecation::TYPE_INDIRECT => 'indirect',
|
||||||
Deprecation::TYPE_UNDETERMINED => 'other',
|
Deprecation::TYPE_UNDETERMINED => 'other',
|
||||||
][$deprecation->getType()];
|
][$deprecation->getType()];
|
||||||
}
|
}
|
||||||
@ -148,18 +145,14 @@ class DeprecationErrorHandler
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if ('legacy' !== $group) {
|
if ('legacy' !== $group) {
|
||||||
$ref = &$this->deprecations[$group][$msg]['count'];
|
$this->deprecationGroups[$group]->addNoticeFromObject($msg, $class, $method);
|
||||||
++$ref;
|
} else {
|
||||||
$ref = &$this->deprecations[$group][$msg][$class.'::'.$method];
|
$this->deprecationGroups[$group]->addNotice();
|
||||||
++$ref;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$ref = &$this->deprecations[$group][$msg]['count'];
|
$this->deprecationGroups[$group]->addNoticeFromProceduralCode($msg);
|
||||||
++$ref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++$this->deprecations[$group.'Count'];
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,34 +177,44 @@ class DeprecationErrorHandler
|
|||||||
echo "\n", self::colorize('THE ERROR HANDLER HAS CHANGED!', true), "\n";
|
echo "\n", self::colorize('THE ERROR HANDLER HAS CHANGED!', true), "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
$groups = ['unsilenced', 'remaining self', 'remaining direct', 'remaining indirect', 'legacy', 'other'];
|
$groups = array_keys($this->deprecationGroups);
|
||||||
|
|
||||||
$this->displayDeprecations($groups, $configuration);
|
|
||||||
|
|
||||||
// store failing status
|
// store failing status
|
||||||
$isFailing = !$configuration->tolerates($this->deprecations);
|
$isFailing = !$configuration->tolerates($this->deprecationGroups);
|
||||||
|
|
||||||
// reset deprecations array
|
$this->displayDeprecations($groups, $configuration, $isFailing);
|
||||||
foreach ($this->deprecations as $group => $arrayOrInt) {
|
|
||||||
$this->deprecations[$group] = \is_int($arrayOrInt) ? 0 : [];
|
$this->resetDeprecationGroups();
|
||||||
}
|
|
||||||
|
|
||||||
register_shutdown_function(function () use ($isFailing, $groups, $configuration) {
|
register_shutdown_function(function () use ($isFailing, $groups, $configuration) {
|
||||||
foreach ($this->deprecations as $group => $arrayOrInt) {
|
foreach ($this->deprecationGroups as $group) {
|
||||||
if (0 < (\is_int($arrayOrInt) ? $arrayOrInt : \count($arrayOrInt))) {
|
if ($group->count() > 0) {
|
||||||
echo "Shutdown-time deprecations:\n";
|
echo "Shutdown-time deprecations:\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->displayDeprecations($groups, $configuration);
|
$isFailingAtShutdown = !$configuration->tolerates($this->deprecationGroups);
|
||||||
|
$this->displayDeprecations($groups, $configuration, $isFailingAtShutdown);
|
||||||
|
|
||||||
if ($isFailing || !$configuration->tolerates($this->deprecations)) {
|
if ($isFailing || $isFailingAtShutdown) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function resetDeprecationGroups()
|
||||||
|
{
|
||||||
|
$this->deprecationGroups = [
|
||||||
|
'unsilenced' => new DeprecationGroup(),
|
||||||
|
'self' => new DeprecationGroup(),
|
||||||
|
'direct' => new DeprecationGroup(),
|
||||||
|
'indirect' => new DeprecationGroup(),
|
||||||
|
'legacy' => new DeprecationGroup(),
|
||||||
|
'other' => new DeprecationGroup(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
private function getConfiguration()
|
private function getConfiguration()
|
||||||
{
|
{
|
||||||
if (null !== $this->configuration) {
|
if (null !== $this->configuration) {
|
||||||
@ -270,31 +273,38 @@ class DeprecationErrorHandler
|
|||||||
/**
|
/**
|
||||||
* @param string[] $groups
|
* @param string[] $groups
|
||||||
* @param Configuration $configuration
|
* @param Configuration $configuration
|
||||||
|
* @param bool $isFailing
|
||||||
*/
|
*/
|
||||||
private function displayDeprecations($groups, $configuration)
|
private function displayDeprecations($groups, $configuration, $isFailing)
|
||||||
{
|
{
|
||||||
$cmp = function ($a, $b) {
|
$cmp = function ($a, $b) {
|
||||||
return $b['count'] - $a['count'];
|
return $b->count() - $a->count();
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach ($groups as $group) {
|
foreach ($groups as $group) {
|
||||||
if ($this->deprecations[$group.'Count']) {
|
if ($this->deprecationGroups[$group]->count()) {
|
||||||
echo "\n", self::colorize(
|
echo "\n", self::colorize(
|
||||||
sprintf('%s deprecation notices (%d)', ucfirst($group), $this->deprecations[$group.'Count']),
|
sprintf(
|
||||||
'legacy' !== $group && 'remaining indirect' !== $group
|
'%s deprecation notices (%d)',
|
||||||
|
\in_array($group, ['direct', 'indirect', 'self'], true) ? "Remaining $group" : ucfirst($group),
|
||||||
|
$this->deprecationGroups[$group]->count()
|
||||||
|
),
|
||||||
|
'legacy' !== $group && 'indirect' !== $group
|
||||||
), "\n";
|
), "\n";
|
||||||
|
|
||||||
if (!$configuration->verboseOutput()) {
|
if ('legacy' !== $group && !$configuration->verboseOutput($group) && !$isFailing) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uasort($this->deprecations[$group], $cmp);
|
$notices = $this->deprecationGroups[$group]->notices();
|
||||||
|
uasort($notices, $cmp);
|
||||||
|
|
||||||
foreach ($this->deprecations[$group] as $msg => $notices) {
|
foreach ($notices as $msg => $notice) {
|
||||||
echo "\n ", $notices['count'], 'x: ', $msg, "\n";
|
echo "\n ", $notice->count(), 'x: ', $msg, "\n";
|
||||||
|
|
||||||
arsort($notices);
|
$countsByCaller = $notice->getCountsByCaller();
|
||||||
|
arsort($countsByCaller);
|
||||||
|
|
||||||
foreach ($notices as $method => $count) {
|
foreach ($countsByCaller as $method => $count) {
|
||||||
if ('count' !== $method) {
|
if ('count' !== $method) {
|
||||||
echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n";
|
echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n";
|
||||||
}
|
}
|
||||||
|
@ -32,17 +32,17 @@ class Configuration
|
|||||||
private $enabled = true;
|
private $enabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool[]
|
||||||
*/
|
*/
|
||||||
private $verboseOutput = true;
|
private $verboseOutput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int[] $thresholds A hash associating groups to thresholds
|
* @param int[] $thresholds A hash associating groups to thresholds
|
||||||
* @param string $regex Will be matched against messages, to decide
|
* @param string $regex Will be matched against messages, to decide
|
||||||
* whether to display a stack trace
|
* whether to display a stack trace
|
||||||
* @param bool $verboseOutput
|
* @param bool[] $verboseOutput Keyed by groups
|
||||||
*/
|
*/
|
||||||
private function __construct(array $thresholds = [], $regex = '', $verboseOutput = true)
|
private function __construct(array $thresholds = [], $regex = '', $verboseOutput = [])
|
||||||
{
|
{
|
||||||
$groups = ['total', 'indirect', 'direct', 'self'];
|
$groups = ['total', 'indirect', 'direct', 'self'];
|
||||||
|
|
||||||
@ -72,7 +72,21 @@ class Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->regex = $regex;
|
$this->regex = $regex;
|
||||||
$this->verboseOutput = $verboseOutput;
|
|
||||||
|
$this->verboseOutput = [
|
||||||
|
'unsilenced' => true,
|
||||||
|
'direct' => true,
|
||||||
|
'indirect' => true,
|
||||||
|
'self' => true,
|
||||||
|
'other' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
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))));
|
||||||
|
}
|
||||||
|
$this->verboseOutput[$group] = (bool) $status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,24 +98,26 @@ class Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mixed[] $deprecations
|
* @param DeprecationGroup[] $deprecationGroups
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function tolerates(array $deprecations)
|
public function tolerates(array $deprecationGroups)
|
||||||
{
|
{
|
||||||
$deprecationCounts = [];
|
$grandTotal = 0;
|
||||||
foreach ($deprecations as $key => $deprecation) {
|
|
||||||
if (false !== strpos($key, 'Count') && false === strpos($key, 'legacy')) {
|
foreach ($deprecationGroups as $name => $group) {
|
||||||
$deprecationCounts[$key] = $deprecation;
|
if ('legacy' !== $name) {
|
||||||
|
$grandTotal += $group->count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_sum($deprecationCounts) > $this->thresholds['total']) {
|
if ($grandTotal > $this->thresholds['total']) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (['self', 'direct', 'indirect'] as $deprecationType) {
|
foreach (['self', 'direct', 'indirect'] as $deprecationType) {
|
||||||
if ($deprecationCounts['remaining '.$deprecationType.'Count'] > $this->thresholds[$deprecationType]) {
|
if ($deprecationGroups[$deprecationType]->count() > $this->thresholds[$deprecationType]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,9 +146,9 @@ class Configuration
|
|||||||
/**
|
/**
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function verboseOutput()
|
public function verboseOutput($group)
|
||||||
{
|
{
|
||||||
return $this->verboseOutput;
|
return $this->verboseOutput[$group];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,7 +161,7 @@ class Configuration
|
|||||||
{
|
{
|
||||||
parse_str($serializedConfiguration, $normalizedConfiguration);
|
parse_str($serializedConfiguration, $normalizedConfiguration);
|
||||||
foreach (array_keys($normalizedConfiguration) as $key) {
|
foreach (array_keys($normalizedConfiguration) as $key) {
|
||||||
if (!\in_array($key, ['max', 'disabled', 'verbose'], true)) {
|
if (!\in_array($key, ['max', 'disabled', 'verbose', 'quiet'], true)) {
|
||||||
throw new \InvalidArgumentException(sprintf('Unknown configuration option "%s"', $key));
|
throw new \InvalidArgumentException(sprintf('Unknown configuration option "%s"', $key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,9 +170,19 @@ class Configuration
|
|||||||
return self::inDisabledMode();
|
return self::inDisabledMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
$verboseOutput = true;
|
$verboseOutput = [];
|
||||||
if (isset($normalizedConfiguration['verbose'])) {
|
if (!isset($normalizedConfiguration['verbose'])) {
|
||||||
$verboseOutput = (bool) $normalizedConfiguration['verbose'];
|
$normalizedConfiguration['verbose'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (['unsilenced', 'direct', 'indirect', 'self', 'other'] as $group) {
|
||||||
|
$verboseOutput[$group] = (bool) $normalizedConfiguration['verbose'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($normalizedConfiguration['quiet']) && \is_array($normalizedConfiguration['quiet'])) {
|
||||||
|
foreach ($normalizedConfiguration['quiet'] as $shushedGroup) {
|
||||||
|
$verboseOutput[$shushedGroup] = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new self(
|
return new self(
|
||||||
@ -190,7 +216,12 @@ class Configuration
|
|||||||
*/
|
*/
|
||||||
public static function inWeakMode()
|
public static function inWeakMode()
|
||||||
{
|
{
|
||||||
return new self([], '', false);
|
$verboseOutput = [];
|
||||||
|
foreach (['unsilenced', 'direct', 'indirect', 'self', 'other'] as $group) {
|
||||||
|
$verboseOutput[$group] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self([], '', $verboseOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
<?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\DeprecationErrorHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class DeprecationGroup
|
||||||
|
{
|
||||||
|
private $count = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var DeprecationNotice[] keys are messages
|
||||||
|
*/
|
||||||
|
private $deprecationNotices = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $message
|
||||||
|
* @param string $class
|
||||||
|
* @param string $method
|
||||||
|
*/
|
||||||
|
public function addNoticeFromObject($message, $class, $method)
|
||||||
|
{
|
||||||
|
$this->deprecationNotice($message)->addObjectOccurence($class, $method);
|
||||||
|
$this->addNotice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $message
|
||||||
|
*/
|
||||||
|
public function addNoticeFromProceduralCode($message)
|
||||||
|
{
|
||||||
|
$this->deprecationNotice($message)->addProceduralOccurence();
|
||||||
|
$this->addNotice();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addNotice()
|
||||||
|
{
|
||||||
|
++$this->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $message
|
||||||
|
*
|
||||||
|
* @return DeprecationNotice
|
||||||
|
*/
|
||||||
|
private function deprecationNotice($message)
|
||||||
|
{
|
||||||
|
if (!isset($this->deprecationNotices[$message])) {
|
||||||
|
$this->deprecationNotices[$message] = new DeprecationNotice();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->deprecationNotices[$message];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return $this->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notices()
|
||||||
|
{
|
||||||
|
return $this->deprecationNotices;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
<?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\DeprecationErrorHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class DeprecationNotice
|
||||||
|
{
|
||||||
|
private $count = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
|
private $countsByCaller = [];
|
||||||
|
|
||||||
|
public function addObjectOccurence($class, $method)
|
||||||
|
{
|
||||||
|
if (!isset($this->countsByCaller["$class::$method"])) {
|
||||||
|
$this->countsByCaller["$class::$method"] = 0;
|
||||||
|
}
|
||||||
|
++$this->countsByCaller["$class::$method"];
|
||||||
|
++$this->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addProceduralOccurence()
|
||||||
|
{
|
||||||
|
++$this->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCountsByCaller()
|
||||||
|
{
|
||||||
|
return $this->countsByCaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return $this->count;
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@ namespace Symfony\Bridge\PhpUnit\Tests\DeprecationErrorHandler;
|
|||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration;
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration;
|
||||||
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\DeprecationGroup;
|
||||||
|
|
||||||
class ConfigurationTest extends TestCase
|
class ConfigurationTest extends TestCase
|
||||||
{
|
{
|
||||||
@ -47,122 +48,122 @@ class ConfigurationTest extends TestCase
|
|||||||
public function testItNoticesExceededTotalThreshold()
|
public function testItNoticesExceededTotalThreshold()
|
||||||
{
|
{
|
||||||
$configuration = Configuration::fromUrlEncodedString('max[total]=3');
|
$configuration = Configuration::fromUrlEncodedString('max[total]=3');
|
||||||
$this->assertTrue($configuration->tolerates([
|
$this->assertTrue($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1,
|
'unsilenced' => 1,
|
||||||
'remaining selfCount' => 0,
|
'self' => 0,
|
||||||
'legacyCount' => 1,
|
'legacy' => 1,
|
||||||
'otherCount' => 0,
|
'other' => 0,
|
||||||
'remaining directCount' => 1,
|
'direct' => 1,
|
||||||
'remaining indirectCount' => 1,
|
'indirect' => 1,
|
||||||
]));
|
])));
|
||||||
$this->assertFalse($configuration->tolerates([
|
$this->assertFalse($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1,
|
'unsilenced' => 1,
|
||||||
'remaining selfCount' => 1,
|
'self' => 1,
|
||||||
'legacyCount' => 1,
|
'legacy' => 1,
|
||||||
'otherCount' => 0,
|
'other' => 0,
|
||||||
'remaining directCount' => 1,
|
'direct' => 1,
|
||||||
'remaining indirectCount' => 1,
|
'indirect' => 1,
|
||||||
]));
|
])));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItNoticesExceededSelfThreshold()
|
public function testItNoticesExceededSelfThreshold()
|
||||||
{
|
{
|
||||||
$configuration = Configuration::fromUrlEncodedString('max[self]=1');
|
$configuration = Configuration::fromUrlEncodedString('max[self]=1');
|
||||||
$this->assertTrue($configuration->tolerates([
|
$this->assertTrue($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1234,
|
'unsilenced' => 1234,
|
||||||
'remaining selfCount' => 1,
|
'self' => 1,
|
||||||
'legacyCount' => 23,
|
'legacy' => 23,
|
||||||
'otherCount' => 13,
|
'other' => 13,
|
||||||
'remaining directCount' => 124,
|
'direct' => 124,
|
||||||
'remaining indirectCount' => 3244,
|
'indirect' => 3244,
|
||||||
]));
|
])));
|
||||||
$this->assertFalse($configuration->tolerates([
|
$this->assertFalse($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1234,
|
'unsilenced' => 1234,
|
||||||
'remaining selfCount' => 2,
|
'self' => 2,
|
||||||
'legacyCount' => 23,
|
'legacy' => 23,
|
||||||
'otherCount' => 13,
|
'other' => 13,
|
||||||
'remaining directCount' => 124,
|
'direct' => 124,
|
||||||
'remaining indirectCount' => 3244,
|
'indirect' => 3244,
|
||||||
]));
|
])));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItNoticesExceededDirectThreshold()
|
public function testItNoticesExceededDirectThreshold()
|
||||||
{
|
{
|
||||||
$configuration = Configuration::fromUrlEncodedString('max[direct]=1&max[self]=999999');
|
$configuration = Configuration::fromUrlEncodedString('max[direct]=1&max[self]=999999');
|
||||||
$this->assertTrue($configuration->tolerates([
|
$this->assertTrue($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1234,
|
'unsilenced' => 1234,
|
||||||
'remaining selfCount' => 123,
|
'self' => 123,
|
||||||
'legacyCount' => 23,
|
'legacy' => 23,
|
||||||
'otherCount' => 13,
|
'other' => 13,
|
||||||
'remaining directCount' => 1,
|
'direct' => 1,
|
||||||
'remaining indirectCount' => 3244,
|
'indirect' => 3244,
|
||||||
]));
|
])));
|
||||||
$this->assertFalse($configuration->tolerates([
|
$this->assertFalse($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1234,
|
'unsilenced' => 1234,
|
||||||
'remaining selfCount' => 124,
|
'self' => 124,
|
||||||
'legacyCount' => 23,
|
'legacy' => 23,
|
||||||
'otherCount' => 13,
|
'other' => 13,
|
||||||
'remaining directCount' => 2,
|
'direct' => 2,
|
||||||
'remaining indirectCount' => 3244,
|
'indirect' => 3244,
|
||||||
]));
|
])));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItNoticesExceededIndirectThreshold()
|
public function testItNoticesExceededIndirectThreshold()
|
||||||
{
|
{
|
||||||
$configuration = Configuration::fromUrlEncodedString('max[indirect]=1&max[direct]=999999&max[self]=999999');
|
$configuration = Configuration::fromUrlEncodedString('max[indirect]=1&max[direct]=999999&max[self]=999999');
|
||||||
$this->assertTrue($configuration->tolerates([
|
$this->assertTrue($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1234,
|
'unsilenced' => 1234,
|
||||||
'remaining selfCount' => 123,
|
'self' => 123,
|
||||||
'legacyCount' => 23,
|
'legacy' => 23,
|
||||||
'otherCount' => 13,
|
'other' => 13,
|
||||||
'remaining directCount' => 1234,
|
'direct' => 1234,
|
||||||
'remaining indirectCount' => 1,
|
'indirect' => 1,
|
||||||
]));
|
])));
|
||||||
$this->assertFalse($configuration->tolerates([
|
$this->assertFalse($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 1234,
|
'unsilenced' => 1234,
|
||||||
'remaining selfCount' => 124,
|
'self' => 124,
|
||||||
'legacyCount' => 23,
|
'legacy' => 23,
|
||||||
'otherCount' => 13,
|
'other' => 13,
|
||||||
'remaining directCount' => 2324,
|
'direct' => 2324,
|
||||||
'remaining indirectCount' => 2,
|
'indirect' => 2,
|
||||||
]));
|
])));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testIndirectThresholdIsUsedAsADefaultForDirectAndSelfThreshold()
|
public function testIndirectThresholdIsUsedAsADefaultForDirectAndSelfThreshold()
|
||||||
{
|
{
|
||||||
$configuration = Configuration::fromUrlEncodedString('max[indirect]=1');
|
$configuration = Configuration::fromUrlEncodedString('max[indirect]=1');
|
||||||
$this->assertTrue($configuration->tolerates([
|
$this->assertTrue($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 0,
|
'unsilenced' => 0,
|
||||||
'remaining selfCount' => 1,
|
'self' => 1,
|
||||||
'legacyCount' => 0,
|
'legacy' => 0,
|
||||||
'otherCount' => 0,
|
'other' => 0,
|
||||||
'remaining directCount' => 0,
|
'direct' => 0,
|
||||||
'remaining indirectCount' => 0,
|
'indirect' => 0,
|
||||||
]));
|
])));
|
||||||
$this->assertFalse($configuration->tolerates([
|
$this->assertFalse($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 0,
|
'unsilenced' => 0,
|
||||||
'remaining selfCount' => 2,
|
'self' => 2,
|
||||||
'legacyCount' => 0,
|
'legacy' => 0,
|
||||||
'otherCount' => 0,
|
'other' => 0,
|
||||||
'remaining directCount' => 0,
|
'direct' => 0,
|
||||||
'remaining indirectCount' => 0,
|
'indirect' => 0,
|
||||||
]));
|
])));
|
||||||
$this->assertTrue($configuration->tolerates([
|
$this->assertTrue($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 0,
|
'unsilenced' => 0,
|
||||||
'remaining selfCount' => 0,
|
'self' => 0,
|
||||||
'legacyCount' => 0,
|
'legacy' => 0,
|
||||||
'otherCount' => 0,
|
'other' => 0,
|
||||||
'remaining directCount' => 1,
|
'direct' => 1,
|
||||||
'remaining indirectCount' => 0,
|
'indirect' => 0,
|
||||||
]));
|
])));
|
||||||
$this->assertFalse($configuration->tolerates([
|
$this->assertFalse($configuration->tolerates($this->buildGroups([
|
||||||
'unsilencedCount' => 0,
|
'unsilenced' => 0,
|
||||||
'remaining selfCount' => 0,
|
'self' => 0,
|
||||||
'legacyCount' => 0,
|
'legacy' => 0,
|
||||||
'otherCount' => 0,
|
'other' => 0,
|
||||||
'remaining directCount' => 2,
|
'direct' => 2,
|
||||||
'remaining indirectCount' => 0,
|
'indirect' => 0,
|
||||||
]));
|
])));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testItCanTellWhetherToDisplayAStackTrace()
|
public function testItCanTellWhetherToDisplayAStackTrace()
|
||||||
@ -184,12 +185,51 @@ class ConfigurationTest extends TestCase
|
|||||||
public function testItCanBeShushed()
|
public function testItCanBeShushed()
|
||||||
{
|
{
|
||||||
$configuration = Configuration::fromUrlEncodedString('verbose');
|
$configuration = Configuration::fromUrlEncodedString('verbose');
|
||||||
$this->assertFalse($configuration->verboseOutput());
|
$this->assertFalse($configuration->verboseOutput('unsilenced'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('direct'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('indirect'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('self'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('other'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCanBePartiallyShushed()
|
||||||
|
{
|
||||||
|
$configuration = Configuration::fromUrlEncodedString('quiet[]=unsilenced&quiet[]=indirect&quiet[]=other');
|
||||||
|
$this->assertFalse($configuration->verboseOutput('unsilenced'));
|
||||||
|
$this->assertTrue($configuration->verboseOutput('direct'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('indirect'));
|
||||||
|
$this->assertTrue($configuration->verboseOutput('self'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('other'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItThrowsOnUnknownVerbosityGroup()
|
||||||
|
{
|
||||||
|
$this->expectException(\InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage('made-up');
|
||||||
|
Configuration::fromUrlEncodedString('quiet[]=made-up');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testOutputIsNotVerboseInWeakMode()
|
public function testOutputIsNotVerboseInWeakMode()
|
||||||
{
|
{
|
||||||
$configuration = Configuration::inWeakMode();
|
$configuration = Configuration::inWeakMode();
|
||||||
$this->assertFalse($configuration->verboseOutput());
|
$this->assertFalse($configuration->verboseOutput('unsilenced'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('direct'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('indirect'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('self'));
|
||||||
|
$this->assertFalse($configuration->verboseOutput('other'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildGroups($counts)
|
||||||
|
{
|
||||||
|
$groups = [];
|
||||||
|
foreach ($counts as $name => $count) {
|
||||||
|
$groups[$name] = new DeprecationGroup();
|
||||||
|
$i = 0;
|
||||||
|
while ($i++ < $count) {
|
||||||
|
$groups[$name]->addNotice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $groups;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\PhpUnit\Tests\DeprecationErrorHandler;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\DeprecationGroup;
|
||||||
|
|
||||||
|
final class DeprecationGroupTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testItGroupsByMessage()
|
||||||
|
{
|
||||||
|
$group = new DeprecationGroup();
|
||||||
|
$group->addNoticeFromObject(
|
||||||
|
'Calling sfContext::getInstance() is deprecated',
|
||||||
|
'MonsterController',
|
||||||
|
'get5klocMethod'
|
||||||
|
);
|
||||||
|
$group->addNoticeFromProceduralCode('Calling sfContext::getInstance() is deprecated');
|
||||||
|
$this->assertCount(1, $group->notices());
|
||||||
|
$this->assertSame(2, $group->count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItAllowsAddingANoticeWithoutClutteringTheMemory()
|
||||||
|
{
|
||||||
|
// this is useful for notices in the legacy group
|
||||||
|
$group = new DeprecationGroup();
|
||||||
|
$group->addNotice();
|
||||||
|
$this->assertSame(1, $group->count());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\PhpUnit\Tests\DeprecationErrorHandler;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\DeprecationNotice;
|
||||||
|
|
||||||
|
final class DeprecationNoticeTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testItGroupsByCaller()
|
||||||
|
{
|
||||||
|
$notice = new DeprecationNotice();
|
||||||
|
$notice->addObjectOccurence('MyAction', '__invoke');
|
||||||
|
$notice->addObjectOccurence('MyAction', '__invoke');
|
||||||
|
$notice->addObjectOccurence('MyOtherAction', '__invoke');
|
||||||
|
|
||||||
|
$countsByCaller = $notice->getCountsByCaller();
|
||||||
|
|
||||||
|
$this->assertCount(2, $countsByCaller);
|
||||||
|
$this->assertArrayHasKey('MyAction::__invoke', $countsByCaller);
|
||||||
|
$this->assertArrayHasKey('MyOtherAction::__invoke', $countsByCaller);
|
||||||
|
$this->assertSame(2, $countsByCaller['MyAction::__invoke']);
|
||||||
|
$this->assertSame(1, $countsByCaller['MyOtherAction::__invoke']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCountsBothTypesOfOccurences()
|
||||||
|
{
|
||||||
|
$notice = new DeprecationNotice();
|
||||||
|
$notice->addObjectOccurence('MyAction', '__invoke');
|
||||||
|
$this->assertSame(1, $notice->count());
|
||||||
|
|
||||||
|
$notice->addProceduralOccurence();
|
||||||
|
$this->assertSame(2, $notice->count());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
--TEST--
|
||||||
|
Test DeprecationErrorHandler quiet on everything but indirect deprecations
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$k = 'SYMFONY_DEPRECATIONS_HELPER';
|
||||||
|
putenv($k.'='.$_SERVER[$k] = $_ENV[$k] = 'max[self]=0&quiet[]=unsilenced&quiet[]=direct&quiet[]=other');
|
||||||
|
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';
|
||||||
|
require __DIR__.'/fake_vendor/autoload.php';
|
||||||
|
require __DIR__.'/fake_vendor/acme/lib/deprecation_riddled.php';
|
||||||
|
require __DIR__.'/fake_vendor/acme/outdated-lib/outdated_file.php';
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Unsilenced deprecation notices (3)
|
||||||
|
|
||||||
|
Remaining direct deprecation notices (1)
|
||||||
|
|
||||||
|
Remaining indirect deprecation notices (1)
|
||||||
|
|
||||||
|
1x: deprecatedApi is deprecated! You should stop relying on it!
|
||||||
|
1x in SomeService::deprecatedApi from acme\lib
|
||||||
|
|
||||||
|
Legacy deprecation notices (2)
|
||||||
|
|
||||||
|
Other deprecation notices (1)
|
||||||
|
|
@ -0,0 +1,39 @@
|
|||||||
|
--TEST--
|
||||||
|
Test DeprecationErrorHandler when failing and not verbose
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$k = 'SYMFONY_DEPRECATIONS_HELPER';
|
||||||
|
putenv($k.'='.$_SERVER[$k] = $_ENV[$k] = 'max[total]=0&verbose=0');
|
||||||
|
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';
|
||||||
|
eval(<<<'EOPHP'
|
||||||
|
namespace PHPUnit\Util;
|
||||||
|
|
||||||
|
class Test
|
||||||
|
{
|
||||||
|
public static function getGroups()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOPHP
|
||||||
|
);
|
||||||
|
require __DIR__.'/fake_vendor/autoload.php';
|
||||||
|
require __DIR__.'/fake_vendor/acme/outdated-lib/outdated_file.php';
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Remaining indirect deprecation notices (1)
|
||||||
|
|
||||||
|
1x: deprecatedApi is deprecated! You should stop relying on it!
|
||||||
|
1x in SomeService::deprecatedApi from acme\lib
|
Reference in New Issue
Block a user