2011-03-05 19:23:35 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2011-03-05 19:23:35 +00:00
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
2013-03-20 17:09:46 +00:00
namespace Symfony\Component\Debug\Tests ;
2011-03-05 19:23:35 +00:00
2013-03-20 17:09:46 +00:00
use Symfony\Component\Debug\ErrorHandler ;
2013-11-28 16:41:31 +00:00
use Symfony\Component\Debug\Exception\DummyException ;
2011-03-05 19:23:35 +00:00
/**
* ErrorHandlerTest
*
* @ author Robert Schönthal < seroscho @ googlemail . com >
*/
class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
{
2013-11-05 20:12:21 +00:00
/**
* @ var int Error reporting level before running tests .
*/
protected $errorReporting ;
/**
* @ var string Display errors setting before running tests .
*/
protected $displayErrors ;
public function setUp () {
$this -> errorReporting = error_reporting ( E_ALL | E_STRICT );
$this -> displayErrors = ini_get ( 'display_errors' );
ini_set ( 'display_errors' , '1' );
}
public function tearDown () {
ini_set ( 'display_errors' , $this -> displayErrors );
error_reporting ( $this -> errorReporting );
}
2013-08-07 14:15:14 +01:00
public function testCompileTimeError ()
{
2013-11-05 20:12:21 +00:00
// the ContextErrorException must not be loaded to test the workaround
// for https://bugs.php.net/bug.php?id=65322.
2013-08-07 14:15:14 +01:00
if ( class_exists ( 'Symfony\Component\Debug\Exception\ContextErrorException' , false )) {
$this -> markTestSkipped ( 'The ContextErrorException class is already loaded.' );
}
2013-10-30 08:30:20 +00:00
2013-11-28 10:16:43 +00:00
$exceptionHandler = $this -> getMock ( 'Symfony\Component\Debug\ExceptionHandler' , array ( 'handle' ));
// the following code forces some PHPUnit classes to be loaded
// so that they will be available in the exception handler
// as they won't be autoloaded by PHP
class_exists ( 'PHPUnit_Framework_MockObject_Invocation_Object' );
$this -> assertInstanceOf ( 'stdClass' , new \stdClass ());
$this -> assertEquals ( 1 , 1 );
$this -> assertStringStartsWith ( 'foo' , 'foobar' );
$this -> assertArrayHasKey ( 'bar' , array ( 'bar' => 'foo' ));
2013-11-05 20:12:21 +00:00
$that = $this ;
2013-11-28 10:16:43 +00:00
$exceptionCheck = function ( $exception ) use ( $that ) {
2013-11-05 20:12:21 +00:00
$that -> assertInstanceOf ( 'Symfony\Component\Debug\Exception\ContextErrorException' , $exception );
$that -> assertEquals ( E_STRICT , $exception -> getSeverity ());
$that -> assertEquals ( 2 , $exception -> getLine ());
2013-11-28 10:16:43 +00:00
$that -> assertStringStartsWith ( 'Runtime Notice: Declaration of _CompileTimeError::foo() should be compatible with' , $exception -> getMessage ());
2013-11-05 20:12:21 +00:00
$that -> assertArrayHasKey ( 'bar' , $exception -> getContext ());
};
2013-08-07 14:15:14 +01:00
2013-11-05 20:12:21 +00:00
$exceptionHandler -> expects ( $this -> once ())
-> method ( 'handle' )
2013-11-28 10:16:43 +00:00
-> will ( $this -> returnCallback ( $exceptionCheck ))
;
2013-08-07 14:15:14 +01:00
2013-11-05 20:12:21 +00:00
ErrorHandler :: register ();
2013-11-28 10:16:43 +00:00
set_exception_handler ( array ( $exceptionHandler , 'handle' ));
2013-11-05 20:12:21 +00:00
// dummy variable to check for in error handler.
$bar = 123 ;
// trigger compile time error
2013-11-28 16:41:31 +00:00
try {
eval ( <<< 'PHP'
2013-08-07 14:15:14 +01:00
class _BaseCompileTimeError { function foo () {} }
class _CompileTimeError extends _BaseCompileTimeError { function foo ( $invalid ) {} }
PHP
2013-11-28 16:41:31 +00:00
);
} catch ( DummyException $e ) {
// if an exception is thrown, the test passed
2013-12-11 15:16:31 +00:00
} catch ( \Exception $e ) {
restore_error_handler ();
restore_exception_handler ();
throw $e ;
2013-11-28 16:41:31 +00:00
}
2013-08-07 14:15:14 +01:00
restore_error_handler ();
2013-11-28 10:16:43 +00:00
restore_exception_handler ();
2013-11-05 20:12:21 +00:00
}
public function testNotice ()
{
$exceptionHandler = $this -> getMock ( 'Symfony\Component\Debug\ExceptionHandler' , array ( 'handle' ));
set_exception_handler ( array ( $exceptionHandler , 'handle' ));
$that = $this ;
$exceptionCheck = function ( $exception ) use ( $that ) {
$that -> assertInstanceOf ( 'Symfony\Component\Debug\Exception\ContextErrorException' , $exception );
$that -> assertEquals ( E_NOTICE , $exception -> getSeverity ());
2013-11-28 16:41:31 +00:00
$that -> assertEquals ( __LINE__ + 40 , $exception -> getLine ());
2013-11-05 20:12:21 +00:00
$that -> assertEquals ( __FILE__ , $exception -> getFile ());
$that -> assertRegexp ( '/^Notice: Undefined variable: (foo|bar)/' , $exception -> getMessage ());
$that -> assertArrayHasKey ( 'foobar' , $exception -> getContext ());
$trace = $exception -> getTrace ();
$that -> assertEquals ( __FILE__ , $trace [ 0 ][ 'file' ]);
$that -> assertEquals ( 'Symfony\Component\Debug\ErrorHandler' , $trace [ 0 ][ 'class' ]);
$that -> assertEquals ( 'handle' , $trace [ 0 ][ 'function' ]);
$that -> assertEquals ( '->' , $trace [ 0 ][ 'type' ]);
$that -> assertEquals ( __FILE__ , $trace [ 1 ][ 'file' ]);
$that -> assertEquals ( __CLASS__ , $trace [ 1 ][ 'class' ]);
$that -> assertEquals ( 'triggerNotice' , $trace [ 1 ][ 'function' ]);
$that -> assertEquals ( '::' , $trace [ 1 ][ 'type' ]);
$that -> assertEquals ( __CLASS__ , $trace [ 2 ][ 'class' ]);
$that -> assertEquals ( 'testNotice' , $trace [ 2 ][ 'function' ]);
$that -> assertEquals ( '->' , $trace [ 2 ][ 'type' ]);
};
2013-11-28 16:41:31 +00:00
$exceptionHandler -> expects ( $this -> once ())
2013-11-05 20:12:21 +00:00
-> method ( 'handle' )
-> will ( $this -> returnCallback ( $exceptionCheck ));
ErrorHandler :: register ();
2013-11-28 16:41:31 +00:00
try {
self :: triggerNotice ( $this );
} catch ( DummyException $e ) {
// if an exception is thrown, the test passed
2013-12-11 15:16:31 +00:00
} catch ( \Exception $e ) {
restore_error_handler ();
throw $e ;
2013-11-28 16:41:31 +00:00
}
2013-08-07 14:15:14 +01:00
restore_error_handler ();
}
2011-04-15 20:12:02 +01:00
2013-11-05 20:12:21 +00:00
// dummy function to test trace in error handler.
2013-11-28 10:16:43 +00:00
private static function triggerNotice ( $that )
{
2013-11-05 20:12:21 +00:00
// dummy variable to check for in error handler.
$foobar = 123 ;
2013-11-28 10:16:43 +00:00
$that -> assertSame ( '' , $foo . $foo . $bar );
2013-08-07 14:15:14 +01:00
}
2011-04-15 20:12:02 +01:00
2011-03-05 19:23:35 +00:00
public function testConstruct ()
{
2013-12-11 15:16:31 +00:00
try {
$handler = ErrorHandler :: register ( 3 );
2011-04-15 20:12:02 +01:00
2013-12-11 15:16:31 +00:00
$level = new \ReflectionProperty ( $handler , 'level' );
$level -> setAccessible ( true );
2011-04-15 20:12:02 +01:00
2013-12-11 15:16:31 +00:00
$this -> assertEquals ( 3 , $level -> getValue ( $handler ));
2011-04-15 20:12:02 +01:00
2013-12-11 15:16:31 +00:00
restore_error_handler ();
} catch ( \Exception $e ) {
restore_error_handler ();
throw $e ;
}
2011-03-05 19:23:35 +00:00
}
public function testHandle ()
{
2013-12-11 15:16:31 +00:00
try {
$handler = ErrorHandler :: register ( 0 );
$this -> assertFalse ( $handler -> handle ( 0 , 'foo' , 'foo.php' , 12 , 'foo' ));
2011-05-05 07:46:20 +01:00
2013-12-11 15:16:31 +00:00
restore_error_handler ();
2011-05-05 07:46:20 +01:00
2013-12-11 15:16:31 +00:00
$handler = ErrorHandler :: register ( 3 );
$this -> assertFalse ( $handler -> handle ( 4 , 'foo' , 'foo.php' , 12 , 'foo' ));
2011-04-15 20:12:02 +01:00
2013-12-11 15:16:31 +00:00
restore_error_handler ();
2011-04-15 20:12:02 +01:00
2013-12-11 15:16:31 +00:00
$handler = ErrorHandler :: register ( 3 );
try {
$handler -> handle ( 111 , 'foo' , 'foo.php' , 12 , 'foo' );
} catch ( \ErrorException $e ) {
$this -> assertSame ( '111: foo in foo.php line 12' , $e -> getMessage ());
$this -> assertSame ( 111 , $e -> getSeverity ());
$this -> assertSame ( 'foo.php' , $e -> getFile ());
$this -> assertSame ( 12 , $e -> getLine ());
}
2011-03-05 19:23:35 +00:00
2013-12-11 15:16:31 +00:00
restore_error_handler ();
2012-12-01 11:25:00 +00:00
2013-12-11 15:16:31 +00:00
$handler = ErrorHandler :: register ( E_USER_DEPRECATED );
$this -> assertTrue ( $handler -> handle ( E_USER_DEPRECATED , 'foo' , 'foo.php' , 12 , 'foo' ));
2012-12-01 11:25:00 +00:00
2013-12-11 15:16:31 +00:00
restore_error_handler ();
2012-12-01 11:25:00 +00:00
2013-12-11 15:16:31 +00:00
$handler = ErrorHandler :: register ( E_DEPRECATED );
$this -> assertTrue ( $handler -> handle ( E_DEPRECATED , 'foo' , 'foo.php' , 12 , 'foo' ));
2012-12-01 11:25:00 +00:00
2013-12-11 15:16:31 +00:00
restore_error_handler ();
2012-12-01 11:25:00 +00:00
2013-12-11 15:16:31 +00:00
$logger = $this -> getMock ( 'Psr\Log\LoggerInterface' );
2012-12-07 11:47:14 +00:00
2013-12-11 15:16:31 +00:00
$that = $this ;
$warnArgCheck = function ( $message , $context ) use ( $that ) {
$that -> assertEquals ( 'foo' , $message );
$that -> assertArrayHasKey ( 'type' , $context );
$that -> assertEquals ( $context [ 'type' ], ErrorHandler :: TYPE_DEPRECATION );
$that -> assertArrayHasKey ( 'stack' , $context );
$that -> assertInternalType ( 'array' , $context [ 'stack' ]);
};
2012-12-07 11:47:14 +00:00
2013-12-11 15:16:31 +00:00
$logger
-> expects ( $this -> once ())
-> method ( 'warning' )
-> will ( $this -> returnCallback ( $warnArgCheck ))
;
2012-12-01 11:25:00 +00:00
2013-12-11 15:16:31 +00:00
$handler = ErrorHandler :: register ( E_USER_DEPRECATED );
$handler -> setLogger ( $logger );
$handler -> handle ( E_USER_DEPRECATED , 'foo' , 'foo.php' , 12 , 'foo' );
2012-12-01 11:25:00 +00:00
2013-12-11 15:16:31 +00:00
restore_error_handler ();
} catch ( \Exception $e ) {
restore_error_handler ();
throw $e ;
}
2011-05-05 07:46:20 +01:00
}
2013-05-28 18:12:41 +01:00
/**
2013-07-24 05:59:37 +01:00
* @ dataProvider provideFatalErrorHandlersData
2013-05-28 18:12:41 +01:00
*/
2013-07-24 05:59:37 +01:00
public function testFatalErrorHandlers ( $error , $class , $translatedMessage )
2013-05-28 18:12:41 +01:00
{
2013-07-24 05:59:37 +01:00
$handler = new ErrorHandler ();
$exceptionHandler = new MockExceptionHandler ();
2013-07-23 19:05:03 +01:00
$m = new \ReflectionMethod ( $handler , 'handleFatalError' );
$m -> setAccessible ( true );
2013-07-24 05:59:37 +01:00
$m -> invoke ( $handler , $exceptionHandler , $error );
2013-05-28 18:12:41 +01:00
2013-07-24 05:59:37 +01:00
$this -> assertInstanceof ( $class , $exceptionHandler -> e );
2013-05-28 18:12:41 +01:00
$this -> assertSame ( $translatedMessage , $exceptionHandler -> e -> getMessage ());
$this -> assertSame ( $error [ 'type' ], $exceptionHandler -> e -> getSeverity ());
$this -> assertSame ( $error [ 'file' ], $exceptionHandler -> e -> getFile ());
$this -> assertSame ( $error [ 'line' ], $exceptionHandler -> e -> getLine ());
}
2013-07-24 05:59:37 +01:00
public function provideFatalErrorHandlersData ()
2013-05-28 18:12:41 +01:00
{
return array (
2013-07-24 05:59:37 +01:00
// undefined function
2013-05-28 18:12:41 +01:00
array (
array (
'type' => 1 ,
'line' => 12 ,
'file' => 'foo.php' ,
2013-07-23 19:05:03 +01:00
'message' => 'Call to undefined function test_namespaced_function()' ,
2013-05-28 18:12:41 +01:00
),
2013-07-24 05:59:37 +01:00
'Symfony\Component\Debug\Exception\UndefinedFunctionException' ,
'Attempted to call function "test_namespaced_function" from the global namespace in foo.php line 12. Did you mean to call: "\\symfony\\component\\debug\\tests\\fatalerrorhandler\\test_namespaced_function"?' ,
2013-05-28 18:12:41 +01:00
),
2013-07-24 05:59:37 +01:00
// class not found
2013-05-28 18:12:41 +01:00
array (
array (
'type' => 1 ,
'line' => 12 ,
'file' => 'foo.php' ,
2013-08-30 12:26:06 +01:00
'message' => 'Class \'WhizBangFactory\' not found' ,
2013-05-28 18:12:41 +01:00
),
2013-07-24 05:59:37 +01:00
'Symfony\Component\Debug\Exception\ClassNotFoundException' ,
'Attempted to load class "WhizBangFactory" from the global namespace in foo.php line 12. Did you forget a use statement for this class?' ,
2013-05-28 18:12:41 +01:00
),
);
}
2011-03-05 19:23:35 +00:00
}