8000 bug #33820 [PhpUnitBridge] Fix some errors when using serialized depr… · symfony/symfony@84d32ac · GitHub
[go: up one dir, main page]

Skip to content

Commit 84d32ac

Browse files
bug #33820 [PhpUnitBridge] Fix some errors when using serialized deprecations (l-vo)
This PR was submitted for the 4.3 branch but it was squashed and merged into the 4.4 branch instead. Discussion ---------- [PhpUnitBridge] Fix some errors when using serialized deprecations | Q | A | ------------- | --- | Branch? | 4.3 | Bug fix? | yes | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | n/a | License | MIT | Doc PR | n/a This PR attempts to fix conflicts that arose in #31478 Creating as a draft for now as I think having separate test methods no longer make sense (`isSelf()` and `isIndirect()` have been replaced with `getType()`). @l-vo please review and confirm I did not loose anything valuable from your original contribution. Commits ------- 056d598 [PhpUnitBridge] Fix some errors when using serialized deprecations
2 parents 3750988 + 056d598 commit 84d32ac

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)
0