196b92c884598286c8d51a140e9f9bd58aa6992d
[yaffs-website] / vendor / symfony / debug / Tests / DebugClassLoaderTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\Debug\Tests;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Debug\DebugClassLoader;
16 use Symfony\Component\Debug\ErrorHandler;
17
18 class DebugClassLoaderTest extends TestCase
19 {
20     /**
21      * @var int Error reporting level before running tests
22      */
23     private $errorReporting;
24
25     private $loader;
26
27     protected function setUp()
28     {
29         $this->errorReporting = error_reporting(E_ALL | E_STRICT);
30         $this->loader = new ClassLoader();
31         spl_autoload_register(array($this->loader, 'loadClass'), true, true);
32         DebugClassLoader::enable();
33     }
34
35     protected function tearDown()
36     {
37         DebugClassLoader::disable();
38         spl_autoload_unregister(array($this->loader, 'loadClass'));
39         error_reporting($this->errorReporting);
40     }
41
42     public function testIdempotence()
43     {
44         DebugClassLoader::enable();
45
46         $functions = spl_autoload_functions();
47         foreach ($functions as $function) {
48             if (is_array($function) && $function[0] instanceof DebugClassLoader) {
49                 $reflClass = new \ReflectionClass($function[0]);
50                 $reflProp = $reflClass->getProperty('classLoader');
51                 $reflProp->setAccessible(true);
52
53                 $this->assertNotInstanceOf('Symfony\Component\Debug\DebugClassLoader', $reflProp->getValue($function[0]));
54
55                 return;
56             }
57         }
58
59         $this->fail('DebugClassLoader did not register');
60     }
61
62     public function testUnsilencing()
63     {
64         if (\PHP_VERSION_ID >= 70000) {
65             $this->markTestSkipped('PHP7 throws exceptions, unsilencing is not required anymore.');
66         }
67         if (defined('HHVM_VERSION')) {
68             $this->markTestSkipped('HHVM is not handled in this test case.');
69         }
70
71         ob_start();
72
73         $this->iniSet('log_errors', 0);
74         $this->iniSet('display_errors', 1);
75
76         // See below: this will fail with parse error
77         // but this should not be @-silenced.
78         @class_exists(__NAMESPACE__.'\TestingUnsilencing', true);
79
80         $output = ob_get_clean();
81
82         $this->assertStringMatchesFormat('%aParse error%a', $output);
83     }
84
85     public function testStacking()
86     {
87         // the ContextErrorException must not be loaded to test the workaround
88         // for https://bugs.php.net/65322.
89         if (class_exists('Symfony\Component\Debug\Exception\ContextErrorException', false)) {
90             $this->markTestSkipped('The ContextErrorException class is already loaded.');
91         }
92         if (defined('HHVM_VERSION')) {
93             $this->markTestSkipped('HHVM is not handled in this test case.');
94         }
95
96         ErrorHandler::register();
97
98         try {
99             // Trigger autoloading + E_STRICT at compile time
100             // which in turn triggers $errorHandler->handle()
101             // that again triggers autoloading for ContextErrorException.
102             // Error stacking works around the bug above and everything is fine.
103
104             eval('
105                 namespace '.__NAMESPACE__.';
106                 class ChildTestingStacking extends TestingStacking { function foo($bar) {} }
107             ');
108             $this->fail('ContextErrorException expected');
109         } catch (\ErrorException $exception) {
110             // if an exception is thrown, the test passed
111             restore_error_handler();
112             restore_exception_handler();
113             $this->assertStringStartsWith(__FILE__, $exception->getFile());
114             if (\PHP_VERSION_ID < 70000) {
115                 $this->assertRegExp('/^Runtime Notice: Declaration/', $exception->getMessage());
116                 $this->assertEquals(E_STRICT, $exception->getSeverity());
117             } else {
118                 $this->assertRegExp('/^Warning: Declaration/', $exception->getMessage());
119                 $this->assertEquals(E_WARNING, $exception->getSeverity());
120             }
121         } catch (\Exception $exception) {
122             restore_error_handler();
123             restore_exception_handler();
124
125             throw $exception;
126         }
127     }
128
129     /**
130      * @expectedException \RuntimeException
131      */
132     public function testNameCaseMismatch()
133     {
134         class_exists(__NAMESPACE__.'\TestingCaseMismatch', true);
135     }
136
137     /**
138      * @expectedException \RuntimeException
139      * @expectedExceptionMessage Case mismatch between class and real file names
140      */
141     public function testFileCaseMismatch()
142     {
143         if (!file_exists(__DIR__.'/Fixtures/CaseMismatch.php')) {
144             $this->markTestSkipped('Can only be run on case insensitive filesystems');
145         }
146
147         class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true);
148     }
149
150     /**
151      * @expectedException \RuntimeException
152      */
153     public function testPsr4CaseMismatch()
154     {
155         class_exists(__NAMESPACE__.'\Fixtures\Psr4CaseMismatch', true);
156     }
157
158     public function testNotPsr0()
159     {
160         $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\NotPSR0', true));
161     }
162
163     public function testNotPsr0Bis()
164     {
165         $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\NotPSR0bis', true));
166     }
167
168     public function testClassAlias()
169     {
170         $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\ClassAlias', true));
171     }
172
173     /**
174      * @dataProvider provideDeprecatedSuper
175      */
176     public function testDeprecatedSuper($class, $super, $type)
177     {
178         set_error_handler(function () { return false; });
179         $e = error_reporting(0);
180         trigger_error('', E_USER_DEPRECATED);
181
182         class_exists('Test\\'.__NAMESPACE__.'\\'.$class, true);
183
184         error_reporting($e);
185         restore_error_handler();
186
187         $lastError = error_get_last();
188         unset($lastError['file'], $lastError['line']);
189
190         $xError = array(
191             'type' => E_USER_DEPRECATED,
192             'message' => 'The Test\Symfony\Component\Debug\Tests\\'.$class.' class '.$type.' Symfony\Component\Debug\Tests\Fixtures\\'.$super.' that is deprecated but this is a test deprecation notice.',
193         );
194
195         $this->assertSame($xError, $lastError);
196     }
197
198     public function provideDeprecatedSuper()
199     {
200         return array(
201             array('DeprecatedInterfaceClass', 'DeprecatedInterface', 'implements'),
202             array('DeprecatedParentClass', 'DeprecatedClass', 'extends'),
203         );
204     }
205
206     public function testInterfaceExtendsDeprecatedInterface()
207     {
208         set_error_handler(function () { return false; });
209         $e = error_reporting(0);
210         trigger_error('', E_USER_NOTICE);
211
212         class_exists('Test\\'.__NAMESPACE__.'\\NonDeprecatedInterfaceClass', true);
213
214         error_reporting($e);
215         restore_error_handler();
216
217         $lastError = error_get_last();
218         unset($lastError['file'], $lastError['line']);
219
220         $xError = array(
221             'type' => E_USER_NOTICE,
222             'message' => '',
223         );
224
225         $this->assertSame($xError, $lastError);
226     }
227
228     public function testDeprecatedSuperInSameNamespace()
229     {
230         set_error_handler(function () { return false; });
231         $e = error_reporting(0);
232         trigger_error('', E_USER_NOTICE);
233
234         class_exists('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent', true);
235
236         error_reporting($e);
237         restore_error_handler();
238
239         $lastError = error_get_last();
240         unset($lastError['file'], $lastError['line']);
241
242         $xError = array(
243             'type' => E_USER_NOTICE,
244             'message' => '',
245         );
246
247         $this->assertSame($xError, $lastError);
248     }
249
250     public function testReservedForPhp7()
251     {
252         if (\PHP_VERSION_ID >= 70000) {
253             $this->markTestSkipped('PHP7 already prevents using reserved names.');
254         }
255
256         set_error_handler(function () { return false; });
257         $e = error_reporting(0);
258         trigger_error('', E_USER_NOTICE);
259
260         class_exists('Test\\'.__NAMESPACE__.'\\Float', true);
261
262         error_reporting($e);
263         restore_error_handler();
264
265         $lastError = error_get_last();
266         unset($lastError['file'], $lastError['line']);
267
268         $xError = array(
269             'type' => E_USER_DEPRECATED,
270             'message' => 'Test\Symfony\Component\Debug\Tests\Float uses a reserved class name (Float) that will break on PHP 7 and higher',
271         );
272
273         $this->assertSame($xError, $lastError);
274     }
275 }
276
277 class ClassLoader
278 {
279     public function loadClass($class)
280     {
281     }
282
283     public function getClassMap()
284     {
285         return array(__NAMESPACE__.'\Fixtures\NotPSR0bis' => __DIR__.'/Fixtures/notPsr0Bis.php');
286     }
287
288     public function findFile($class)
289     {
290         $fixtureDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR;
291
292         if (__NAMESPACE__.'\TestingUnsilencing' === $class) {
293             eval('-- parse error --');
294         } elseif (__NAMESPACE__.'\TestingStacking' === $class) {
295             eval('namespace '.__NAMESPACE__.'; class TestingStacking { function foo() {} }');
296         } elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) {
297             eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}');
298         } elseif (__NAMESPACE__.'\Fixtures\CaseMismatch' === $class) {
299             return $fixtureDir.'CaseMismatch.php';
300         } elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) {
301             return $fixtureDir.'psr4'.DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php';
302         } elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) {
303             return $fixtureDir.'reallyNotPsr0.php';
304         } elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) {
305             return $fixtureDir.'notPsr0Bis.php';
306         } elseif (__NAMESPACE__.'\Fixtures\DeprecatedInterface' === $class) {
307             return $fixtureDir.'DeprecatedInterface.php';
308         } elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) {
309             eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
310         } elseif ('Test\\'.__NAMESPACE__.'\DeprecatedParentClass' === $class) {
311             eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedParentClass extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}');
312         } elseif ('Test\\'.__NAMESPACE__.'\DeprecatedInterfaceClass' === $class) {
313             eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\DeprecatedInterface {}');
314         } elseif ('Test\\'.__NAMESPACE__.'\NonDeprecatedInterfaceClass' === $class) {
315             eval('namespace Test\\'.__NAMESPACE__.'; class NonDeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\NonDeprecatedInterface {}');
316         } elseif ('Test\\'.__NAMESPACE__.'\Float' === $class) {
317             eval('namespace Test\\'.__NAMESPACE__.'; class Float {}');
318         }
319     }
320 }