Updating Media dependent modules to versions compatible with core Media.
[yaffs-website] / vendor / symfony / debug / Tests / ErrorHandlerTest.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 Psr\Log\LogLevel;
16 use Symfony\Component\Debug\BufferingLogger;
17 use Symfony\Component\Debug\ErrorHandler;
18 use Symfony\Component\Debug\Exception\SilencedErrorContext;
19
20 /**
21  * ErrorHandlerTest.
22  *
23  * @author Robert Schönthal <seroscho@googlemail.com>
24  * @author Nicolas Grekas <p@tchwork.com>
25  */
26 class ErrorHandlerTest extends TestCase
27 {
28     public function testRegister()
29     {
30         $handler = ErrorHandler::register();
31
32         try {
33             $this->assertInstanceOf('Symfony\Component\Debug\ErrorHandler', $handler);
34             $this->assertSame($handler, ErrorHandler::register());
35
36             $newHandler = new ErrorHandler();
37
38             $this->assertSame($handler, ErrorHandler::register($newHandler, false));
39             $h = set_error_handler('var_dump');
40             restore_error_handler();
41             $this->assertSame(array($handler, 'handleError'), $h);
42
43             try {
44                 $this->assertSame($newHandler, ErrorHandler::register($newHandler, true));
45                 $h = set_error_handler('var_dump');
46                 restore_error_handler();
47                 $this->assertSame(array($newHandler, 'handleError'), $h);
48             } catch (\Exception $e) {
49             }
50
51             restore_error_handler();
52             restore_exception_handler();
53
54             if (isset($e)) {
55                 throw $e;
56             }
57         } catch (\Exception $e) {
58         }
59
60         restore_error_handler();
61         restore_exception_handler();
62
63         if (isset($e)) {
64             throw $e;
65         }
66     }
67
68     public function testErrorGetLast()
69     {
70         $handler = ErrorHandler::register();
71         $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
72         $handler->setDefaultLogger($logger);
73         $handler->screamAt(E_ALL);
74
75         try {
76             @trigger_error('Hello', E_USER_WARNING);
77             $expected = array(
78                 'type' => E_USER_WARNING,
79                 'message' => 'Hello',
80                 'file' => __FILE__,
81                 'line' => __LINE__ - 5,
82             );
83             $this->assertSame($expected, error_get_last());
84         } catch (\Exception $e) {
85             restore_error_handler();
86             restore_exception_handler();
87
88             throw $e;
89         }
90     }
91
92     public function testNotice()
93     {
94         ErrorHandler::register();
95
96         try {
97             self::triggerNotice($this);
98             $this->fail('ErrorException expected');
99         } catch (\ErrorException $exception) {
100             // if an exception is thrown, the test passed
101             $this->assertEquals(E_NOTICE, $exception->getSeverity());
102             $this->assertEquals(__FILE__, $exception->getFile());
103             $this->assertRegExp('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage());
104
105             $trace = $exception->getTrace();
106
107             $this->assertEquals(__FILE__, $trace[0]['file']);
108             $this->assertEquals(__CLASS__, $trace[0]['class']);
109             $this->assertEquals('triggerNotice', $trace[0]['function']);
110             $this->assertEquals('::', $trace[0]['type']);
111
112             $this->assertEquals(__FILE__, $trace[0]['file']);
113             $this->assertEquals(__CLASS__, $trace[1]['class']);
114             $this->assertEquals(__FUNCTION__, $trace[1]['function']);
115             $this->assertEquals('->', $trace[1]['type']);
116         } finally {
117             restore_error_handler();
118             restore_exception_handler();
119         }
120     }
121
122     // dummy function to test trace in error handler.
123     private static function triggerNotice($that)
124     {
125         $that->assertSame('', $foo.$foo.$bar);
126     }
127
128     public function testConstruct()
129     {
130         try {
131             $handler = ErrorHandler::register();
132             $handler->throwAt(3, true);
133             $this->assertEquals(3 | E_RECOVERABLE_ERROR | E_USER_ERROR, $handler->throwAt(0));
134         } finally {
135             restore_error_handler();
136             restore_exception_handler();
137         }
138     }
139
140     public function testDefaultLogger()
141     {
142         try {
143             $handler = ErrorHandler::register();
144
145             $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
146
147             $handler->setDefaultLogger($logger, E_NOTICE);
148             $handler->setDefaultLogger($logger, array(E_USER_NOTICE => LogLevel::CRITICAL));
149
150             $loggers = array(
151                 E_DEPRECATED => array(null, LogLevel::INFO),
152                 E_USER_DEPRECATED => array(null, LogLevel::INFO),
153                 E_NOTICE => array($logger, LogLevel::WARNING),
154                 E_USER_NOTICE => array($logger, LogLevel::CRITICAL),
155                 E_STRICT => array(null, LogLevel::WARNING),
156                 E_WARNING => array(null, LogLevel::WARNING),
157                 E_USER_WARNING => array(null, LogLevel::WARNING),
158                 E_COMPILE_WARNING => array(null, LogLevel::WARNING),
159                 E_CORE_WARNING => array(null, LogLevel::WARNING),
160                 E_USER_ERROR => array(null, LogLevel::CRITICAL),
161                 E_RECOVERABLE_ERROR => array(null, LogLevel::CRITICAL),
162                 E_COMPILE_ERROR => array(null, LogLevel::CRITICAL),
163                 E_PARSE => array(null, LogLevel::CRITICAL),
164                 E_ERROR => array(null, LogLevel::CRITICAL),
165                 E_CORE_ERROR => array(null, LogLevel::CRITICAL),
166             );
167             $this->assertSame($loggers, $handler->setLoggers(array()));
168         } finally {
169             restore_error_handler();
170             restore_exception_handler();
171         }
172     }
173
174     public function testHandleError()
175     {
176         try {
177             $handler = ErrorHandler::register();
178             $handler->throwAt(0, true);
179             $this->assertFalse($handler->handleError(0, 'foo', 'foo.php', 12, array()));
180
181             restore_error_handler();
182             restore_exception_handler();
183
184             $handler = ErrorHandler::register();
185             $handler->throwAt(3, true);
186             $this->assertFalse($handler->handleError(4, 'foo', 'foo.php', 12, array()));
187
188             restore_error_handler();
189             restore_exception_handler();
190
191             $handler = ErrorHandler::register();
192             $handler->throwAt(3, true);
193             try {
194                 $handler->handleError(4, 'foo', 'foo.php', 12, array());
195             } catch (\ErrorException $e) {
196                 $this->assertSame('Parse Error: foo', $e->getMessage());
197                 $this->assertSame(4, $e->getSeverity());
198                 $this->assertSame('foo.php', $e->getFile());
199                 $this->assertSame(12, $e->getLine());
200             }
201
202             restore_error_handler();
203             restore_exception_handler();
204
205             $handler = ErrorHandler::register();
206             $handler->throwAt(E_USER_DEPRECATED, true);
207             $this->assertFalse($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array()));
208
209             restore_error_handler();
210             restore_exception_handler();
211
212             $handler = ErrorHandler::register();
213             $handler->throwAt(E_DEPRECATED, true);
214             $this->assertFalse($handler->handleError(E_DEPRECATED, 'foo', 'foo.php', 12, array()));
215
216             restore_error_handler();
217             restore_exception_handler();
218
219             $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
220
221             $warnArgCheck = function ($logLevel, $message, $context) {
222                 $this->assertEquals('info', $logLevel);
223                 $this->assertEquals('User Deprecated: foo', $message);
224                 $this->assertArrayHasKey('exception', $context);
225                 $exception = $context['exception'];
226                 $this->assertInstanceOf(\ErrorException::class, $exception);
227                 $this->assertSame('User Deprecated: foo', $exception->getMessage());
228                 $this->assertSame(E_USER_DEPRECATED, $exception->getSeverity());
229             };
230
231             $logger
232                 ->expects($this->once())
233                 ->method('log')
234                 ->will($this->returnCallback($warnArgCheck))
235             ;
236
237             $handler = ErrorHandler::register();
238             $handler->setDefaultLogger($logger, E_USER_DEPRECATED);
239             $this->assertTrue($handler->handleError(E_USER_DEPRECATED, 'foo', 'foo.php', 12, array()));
240
241             restore_error_handler();
242             restore_exception_handler();
243
244             $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
245
246             $line = null;
247             $logArgCheck = function ($level, $message, $context) use (&$line) {
248                 $this->assertEquals('Notice: Undefined variable: undefVar', $message);
249                 $this->assertArrayHasKey('exception', $context);
250                 $exception = $context['exception'];
251                 $this->assertInstanceOf(SilencedErrorContext::class, $exception);
252                 $this->assertSame(E_NOTICE, $exception->getSeverity());
253                 $this->assertSame(__FILE__, $exception->getFile());
254                 $this->assertSame($line, $exception->getLine());
255                 $this->assertNotEmpty($exception->getTrace());
256                 $this->assertSame(1, $exception->count);
257             };
258
259             $logger
260                 ->expects($this->once())
261                 ->method('log')
262                 ->will($this->returnCallback($logArgCheck))
263             ;
264
265             $handler = ErrorHandler::register();
266             $handler->setDefaultLogger($logger, E_NOTICE);
267             $handler->screamAt(E_NOTICE);
268             unset($undefVar);
269             $line = __LINE__ + 1;
270             @$undefVar++;
271
272             restore_error_handler();
273             restore_exception_handler();
274         } catch (\Exception $e) {
275             restore_error_handler();
276             restore_exception_handler();
277
278             throw $e;
279         }
280     }
281
282     public function testHandleUserError()
283     {
284         try {
285             $handler = ErrorHandler::register();
286             $handler->throwAt(0, true);
287
288             $e = null;
289             $x = new \Exception('Foo');
290
291             try {
292                 $f = new Fixtures\ToStringThrower($x);
293                 $f .= ''; // Trigger $f->__toString()
294             } catch (\Exception $e) {
295             }
296
297             $this->assertSame($x, $e);
298         } finally {
299             restore_error_handler();
300             restore_exception_handler();
301         }
302     }
303
304     public function testHandleDeprecation()
305     {
306         $logArgCheck = function ($level, $message, $context) {
307             $this->assertEquals(LogLevel::INFO, $level);
308             $this->assertArrayHasKey('exception', $context);
309             $exception = $context['exception'];
310             $this->assertInstanceOf(\ErrorException::class, $exception);
311             $this->assertSame('User Deprecated: Foo deprecation', $exception->getMessage());
312         };
313
314         $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
315         $logger
316             ->expects($this->once())
317             ->method('log')
318             ->will($this->returnCallback($logArgCheck))
319         ;
320
321         $handler = new ErrorHandler();
322         $handler->setDefaultLogger($logger);
323         @$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, array());
324     }
325
326     /**
327      * @group no-hhvm
328      */
329     public function testHandleException()
330     {
331         try {
332             $handler = ErrorHandler::register();
333
334             $exception = new \Exception('foo');
335
336             $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
337
338             $logArgCheck = function ($level, $message, $context) {
339                 $this->assertSame('Uncaught Exception: foo', $message);
340                 $this->assertArrayHasKey('exception', $context);
341                 $this->assertInstanceOf(\Exception::class, $context['exception']);
342             };
343
344             $logger
345                 ->expects($this->exactly(2))
346                 ->method('log')
347                 ->will($this->returnCallback($logArgCheck))
348             ;
349
350             $handler->setDefaultLogger($logger, E_ERROR);
351
352             try {
353                 $handler->handleException($exception);
354                 $this->fail('Exception expected');
355             } catch (\Exception $e) {
356                 $this->assertSame($exception, $e);
357             }
358
359             $handler->setExceptionHandler(function ($e) use ($exception) {
360                 $this->assertSame($exception, $e);
361             });
362
363             $handler->handleException($exception);
364         } finally {
365             restore_error_handler();
366             restore_exception_handler();
367         }
368     }
369
370     /**
371      * @group legacy
372      */
373     public function testErrorStacking()
374     {
375         try {
376             $handler = ErrorHandler::register();
377             $handler->screamAt(E_USER_WARNING);
378
379             $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
380
381             $logger
382                 ->expects($this->exactly(2))
383                 ->method('log')
384                 ->withConsecutive(
385                     array($this->equalTo(LogLevel::WARNING), $this->equalTo('Dummy log')),
386                     array($this->equalTo(LogLevel::DEBUG), $this->equalTo('User Warning: Silenced warning'))
387                 )
388             ;
389
390             $handler->setDefaultLogger($logger, array(E_USER_WARNING => LogLevel::WARNING));
391
392             ErrorHandler::stackErrors();
393             @trigger_error('Silenced warning', E_USER_WARNING);
394             $logger->log(LogLevel::WARNING, 'Dummy log');
395             ErrorHandler::unstackErrors();
396         } finally {
397             restore_error_handler();
398             restore_exception_handler();
399         }
400     }
401
402     public function testBootstrappingLogger()
403     {
404         $bootLogger = new BufferingLogger();
405         $handler = new ErrorHandler($bootLogger);
406
407         $loggers = array(
408             E_DEPRECATED => array($bootLogger, LogLevel::INFO),
409             E_USER_DEPRECATED => array($bootLogger, LogLevel::INFO),
410             E_NOTICE => array($bootLogger, LogLevel::WARNING),
411             E_USER_NOTICE => array($bootLogger, LogLevel::WARNING),
412             E_STRICT => array($bootLogger, LogLevel::WARNING),
413             E_WARNING => array($bootLogger, LogLevel::WARNING),
414             E_USER_WARNING => array($bootLogger, LogLevel::WARNING),
415             E_COMPILE_WARNING => array($bootLogger, LogLevel::WARNING),
416             E_CORE_WARNING => array($bootLogger, LogLevel::WARNING),
417             E_USER_ERROR => array($bootLogger, LogLevel::CRITICAL),
418             E_RECOVERABLE_ERROR => array($bootLogger, LogLevel::CRITICAL),
419             E_COMPILE_ERROR => array($bootLogger, LogLevel::CRITICAL),
420             E_PARSE => array($bootLogger, LogLevel::CRITICAL),
421             E_ERROR => array($bootLogger, LogLevel::CRITICAL),
422             E_CORE_ERROR => array($bootLogger, LogLevel::CRITICAL),
423         );
424
425         $this->assertSame($loggers, $handler->setLoggers(array()));
426
427         $handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, array());
428
429         $logs = $bootLogger->cleanLogs();
430
431         $this->assertCount(1, $logs);
432         $log = $logs[0];
433         $this->assertSame('info', $log[0]);
434         $this->assertSame('Deprecated: Foo message', $log[1]);
435         $this->assertArrayHasKey('exception', $log[2]);
436         $exception = $log[2]['exception'];
437         $this->assertInstanceOf(\ErrorException::class, $exception);
438         $this->assertSame('Deprecated: Foo message', $exception->getMessage());
439         $this->assertSame(__FILE__, $exception->getFile());
440         $this->assertSame(123, $exception->getLine());
441         $this->assertSame(E_DEPRECATED, $exception->getSeverity());
442
443         $bootLogger->log(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
444
445         $mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
446         $mockLogger->expects($this->once())
447             ->method('log')
448             ->with(LogLevel::WARNING, 'Foo message', array('exception' => $exception));
449
450         $handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING)));
451     }
452
453     /**
454      * @group no-hhvm
455      */
456     public function testSettingLoggerWhenExceptionIsBuffered()
457     {
458         $bootLogger = new BufferingLogger();
459         $handler = new ErrorHandler($bootLogger);
460
461         $exception = new \Exception('Foo message');
462
463         $mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
464         $mockLogger->expects($this->once())
465             ->method('log')
466             ->with(LogLevel::CRITICAL, 'Uncaught Exception: Foo message', array('exception' => $exception));
467
468         $handler->setExceptionHandler(function () use ($handler, $mockLogger) {
469             $handler->setDefaultLogger($mockLogger);
470         });
471
472         $handler->handleException($exception);
473     }
474
475     /**
476      * @group no-hhvm
477      */
478     public function testHandleFatalError()
479     {
480         try {
481             $handler = ErrorHandler::register();
482
483             $error = array(
484                 'type' => E_PARSE,
485                 'message' => 'foo',
486                 'file' => 'bar',
487                 'line' => 123,
488             );
489
490             $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
491
492             $logArgCheck = function ($level, $message, $context) {
493                 $this->assertEquals('Fatal Parse Error: foo', $message);
494                 $this->assertArrayHasKey('exception', $context);
495                 $this->assertInstanceOf(\Exception::class, $context['exception']);
496             };
497
498             $logger
499                 ->expects($this->once())
500                 ->method('log')
501                 ->will($this->returnCallback($logArgCheck))
502             ;
503
504             $handler->setDefaultLogger($logger, E_PARSE);
505
506             $handler->handleFatalError($error);
507
508             restore_error_handler();
509             restore_exception_handler();
510         } catch (\Exception $e) {
511             restore_error_handler();
512             restore_exception_handler();
513
514             throw $e;
515         }
516     }
517
518     /**
519      * @requires PHP 7
520      */
521     public function testHandleErrorException()
522     {
523         $exception = new \Error("Class 'Foo' not found");
524
525         $handler = new ErrorHandler();
526         $handler->setExceptionHandler(function () use (&$args) {
527             $args = func_get_args();
528         });
529
530         $handler->handleException($exception);
531
532         $this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]);
533         $this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
534     }
535
536     /**
537      * @group no-hhvm
538      */
539     public function testHandleFatalErrorOnHHVM()
540     {
541         try {
542             $handler = ErrorHandler::register();
543
544             $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
545             $logger
546                 ->expects($this->once())
547                 ->method('log')
548                 ->with(
549                     $this->equalTo(LogLevel::CRITICAL),
550                     $this->equalTo('Fatal Error: foo')
551                 )
552             ;
553
554             $handler->setDefaultLogger($logger, E_ERROR);
555
556             $error = array(
557                 'type' => E_ERROR + 0x1000000, // This error level is used by HHVM for fatal errors
558                 'message' => 'foo',
559                 'file' => 'bar',
560                 'line' => 123,
561                 'context' => array(123),
562                 'backtrace' => array(456),
563             );
564
565             call_user_func_array(array($handler, 'handleError'), $error);
566             $handler->handleFatalError($error);
567         } finally {
568             restore_error_handler();
569             restore_exception_handler();
570         }
571     }
572
573     /**
574      * @expectedException \Exception
575      * @group no-hhvm
576      */
577     public function testCustomExceptionHandler()
578     {
579         $handler = new ErrorHandler();
580         $handler->setExceptionHandler(function ($e) use ($handler) {
581             $handler->handleException($e);
582         });
583
584         $handler->handleException(new \Exception());
585     }
586 }