Skip to content

Commit 92d4a84

Browse files
committed
[PHPUnitBridge] Fix deprecation type detection when trigger_deprecation is used
1 parent 96151f3 commit 92d4a84

File tree

11 files changed

+232
-14
lines changed

11 files changed

+232
-14
lines changed

src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,19 @@ class Deprecation
5252
*/
5353
public function __construct($message, array $trace, $file)
5454
{
55-
$this->trace = $trace;
55+
$backtraceTriggerDeprecation = $trace[2] ?? null;
56+
if ($backtraceTriggerDeprecation && 'trigger_deprecation' === $backtraceTriggerDeprecation['function']) {
57+
$file = $backtraceTriggerDeprecation['file'];
58+
unset($trace[1]);
59+
}
60+
61+
$this->trace = array_values($trace);
5662
$this->message = $message;
57-
$i = \count($trace);
58-
while (1 < $i && $this->lineShouldBeSkipped($trace[--$i])) {
63+
$i = \count($this->trace);
64+
while (1 < $i && $this->lineShouldBeSkipped($this->trace[--$i])) {
5965
// No-op
6066
}
61-
$line = $trace[$i];
67+
$line = $this->trace[$i];
6268
$this->triggeringFile = $file;
6369
if (isset($line['object']) || isset($line['class'])) {
6470
if (isset($line['class']) && 0 === strpos($line['class'], SymfonyTestsListenerFor::class)) {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace App\Services;
4+
5+
use acme\lib\SomeService;
6+
use foo\lib\SomeOtherService;
7+
8+
final class AppService
9+
{
10+
public function directDeprecationsTwoVendors()
11+
{
12+
$service1 = new SomeService();
13+
$service1->deprecatedApi();
14+
15+
$service2 = new SomeOtherService();
16+
$service2->deprecatedApi();
17+
}
18+
19+
public function selfDeprecation(bool $useContracts = false)
20+
{
21+
$args = [__FUNCTION__, __FUNCTION__];
22+
if ($useContracts) {
23+
trigger_deprecation('App', '3.0', sprintf('%s is deprecated, use %s_new instead.', ...$args));
24+
} else {
25+
@trigger_error(sprintf('Since App 3.0: %s is deprecated, use %s_new instead.', ...$args), E_USER_DEPRECATED);
26+
}
27+
}
28+
29+
public function directDeprecation(bool $useContracts = false)
30+
{
31+
$service = new SomeService();
32+
$service->deprecatedApi($useContracts);
33+
}
34+
35+
public function indirectDeprecation(bool $useContracts = false)
36+
{
37+
$service = new SomeService();
38+
$service->indirectDeprecatedApi($useContracts);
39+
}
40+
}
41+

src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/lib/SomeService.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,22 @@
22

33
namespace acme\lib;
44

5+
use bar\lib\AnotherService;
6+
57
class SomeService
68
{
7-
public function deprecatedApi()
9+
public function deprecatedApi(bool $useContracts = false)
10+
{
11+
$args = [__FUNCTION__, __FUNCTION__];
12+
if ($useContracts) {
13+
trigger_deprecation('acme/lib', '3.0', sprintf('%s is deprecated, use %s_new instead.', ...$args));
14+
} else {
15+
@trigger_error(sprintf('Since acme/lib 3.0: %s is deprecated, use %s_new instead.', ...$args), E_USER_DEPRECATED);
16+
}
17+
}
18+
19+
public function indirectDeprecatedApi(bool $useContracts = false)
820
{
9-
@trigger_error(
10-
__FUNCTION__.' is deprecated! You should stop relying on it!',
11-
E_USER_DEPRECATED
12-
);
21+
(new AnotherService())->deprecatedApi($useContracts);
1322
}
1423
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace bar\lib;
4+
5+
class AnotherService
6+
{
7+
public function deprecatedApi(bool $useContracts = false)
8+
{
9+
$args = [__FUNCTION__, __FUNCTION__];
10+
if ($useContracts) {
11+
trigger_deprecation('bar/lib', '3.0', sprintf('%s is deprecated, use %s_new instead.', ...$args));
12+
} else {
13+
@trigger_error(sprintf('Since bar/lib 3.0: %s is deprecated, use %s_new instead.', ...$args), E_USER_DEPRECATED);
14+
}
15+
}
16+
}

src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/composer/autoload_real.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,41 @@ public function getPrefixes()
99

1010
public function getPrefixesPsr4()
1111
{
12-
return [];
12+
return [
13+
'App\\Services\\' => [__DIR__.'/../../fake_app/'],
14+
'acme\\lib\\' => [__DIR__.'/../acme/lib/'],
15+
'bar\\lib\\' => [__DIR__.'/../bar/lib/'],
16+
];
17+
}
18+
19+
public function loadClass($className)
20+
{
21+
foreach ($this->getPrefixesPsr4() as $prefix => $baseDirs) {
22+
if (strpos($className, $prefix) !== 0) {
23+
continue;
24+
}
25+
26+
foreach ($baseDirs as $baseDir) {
27+
$file = str_replace([$prefix, '\\'], [$baseDir, '/'], $className.'.php');
28+
if (file_exists($file)) {
29+
require $file;
30+
}
31+
}
32+
}
1333
}
1434
}
1535

1636
class ComposerAutoloaderInitFake
1737
{
38+
private static $loader;
39+
1840
public static function getLoader()
1941
{
20-
return new ComposerLoaderFake();
42+
if (null === self::$loader) {
43+
self::$loader = new ComposerLoaderFake();
44+
spl_autoload_register([self::$loader, 'loadClass']);
45+
}
46+
47+
return self::$loader;
2148
}
2249
}

src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/lagging_vendor.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ require __DIR__.'/fake_vendor/acme/outdated-lib/outdated_file.php';
3535
--EXPECTF--
3636
Remaining indirect deprecation notices (1)
3737

38-
1x: deprecatedApi is deprecated! You should stop relying on it!
38+
1x: Since acme/lib 3.0: deprecatedApi is deprecated, use deprecatedApi_new instead.
3939
1x in SomeService::deprecatedApi from acme\lib

src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/partially_quiet.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Remaining direct deprecation notices (1)
2828

2929
Remaining indirect deprecation notices (1)
3030

31-
1x: deprecatedApi is deprecated! You should stop relying on it!
31+
1x: Since acme/lib 3.0: deprecatedApi is deprecated, use deprecatedApi_new instead.
3232
1x in SomeService::deprecatedApi from acme\lib
3333

3434
Legacy deprecation notices (2)

src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/quiet_but_failing.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ require __DIR__.'/fake_vendor/acme/outdated-lib/outdated_file.php';
3535
--EXPECTF--
3636
Remaining indirect deprecation notices (1)
3737

38-
1x: deprecatedApi is deprecated! You should stop relying on it!
38+
1x: Since acme/lib 3.0: deprecatedApi is deprecated, use deprecatedApi_new instead.
3939
1x in SomeService::deprecatedApi from acme\lib
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Test deprecation types with trigger_deprecation
3+
--FILE--
4+
<?php
5+
6+
$k = 'SYMFONY_DEPRECATIONS_HELPER';
7+
putenv($k.'='.$_SERVER[$k] = $_ENV[$k] = 'max[self]=0');
8+
putenv('ANSICON');
9+
putenv('ConEmuANSI');
10+
putenv('TERM');
11+
12+
$vendor = __DIR__;
13+
while (!file_exists($vendor.'/vendor')) {
14+
$vendor = dirname($vendor);
15+
}
16+
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
17+
require PHPUNIT_COMPOSER_INSTALL;
18+
require_once __DIR__.'/../../bootstrap.php';
19+
20+
eval(<<<'EOPHP'
21+
namespace PHPUnit\Util;
22+
23+
class Test
24+
{
25+
public static function getGroups()
26+
{
27+
return array();
28+
}
29+
}
30+
EOPHP
31+
);
32+
33+
require __DIR__.'/fake_vendor/autoload.php';
34+
35+
(new \App\Services\AppService())->selfDeprecation(true);
36+
(new \App\Services\AppService())->directDeprecation(true);
37+
(new \App\Services\AppService())->indirectDeprecation(true);
38+
trigger_deprecation('foo/bar', '2.0', 'func is deprecated, use new instead.');
39+
?>
40+
--EXPECTF--
41+
Remaining self deprecation notices (1)
42+
43+
1x: Since App 3.0: selfDeprecation is deprecated, use selfDeprecation_new instead.
44+
1x in AppService::selfDeprecation from App\Services
45+
46+
Remaining direct deprecation notices (1)
47+
48+
1x: Since acme/lib 3.0: deprecatedApi is deprecated, use deprecatedApi_new instead.
49+
1x in AppService::directDeprecation from App\Services
50+
51+
Remaining indirect deprecation notices (1)
52+
53+
1x: Since bar/lib 3.0: deprecatedApi is deprecated, use deprecatedApi_new instead.
54+
1x in AppService::indirectDeprecation from App\Services
55+
56+
Other deprecation notices (1)
57+
58+
1x: Since foo/bar 2.0: func is deprecated, use new instead.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Test deprecation types with trigger_error
3+
--FILE--
4+
<?php
5+
6+
$k = 'SYMFONY_DEPRECATIONS_HELPER';
7+
putenv($k.'='.$_SERVER[$k] = $_ENV[$k] = 'max[self]=0');
8+
putenv('ANSICON');
9+
putenv('ConEmuANSI');
10+
putenv('TERM');
11+
12+
$vendor = __DIR__;
13+
while (!file_exists($vendor.'/vendor')) {
14+
$vendor = dirname($vendor);
15+
}
16+
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
17+
require PHPUNIT_COMPOSER_INSTALL;
18+
require_once __DIR__.'/../../bootstrap.php';
19+
20+
eval(<<<'EOPHP'
21+
namespace PHPUnit\Util;
22+
23+
class Test
24+
{
25+
public static function getGroups()
26+
{
27+
return array();
28+
}
29+
}
30+
EOPHP
31+
);
32+
33+
require __DIR__.'/fake_vendor/autoload.php';
34+
35+
(new \App\Services\AppService())->selfDeprecation();
36+
(new \App\Services\AppService())->directDeprecation();
37+
(new \App\Services\AppService())->indirectDeprecation();
38+
@trigger_error('Since foo/bar 2.0: func is deprecated, use new instead.', E_USER_DEPRECATED);
39+
?>
40+
--EXPECTF--
41+
Remaining self deprecation notices (1)
42+
43+
1x: Since App 3.0: selfDeprecation is deprecated, use selfDeprecation_new instead.
44+
1x in AppService::selfDeprecation from App\Services
45+
46+
Remaining direct deprecation notices (1)
47+
48+
1x: Since acme/lib 3.0: deprecatedApi is deprecated, use deprecatedApi_new instead.
49+
1x in AppService::directDeprecation from App\Services
50+
51+
Remaining indirect deprecation notices (1)
52+
53+
1x: Since bar/lib 3.0: deprecatedApi is deprecated, use deprecatedApi_new instead.
54+
1x in AppService::indirectDeprecation from App\Services
55+
56+
Other deprecation notices (1)
57+
58+
1x: Since foo/bar 2.0: func is deprecated, use new instead.

0 commit comments

Comments
 (0)