Introduce weak vendors mode

A new mode is introduced, in which deprecations coming from the vendors
are not taken into account when deciding to exit with an error code. In
this mode, deprecations coming from the vendors are segregated from
other deprecations.
This commit is contained in:
Grégoire Paris 2017-02-05 18:06:12 +01:00
parent 1d50688580
commit 61fd043dd5
No known key found for this signature in database
GPG Key ID: 24D48B8012B116BF
7 changed files with 196 additions and 6 deletions

View File

@ -19,6 +19,7 @@ namespace Symfony\Bridge\PhpUnit;
class DeprecationErrorHandler
{
const MODE_WEAK = 'weak';
const MODE_WEAK_VENDORS = 'weak_vendors';
const MODE_DISABLED = 'disabled';
private static $isRegistered = false;
@ -28,6 +29,7 @@ class DeprecationErrorHandler
*
* The following reporting modes are supported:
* - use "weak" to hide the deprecation report but keep a global count;
* - use "weak_vendors" to act as "weak" but only for vendors;
* - use "/some-regexp/" to stop the test suite whenever a deprecation
* message matches the given regular expression;
* - use a number to define the upper bound of allowed deprecations,
@ -52,13 +54,37 @@ class DeprecationErrorHandler
if (false === $mode) {
$mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
}
if (DeprecationErrorHandler::MODE_WEAK !== $mode && (!isset($mode[0]) || '/' !== $mode[0])) {
if (DeprecationErrorHandler::MODE_WEAK !== $mode && DeprecationErrorHandler::MODE_WEAK_VENDORS !== $mode && (!isset($mode[0]) || '/' !== $mode[0])) {
$mode = preg_match('/^[1-9][0-9]*$/', $mode) ? (int) $mode : 0;
}
return $memoizedMode = $mode;
};
$inVendors = function ($path) {
/** @var string[] absolute paths to vendor directories */
static $vendors;
if (null === $vendors) {
foreach (get_declared_classes() as $class) {
if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
$r = new \ReflectionClass($class);
$v = dirname(dirname($r->getFileName()));
if (file_exists($v.'/composer/installed.json')) {
$vendors[] = $v;
}
}
}
}
$path = realpath($path) ?: $path;
foreach ($vendors as $vendor) {
if (0 === strpos($path, $vendor) && false !== strpbrk(substr($path, strlen($vendor), 1), '/'.DIRECTORY_SEPARATOR)) {
return true;
}
}
return false;
};
$deprecations = array(
'unsilencedCount' => 0,
'remainingCount' => 0,
@ -69,7 +95,13 @@ class DeprecationErrorHandler
'legacy' => array(),
'other' => array(),
);
$deprecationHandler = function ($type, $msg, $file, $line, $context) use (&$deprecations, $getMode, $UtilPrefix) {
if (self::MODE_WEAK_VENDORS === $mode) {
$deprecations += array(
'remaining vendorCount' => 0,
'remaining vendor' => array(),
);
}
$deprecationHandler = function ($type, $msg, $file, $line, $context) use (&$deprecations, $getMode, $UtilPrefix, $inVendors) {
$mode = $getMode();
if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || DeprecationErrorHandler::MODE_DISABLED === $mode) {
$ErrorHandler = $UtilPrefix.'ErrorHandler';
@ -80,6 +112,8 @@ class DeprecationErrorHandler
$trace = debug_backtrace(true);
$group = 'other';
$isWeak = DeprecationErrorHandler::MODE_WEAK === $mode || (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $isVendor = $inVendors($file));
$i = count($trace);
while (1 < $i && (!isset($trace[--$i]['class']) || ('ReflectionMethod' === $trace[$i]['class'] || 0 === strpos($trace[$i]['class'], 'PHPUnit_') || 0 === strpos($trace[$i]['class'], 'PHPUnit\\')))) {
// No-op
@ -99,6 +133,8 @@ class DeprecationErrorHandler
|| in_array('legacy', $Test::getGroups($class, $method), true)
) {
$group = 'legacy';
} elseif (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode && $isVendor) {
$group = 'remaining vendor';
} else {
$group = 'remaining';
}
@ -117,13 +153,13 @@ class DeprecationErrorHandler
exit(1);
}
if ('legacy' !== $group && DeprecationErrorHandler::MODE_WEAK !== $mode) {
if ('legacy' !== $group && !$isWeak) {
$ref = &$deprecations[$group][$msg]['count'];
++$ref;
$ref = &$deprecations[$group][$msg][$class.'::'.$method];
++$ref;
}
} elseif (DeprecationErrorHandler::MODE_WEAK !== $mode) {
} elseif (!$isWeak) {
$ref = &$deprecations[$group][$msg]['count'];
++$ref;
}
@ -167,9 +203,18 @@ class DeprecationErrorHandler
return $b['count'] - $a['count'];
};
foreach (array('unsilenced', 'remaining', 'legacy', 'other') as $group) {
$groups = array('unsilenced', 'remaining');
if (DeprecationErrorHandler::MODE_WEAK_VENDORS === $mode) {
$groups[] = 'remaining vendor';
}
array_push($groups, 'legacy', 'other');
foreach ($groups as $group) {
if ($deprecations[$group.'Count']) {
echo "\n", $colorize(sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']), 'legacy' !== $group), "\n";
echo "\n", $colorize(
sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']),
'legacy' !== $group && 'remaining vendor' !== $group
), "\n";
uasort($deprecations[$group], $cmp);

View File

@ -0,0 +1,35 @@
<?php
eval(<<<'EOPHP'
namespace PHPUnit\Util;
class Test
{
public static function getGroups()
{
return array();
}
}
EOPHP
);
@trigger_error('root deprecation', E_USER_DEPRECATED);
class FooTestCase
{
public function testLegacyFoo()
{
@trigger_error('silenced foo deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
}
public function testNonLegacyBar()
{
@trigger_error('silenced bar deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced bar deprecation', E_USER_DEPRECATED);
}
}
$foo = new FooTestCase();
$foo->testLegacyFoo();
$foo->testNonLegacyBar();

View File

@ -0,0 +1,3 @@
<?php
require_once __DIR__.'/composer/autoload_real.php';

View File

@ -0,0 +1,5 @@
<?php
class ComposerAutoloaderInitFake
{
}

View File

@ -0,0 +1 @@
{"just here": "for the detection"}

View File

@ -0,0 +1,74 @@
--TEST--
Test DeprecationErrorHandler in weak vendors mode on a non vendor file
--FILE--
<?php
putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors');
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);
eval(<<<'EOPHP'
namespace PHPUnit\Util;
class Test
{
public static function getGroups()
{
return array();
}
}
EOPHP
);
class FooTestCase
{
public function testLegacyFoo()
{
@trigger_error('silenced foo deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
}
public function testNonLegacyBar()
{
@trigger_error('silenced bar deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced bar deprecation', E_USER_DEPRECATED);
}
}
$foo = new FooTestCase();
$foo->testLegacyFoo();
$foo->testNonLegacyBar();
?>
--EXPECTF--
Unsilenced deprecation notices (3)
unsilenced foo deprecation: 2x
2x in FooTestCase::testLegacyFoo
unsilenced bar deprecation: 1x
1x in FooTestCase::testNonLegacyBar
Remaining deprecation notices (1)
silenced bar deprecation: 1x
1x in FooTestCase::testNonLegacyBar
Legacy deprecation notices (1)
Other deprecation notices (1)
root deprecation: 1x

View File

@ -0,0 +1,27 @@
--TEST--
Test DeprecationErrorHandler in weak vendors mode on vendor file
--FILE--
<?php
putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors');
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';
--EXPECTF--
Unsilenced deprecation notices (2)
Remaining vendor deprecation notices (1)
Legacy deprecation notices (1)
Other deprecation notices (1)