Skip to content

[PHPUnitBridge] Improved deprecations display #35271

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 29, 2020
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
6 changes: 6 additions & 0 deletions src/Symfony/Bridge/PhpUnit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
CHANGELOG
=========

5.1.0
-----

* ignore verbosity settings when the build fails because of deprecations
* added per-group verbosity

5.0.0
-----

Expand Down
106 changes: 58 additions & 48 deletions src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use PHPUnit\Util\ErrorHandler;
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration;
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\DeprecationGroup;
use Symfony\Component\ErrorHandler\DebugClassLoader;

/**
Expand All @@ -30,24 +31,20 @@ class DeprecationErrorHandler

private $mode;
private $configuration;
private $deprecations = [
'unsilencedCount' => 0,
'remaining selfCount' => 0,
'legacyCount' => 0,
'otherCount' => 0,
'remaining directCount' => 0,
'remaining indirectCount' => 0,
'unsilenced' => [],
'remaining self' => [],
'legacy' => [],
'other' => [],
'remaining direct' => [],
'remaining indirect' => [],
];

/**
* @var DeprecationGroup[]
*/
private $deprecationGroups = [];

private static $isRegistered = false;
private static $isAtLeastPhpUnit83;

public function __construct()
{
$this->resetDeprecationGroups();
}

/**
* Registers and configures the deprecation handler.
*
Expand Down Expand Up @@ -135,9 +132,9 @@ public function handleError($type, $msg, $file, $line, $context = [])
$group = 'legacy';
} else {
$group = [
Deprecation::TYPE_SELF => 'remaining self',
Deprecation::TYPE_DIRECT => 'remaining direct',
Deprecation::TYPE_INDIRECT => 'remaining indirect',
Deprecation::TYPE_SELF => 'self',
Deprecation::TYPE_DIRECT => 'direct',
Deprecation::TYPE_INDIRECT => 'indirect',
Deprecation::TYPE_UNDETERMINED => 'other',
][$deprecation->getType()];
}
Expand All @@ -148,18 +145,14 @@ public function handleError($type, $msg, $file, $line, $context = [])
exit(1);
}
if ('legacy' !== $group) {
$ref = &$this->deprecations[$group][$msg]['count'];
++$ref;
$ref = &$this->deprecations[$group][$msg][$class.'::'.$method];
++$ref;
$this->deprecationGroups[$group]->addNoticeFromObject($msg, $class, $method);
} else {
$this->deprecationGroups[$group]->addNotice();
}
} else {
$ref = &$this->deprecations[$group][$msg]['count'];
++$ref;
$this->deprecationGroups[$group]->addNoticeFromProceduralCode($msg);
}

++$this->deprecations[$group.'Count'];

return null;
}

Expand All @@ -184,34 +177,44 @@ public function shutdown()
echo "\n", self::colorize('THE ERROR HANDLER HAS CHANGED!', true), "\n";
}

$groups = ['unsilenced', 'remaining self', 'remaining direct', 'remaining indirect', 'legacy', 'other'];

$this->displayDeprecations($groups, $configuration);
$groups = array_keys($this->deprecationGroups);

// store failing status
$isFailing = !$configuration->tolerates($this->deprecations);
$isFailing = !$configuration->tolerates($this->deprecationGroups);

// reset deprecations array
foreach ($this->deprecations as $group => $arrayOrInt) {
$this->deprecations[$group] = \is_int($arrayOrInt) ? 0 : [];
}
$this->displayDeprecations($groups, $configuration, $isFailing);

$this->resetDeprecationGroups();

register_shutdown_function(function () use ($isFailing, $groups, $configuration) {
foreach ($this->deprecations as $group => $arrayOrInt) {
if (0 < (\is_int($arrayOrInt) ? $arrayOrInt : \count($arrayOrInt))) {
foreach ($this->deprecationGroups as $group) {
if ($group->count() > 0) {
echo "Shutdown-time deprecations:\n";
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);
}
});
}

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()
{
if (null !== $this->configuration) {
Expand Down Expand Up @@ -270,31 +273,38 @@ private static function colorize($str, $red)
/**
* @param string[] $groups
* @param Configuration $configuration
* @param bool $isFailing
*/
private function displayDeprecations($groups, $configuration)
private function displayDeprecations($groups, $configuration, $isFailing)
{
$cmp = function ($a, $b) {
return $b['count'] - $a['count'];
return $b->count() - $a->count();
};

foreach ($groups as $group) {
if ($this->deprecations[$group.'Count']) {
if ($this->deprecationGroups[$group]->count()) {
echo "\n", self::colorize(
sprintf('%s deprecation notices (%d)', ucfirst($group), $this->deprecations[$group.'Count']),
'legacy' !== $group && 'remaining indirect' !== $group
sprintf(
'%s deprecation notices (%d)',
\in_array($group, ['direct', 'indirect', 'self'], true) ? "Remaining $group" : ucfirst($group),
$this->deprecationGroups[$group]->count()
),
'legacy' !== $group && 'indirect' !== $group
), "\n";

if (!$configuration->verboseOutput()) {
if ('legacy' !== $group && !$configuration->verboseOutput($group) && !$isFailing) {
continue;
}
uasort($this->deprecations[$group], $cmp);
$notices = $this->deprecationGroups[$group]->notices();
uasort($notices, $cmp);

foreach ($this->deprecations[$group] as $msg => $notices) {
echo "\n ", $notices['count'], 'x: ', $msg, "\n";
foreach ($notices as $msg => $notice) {
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) {
echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ class Configuration
private $enabled = true;

/**
* @var bool
* @var bool[]
*/
private $verboseOutput = true;
private $verboseOutput;

/**
* @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
* @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'];

Expand Down Expand Up @@ -72,7 +72,21 @@ private function __construct(array $thresholds = [], $regex = '', $verboseOutput
}
}
$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;
}
}

/**
Expand All @@ -84,24 +98,26 @@ public function isEnabled()
}

/**
* @param mixed[] $deprecations
* @param DeprecationGroup[] $deprecationGroups
*
* @return bool
*/
public function tolerates(array $deprecations)
public function tolerates(array $deprecationGroups)
{
$deprecationCounts = [];
foreach ($deprecations as $key => $deprecation) {
if (false !== strpos($key, 'Count') && false === strpos($key, 'legacy')) {
$deprecationCounts[$key] = $deprecation;
$grandTotal = 0;

foreach ($deprecationGroups as $name => $group) {
if ('legacy' !== $name) {
$grandTotal += $group->count();
}
}

if (array_sum($deprecationCounts) > $this->thresholds['total']) {
if ($grandTotal > $this->thresholds['total']) {
return false;
}

foreach (['self', 'direct', 'indirect'] as $deprecationType) {
if ($deprecationCounts['remaining '.$deprecationType.'Count'] > $this->thresholds[$deprecationType]) {
if ($deprecationGroups[$deprecationType]->count() > $this->thresholds[$deprecationType]) {
return false;
}
}
Expand Down Expand Up @@ -130,9 +146,9 @@ public function isInRegexMode()
/**
* @return bool
*/
public function verboseOutput()
public function verboseOutput($group)
{
return $this->verboseOutput;
return $this->verboseOutput[$group];
}

/**
Expand All @@ -145,7 +161,7 @@ public static function fromUrlEncodedString($serializedConfiguration)
{
parse_str($serializedConfiguration, $normalizedConfiguration);
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));
}
}
Expand All @@ -154,9 +170,19 @@ public static function fromUrlEncodedString($serializedConfiguration)
return self::inDisabledMode();
}

$verboseOutput = true;
if (isset($normalizedConfiguration['verbose'])) {
$verboseOutput = (bool) $normalizedConfiguration['verbose'];
$verboseOutput = [];
if (!isset($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(
Expand Down Expand Up @@ -190,7 +216,12 @@ public static function inStrictMode()
*/
public static function inWeakMode()
{
return new self([], '', false);
$verboseOutput = [];
foreach (['unsilenced', 'direct', 'indirect', 'self', 'other'] as $group) {
$verboseOutput[$group] = false;
}

return new self([], '', $verboseOutput);
}

/**
Expand Down
Loading