Skip to content

Commit 056d598

Browse files
l-vonicolas-grekas
authored andcommitted
[PhpUnitBridge] Fix some errors when using serialized deprecations
1 parent 3750988 commit 056d598

File tree

3 files changed

+180
-10
lines changed

3 files changed

+180
-10
lines changed

src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,19 @@ public static function collectDeprecations($outputFile)
104104
return \call_user_func(self::getPhpUnitErrorHandler(), $type, $msg, $file, $line, $context);
105105
}
106106

107-
$deprecations[] = [error_reporting(), $msg, $file];
107+
$trace = debug_backtrace();
108+
$filesStack = [];
109+
foreach ($trace as $line) {
110+
if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
111+
continue;
112+
}
113+
114+
if (isset($line['file'])) {
115+
$filesStack[] = $line['file'];
116+
}
117+
}
118+
119+
$deprecations[] = [error_reporting(), $msg, $file, $filesStack];
108120

109121
return null;
110122
});

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

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class Deprecation
4444
*/
4545
private static $internalPaths = [];
4646

47+
private $originalFilesStack;
48+
4749
/**
4850
* @param string $message
4951
* @param string $file
@@ -64,6 +66,7 @@ public function __construct($message, array $trace, $file)
6466
$this->message = $parsedMsg['deprecation'];
6567
$this->originClass = $parsedMsg['class'];
6668
$this->originMethod = $parsedMsg['method'];
69+
$this->originalFilesStack = $parsedMsg['files_stack'];
6770
// If the deprecation has been triggered via
6871
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
6972
// then we need to use the serialized information to determine
@@ -162,6 +165,24 @@ public function isMuted()
162165
return false !== strpos($this->triggeringFile, \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR.'phpunit'.\DIRECTORY_SEPARATOR);
163166
}
164167

168+
private function getOriginalFilesStack(): array
169+
{
170+
if (null === $this->originalFilesStack) {
171+
$this->originalFilesStack = [];
172+
foreach ($this->trace as $line) {
173+
if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
174+
continue;
175+
}
176+
if (!isset($line['file'])) {
177+
continue;
178+
}
179+
$this->originalFilesStack[] = $line['file'];
180+
}
181+
}
182+
183+
return $this->originalFilesStack;
184+
}
185+
165186
/**
166187
* Tells whether both the calling package and the called package are vendor
167188
* packages.
@@ -178,14 +199,8 @@ public function getType()
178199
return self::TYPE_UNDETERMINED;
179200
}
180201
$erroringFile = $erroringPackage = null;
181-
foreach ($this->trace as $line) {
182-
if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
183-
continue;
184-
}
185-
if (!isset($line['file'])) {
186-
continue;
187-
}
188-
$file = $line['file'];
202+
203+
foreach ($this->getOriginalFilesStack() as $file) {
189204
if ('-' === $file || 'Standard input code' === $file || !realpath($file)) {
190205
continue;
191206
}

src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php

Lines changed: 144 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,32 @@
1111

1212
namespace Symfony\Bridge\PhpUnit\Tests\DeprecationErrorHandler;
1313

14+
use Composer\Autoload\ClassLoader;
1415
use PHPUnit\Framework\TestCase;
1516
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler;
1617
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation;
18+
use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV5;
1719

1820
class DeprecationTest extends TestCase
1921
{
22+
public static function setUpBeforeClass(): void
23+
{
24+
$vendorDir = self::getVendorDir();
25+
26+
mkdir($vendorDir.'/myfakevendor/myfakepackage1', 0777, true);
27+
mkdir($vendorDir.'/myfakevendor/myfakepackage2');
28+
touch($vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php');
29+
touch($vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile2.php');
30+
touch($vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php');
31+
}
32+
33+
private static function getVendorDir(): string
34+
{
35+
$reflection = new \ReflectionClass(ClassLoader::class);
36+
37+
return \dirname($reflection->getFileName(), 2);
38+
}
39+
2040
public function testItCanDetermineTheClassWhereTheDeprecationHappened()
2141
{
2242
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
@@ -118,12 +138,135 @@ public function testItTakesMutesDeprecationFromPhpUnitFiles()
118138
$this->assertTrue($deprecation->isMuted());
119139
}
120140

141+
public function providerGetTypeDetectsSelf(): array
142+
{
143+
foreach (get_declared_classes() as $class) {
144+
if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
145+
$r = new \ReflectionClass($class);
146+
$v = \dirname(\dirname($r->getFileName()));
147+
if (file_exists($v.'/composer/installed.json')) {
148+
$loader = require $v.'/autoload.php';
149+
$reflection = new \ReflectionClass($loader);
150+
$prop = $reflection->getProperty('prefixDirsPsr4');
151+
$prop->setAccessible(true);
152+
$currentValue = $prop->getValue($loader);
153+
$currentValue['Symfony\\Bridge\\PhpUnit\\'] = [realpath(__DIR__.'/../..')];
154+
$prop->setValue($loader, $currentValue);
155+
}
156+
}
157+
}
158+
159+
return [
160+
'not_from_vendors_file' => [Deprecation::TYPE_SELF, '', 'MyClass1', ''],
161+
'nonexistent_file' => [Deprecation::TYPE_UNDETERMINED, '', 'MyClass1', 'dummy_vendor_path'],
162+
'serialized_trace_with_nonexistent_triggering_file' => [
163+
Deprecation::TYPE_UNDETERMINED,
164+
serialize([
165+
'class' => '',
166+
'method' => '',
167+
'deprecation' => '',
168+
'triggering_file' => 'dummy_vendor_path',
169+
'files_stack' => [],
170+
]),
171+
SymfonyTestsListenerForV5::class,
172+
'',
173+
],
174+
];
175+
}
176+
177+
/**
178+
* @dataProvider providerGetTypeDetectsSelf
179+
*/
180+
public function testGetTypeDetectsSelf(string $expectedType, string $message, string $traceClass, string $file): void
181+
{
182+
$trace = [
183+
['class' => 'MyClass1', 'function' => 'myMethod'],
184+
['class' => $traceClass, 'function' => 'myMethod'],
185+
];
186+
$deprecation = new Deprecation($message, $trace, $file);
187+
$this->assertEquals($expectedType, $deprecation->getType());
188+
}
189+
190+
public function providerGetTypeUsesRightTrace(): array
191+
{
192+
$vendorDir = self::getVendorDir();
193+
194+
return [
195+
'no_file_in_stack' => [Deprecation::TYPE_DIRECT, '', [['function' => 'myfunc1'], ['function' => 'myfunc2']]],
196+
'files_in_stack_from_various_packages' => [
197+
Deprecation::TYPE_INDIRECT,
198+
'',
199+
[
200+
['function' => 'myfunc1', 'file' => $vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php'],
201+
['function' => 'myfunc2', 'file' => $vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php'],
202+
],
203+
],
204+
'serialized_stack_files_from_same_package' => [
205+
Deprecation::TYPE_DIRECT,
206+
serialize([
207+
'deprecation' => 'My deprecation message',
208+
'class' => 'MyClass',
209+
'method' => 'myMethod',
210+
'files_stack' => [
211+
$vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php',
212+
$vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile2.php',
213+
],
214+
]),
215+
[['function' => 'myfunc1'], ['class' => SymfonyTestsListenerForV5::class, 'method' => 'mymethod']],
216+
],
217+
'serialized_stack_files_from_various_packages' => [
218+
Deprecation::TYPE_INDIRECT,
219+
serialize([
220+
'deprecation' => 'My deprecation message',
221+
'class' => 'MyClass',
222+
'method' => 'myMethod',
223+
'files_stack' => [
224+
$vendorDir.'/myfakevendor/myfakepackage1/MyFakeFile1.php',
225+
$vendorDir.'/myfakevendor/myfakepackage2/MyFakeFile.php',
226+
],
227+
]),
228+
[['function' => 'myfunc1'], ['class' => SymfonyTestsListenerForV5::class, 'method' => 'mymethod']],
229+
],
230+
];
231+
}
232+
233+
/**
234+
* @dataProvider providerGetTypeUsesRightTrace
235+
*/
236+
public function testGetTypeUsesRightTrace(string $expectedType, string $message, array $trace): void
237+
{
238+
$deprecation = new Deprecation(
239+
$message,
240+
$trace,
241+
self::getVendorDir().'/myfakevendor/myfakepackage2/MyFakeFile.php'
242+
);
243+
$this->assertEquals($expectedType, $deprecation->getType());
244+
}
245+
121246
/**
122247
* This method is here to simulate the extra level from the piece of code
123-
* triggering an error to the error handler
248+
* triggering an error to the error handler.
124249
*/
125250
public function debugBacktrace(): array
126251
{
127252
return debug_backtrace();
128253
}
254+
255+
private static function removeDir($dir): void
256+
{
257+
$files = glob($dir.'/*');
258+
foreach ($files as $file) {
259+
if (is_file($file)) {
260+
unlink($file);
261+
} else {
262+
self::removeDir($file);
263+
}
264+
}
265+
rmdir($dir);
266+
}
267+
268+
public static function tearDownAfterClass(): void
269+
{
270+
self::removeDir(self::getVendorDir().'/myfakevendor');
271+
}
129272
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy