11
11
12
12
namespace Symfony \Bridge \PhpUnit \Tests \DeprecationErrorHandler ;
13
13
14
+ use App \Services \AppService ;
14
15
use PHPUnit \Framework \TestCase ;
15
16
use Symfony \Bridge \PhpUnit \DeprecationErrorHandler ;
16
17
use Symfony \Bridge \PhpUnit \DeprecationErrorHandler \Deprecation ;
17
18
use Symfony \Bridge \PhpUnit \Legacy \SymfonyTestsListenerForV5 ;
18
19
use Symfony \Bridge \PhpUnit \SetUpTearDownTrait ;
20
+ use Symfony \Bridge \PhpUnit \Tests \TestUtils \FakeVendor ;
21
+ use Symfony \Component \Filesystem \Filesystem ;
19
22
20
23
class DeprecationTest extends TestCase
21
24
{
22
25
use SetUpTearDownTrait;
23
26
24
- private static $ vendorDir ;
25
- private static $ prefixDirsPsr4 ;
27
+ /**
28
+ * @var FakeVendor
29
+ */
30
+ private static $ fakeVendor ;
26
31
27
32
private static function getVendorDir ()
28
33
{
29
- if (null !== self ::$ vendorDir ) {
30
- return self ::$ vendorDir ;
34
+ if (null !== self ::$ fakeVendor ) {
35
+ return self ::$ fakeVendor -> getRootDir () ;
31
36
}
32
37
33
- foreach (get_declared_classes () as $ class ) {
34
- if ('C ' === $ class [0 ] && 0 === strpos ($ class , 'ComposerAutoloaderInit ' )) {
35
- $ r = new \ReflectionClass ($ class );
36
- $ vendorDir = \dirname (\dirname ($ r ->getFileName ()));
37
- if (file_exists ($ vendorDir .'/composer/installed.json ' ) && @mkdir ($ vendorDir .'/myfakevendor/myfakepackage1 ' , 0777 , true )) {
38
- break ;
39
- }
40
- }
41
- }
38
+ self ::$ fakeVendor = FakeVendor::create ()
39
+ ->addPackage (null , 'myfakevendor ' , 'myfakepackage1 ' , 'Fake \\Package1 \\' )
40
+ ->addPackage (null , 'myfakevendor ' , 'myfakepackage2 ' , 'Fake \\Package2 \\' )
41
+ ->generate ();
42
+ $ rootDir = self ::$ fakeVendor ->getRootDir ();
42
43
43
- self ::$ vendorDir = $ vendorDir ;
44
- mkdir ($ vendorDir .'/myfakevendor/myfakepackage2 ' );
45
- touch ($ vendorDir .'/myfakevendor/myfakepackage1/MyFakeFile1.php ' );
46
- touch ($ vendorDir .'/myfakevendor/myfakepackage1/MyFakeFile2.php ' );
47
- touch ($ vendorDir .'/myfakevendor/myfakepackage2/MyFakeFile.php ' );
44
+ $ fs = new Filesystem ();
45
+ $ fs ->mkdir ([
46
+ $ rootDir .'/myfakevendor/myfakepackage1 ' ,
47
+ $ rootDir .'/myfakevendor/myfakepackage2 ' ,
48
+ ]);
49
+ $ fs ->touch ([
50
+ $ rootDir .'/myfakevendor/myfakepackage1/MyFakeFile1.php ' ,
51
+ $ rootDir .'/myfakevendor/myfakepackage1/MyFakeFile2.php ' ,
52
+ $ rootDir .'/myfakevendor/myfakepackage2/MyFakeFile.php ' ,
53
+ ]);
48
54
49
- return self :: $ vendorDir ;
55
+ return $ rootDir ;
50
56
}
51
57
52
58
public function testItCanDetermineTheClassWhereTheDeprecationHappened ()
@@ -231,6 +237,9 @@ public function providerGetTypeUsesRightTrace()
231
237
*/
232
238
public function testGetTypeUsesRightTrace (string $ expectedType , string $ message , array $ trace )
233
239
{
240
+ $ this ->resetStaticVendors ();
241
+ require_once self ::getVendorDir ().'/autoload.php ' ;
242
+
234
243
$ deprecation = new Deprecation (
235
244
$ message ,
236
245
$ trace ,
@@ -239,54 +248,64 @@ public function testGetTypeUsesRightTrace(string $expectedType, string $message,
239
248
$ this ->assertSame ($ expectedType , $ deprecation ->getType ());
240
249
}
241
250
242
- /**
243
- * This method is here to simulate the extra level from the piece of code
244
- * triggering an error to the error handler.
245
- */
246
- public function debugBacktrace ()
251
+ private function resetStaticVendors ()
247
252
{
248
- return debug_backtrace ();
253
+ $ reflectionClass = new \ReflectionClass (Deprecation::class);
254
+ $ vendorsProp = $ reflectionClass ->getProperty ('vendors ' );
255
+ $ vendorsProp ->setAccessible (true );
256
+ $ vendorsProp ->setValue (null );
249
257
}
250
258
251
- private static function removeDir ( $ dir )
259
+ public function testWithMultipleVendorDirs ( )
252
260
{
253
- $ files = glob ($ dir .'/* ' );
254
- foreach ($ files as $ file ) {
255
- if (is_file ($ file )) {
256
- unlink ($ file );
257
- } else {
258
- self ::removeDir ($ file );
261
+ $ this ->resetStaticVendors ();
262
+
263
+ $ changed = null ;
264
+ try {
265
+ $ sut = new DeprecationErrorHandler ();
266
+ $ changed = set_error_handler ([$ sut , 'handleError ' ]);
267
+
268
+ $ fakeVendor1 = FakeVendor::create ()
269
+ ->addPsr4Dir (__DIR__ .'/../Fixtures/fake_app ' , 'App \\Services \\' )
270
+ ->addPackage (__DIR__ .'/fake_vendor/acme/lib ' , 'acme ' , 'lib ' , 'acme \\lib \\' )
271
+ ->generate ();
272
+
273
+ require $ fakeVendor1 ->getRootDir ().'/autoload.php ' ;
274
+
275
+ $ fakeVendor2 = FakeVendor::create ()
276
+ ->addPackage (__DIR__ .'/fake_vendor/foo/lib ' , 'foo ' , 'lib ' , 'foo \\lib \\' )
277
+ ->generate ();
278
+
279
+ require $ fakeVendor2 ->getRootDir ().'/autoload.php ' ;
280
+
281
+ (new AppService ())->directDeprecations ();
282
+
283
+ ob_start ();
284
+ $ sut ->shutdown ();
285
+ $ deprecations = ob_get_clean ();
286
+ $ this ->assertStringContainsString ('Remaining direct deprecation notices (2) ' , $ deprecations );
287
+ } finally {
288
+ $ fakeVendor1 ->clear ();
289
+ $ fakeVendor2 ->clear ();
290
+ if ($ changed ) {
291
+ restore_error_handler ();
259
292
}
260
293
}
261
- rmdir ($ dir );
262
294
}
263
295
264
- private static function doSetupBeforeClass ()
296
+ /**
297
+ * This method is here to simulate the extra level from the piece of code
298
+ * triggering an error to the error handler.
299
+ */
300
+ public function debugBacktrace ()
265
301
{
266
- foreach (get_declared_classes () as $ class ) {
267
- if ('C ' === $ class [0 ] && 0 === strpos ($ class , 'ComposerAutoloaderInit ' )) {
268
- $ r = new \ReflectionClass ($ class );
269
- $ v = \dirname (\dirname ($ r ->getFileName ()));
270
- if (file_exists ($ v .'/composer/installed.json ' )) {
271
- $ loader = require $ v .'/autoload.php ' ;
272
- $ reflection = new \ReflectionClass ($ loader );
273
- $ prop = $ reflection ->getProperty ('prefixDirsPsr4 ' );
274
- $ prop ->setAccessible (true );
275
- $ currentValue = $ prop ->getValue ($ loader );
276
- self ::$ prefixDirsPsr4 [] = [$ prop , $ loader , $ currentValue ];
277
- $ currentValue ['Symfony \\Bridge \\PhpUnit \\' ] = [realpath (__DIR__ .'/../.. ' )];
278
- $ prop ->setValue ($ loader , $ currentValue );
279
- }
280
- }
281
- }
302
+ return debug_backtrace ();
282
303
}
283
304
284
305
private static function doTearDownAfterClass ()
285
306
{
286
- foreach (self ::$ prefixDirsPsr4 as [ $ prop , $ loader , $ prefixDirsPsr4 ] ) {
287
- $ prop -> setValue ( $ loader , $ prefixDirsPsr4 );
307
+ if (self ::$ fakeVendor ) {
308
+ self :: $ fakeVendor -> clear ( );
288
309
}
289
-
290
- self ::removeDir (self ::getVendorDir ().'/myfakevendor ' );
291
310
}
292
311
}