mirror of
https://github.com/symfony/debug.git
synced 2026-03-25 09:42:20 +01:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3e7ce815d | ||
|
|
0b60030091 | ||
|
|
2ab93347e8 | ||
|
|
4645282605 | ||
|
|
93fd0e9f20 | ||
|
|
c5366e87da | ||
|
|
a78bf4dc3a | ||
|
|
4dc880d082 | ||
|
|
63f26f1891 | ||
|
|
bef2cd01a1 | ||
|
|
22fea487fa | ||
|
|
89429ed0eb | ||
|
|
bc977cb268 | ||
|
|
dabd21d13b | ||
|
|
b6f28caaf2 | ||
|
|
5bf4824968 | ||
|
|
dff676526c | ||
|
|
b49ea98332 | ||
|
|
a808f15333 | ||
|
|
32d260af46 | ||
|
|
740602e8b0 | ||
|
|
d58c0d65d7 | ||
|
|
1172dc1abe | ||
|
|
7e1a4ec082 | ||
|
|
e79bbe15d8 | ||
|
|
671fc55bd1 |
@@ -149,11 +149,11 @@ class DebugClassLoader
|
||||
if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
|
||||
// no-op
|
||||
} elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
|
||||
require $file;
|
||||
include $file;
|
||||
|
||||
return;
|
||||
} else {
|
||||
require $file;
|
||||
} elseif (false === include $file) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
\call_user_func($this->classLoader, $class);
|
||||
@@ -168,7 +168,7 @@ class DebugClassLoader
|
||||
|
||||
private function checkClass($class, $file = null)
|
||||
{
|
||||
$exists = null === $file || \class_exists($class, false) || \interface_exists($class, false) || \trait_exists($class, false);
|
||||
$exists = null === $file || class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
|
||||
|
||||
if (null !== $file && $class && '\\' === $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
@@ -186,13 +186,13 @@ class DebugClassLoader
|
||||
}
|
||||
$name = $refl->getName();
|
||||
|
||||
if ($name !== $class && 0 === \strcasecmp($name, $class)) {
|
||||
if ($name !== $class && 0 === strcasecmp($name, $class)) {
|
||||
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name));
|
||||
}
|
||||
|
||||
$deprecations = $this->checkAnnotations($refl, $name);
|
||||
|
||||
if (isset(self::$php7Reserved[\strtolower($refl->getShortName())])) {
|
||||
if (isset(self::$php7Reserved[strtolower($refl->getShortName())])) {
|
||||
$deprecations[] = sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName());
|
||||
}
|
||||
|
||||
@@ -223,23 +223,23 @@ class DebugClassLoader
|
||||
$deprecations = [];
|
||||
|
||||
// Don't trigger deprecations for classes in the same vendor
|
||||
if (2 > $len = 1 + (\strpos($class, '\\') ?: \strpos($class, '_'))) {
|
||||
if (2 > $len = 1 + (strpos($class, '\\') ?: strpos($class, '_'))) {
|
||||
$len = 0;
|
||||
$ns = '';
|
||||
} else {
|
||||
$ns = \str_replace('_', '\\', \substr($class, 0, $len));
|
||||
$ns = str_replace('_', '\\', substr($class, 0, $len));
|
||||
}
|
||||
|
||||
// Detect annotations on the class
|
||||
if (false !== $doc = $refl->getDocComment()) {
|
||||
foreach (['final', 'deprecated', 'internal'] as $annotation) {
|
||||
if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
|
||||
if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
|
||||
self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$parent = \get_parent_class($class);
|
||||
$parent = get_parent_class($class);
|
||||
$parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent);
|
||||
if ($parent) {
|
||||
$parentAndOwnInterfaces[$parent] = $parent;
|
||||
@@ -254,22 +254,22 @@ class DebugClassLoader
|
||||
}
|
||||
|
||||
// Detect if the parent is annotated
|
||||
foreach ($parentAndOwnInterfaces + \class_uses($class, false) as $use) {
|
||||
foreach ($parentAndOwnInterfaces + class_uses($class, false) as $use) {
|
||||
if (!isset(self::$checkedClasses[$use])) {
|
||||
$this->checkClass($use);
|
||||
}
|
||||
if (isset(self::$deprecated[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len) && !isset(self::$deprecated[$class])) {
|
||||
if (isset(self::$deprecated[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len) && !isset(self::$deprecated[$class])) {
|
||||
$type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait');
|
||||
$verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
|
||||
|
||||
$deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $class, $type, $verb, $use, self::$deprecated[$use]);
|
||||
}
|
||||
if (isset(self::$internal[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len)) {
|
||||
if (isset(self::$internal[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len)) {
|
||||
$deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class);
|
||||
}
|
||||
}
|
||||
|
||||
if (\trait_exists($class)) {
|
||||
if (trait_exists($class)) {
|
||||
return $deprecations;
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ class DebugClassLoader
|
||||
|
||||
if (isset(self::$internalMethods[$class][$method->name])) {
|
||||
list($declaringClass, $message) = self::$internalMethods[$class][$method->name];
|
||||
if (\strncmp($ns, $declaringClass, $len)) {
|
||||
if (strncmp($ns, $declaringClass, $len)) {
|
||||
$deprecations[] = sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
|
||||
}
|
||||
}
|
||||
@@ -307,7 +307,7 @@ class DebugClassLoader
|
||||
}
|
||||
|
||||
foreach (['final', 'internal'] as $annotation) {
|
||||
if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
|
||||
if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
|
||||
$message = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : '';
|
||||
self::${$annotation.'Methods'}[$class][$method->name] = [$class, $message];
|
||||
}
|
||||
@@ -317,6 +317,12 @@ class DebugClassLoader
|
||||
return $deprecations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $file
|
||||
* @param string $class
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function checkCase(\ReflectionClass $refl, $file, $class)
|
||||
{
|
||||
$real = explode('\\', $class.strrchr($file, '.'));
|
||||
@@ -333,7 +339,7 @@ class DebugClassLoader
|
||||
array_splice($tail, 0, $i + 1);
|
||||
|
||||
if (!$tail) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$tail = \DIRECTORY_SEPARATOR.implode(\DIRECTORY_SEPARATOR, $tail);
|
||||
@@ -349,6 +355,8 @@ class DebugClassLoader
|
||||
) {
|
||||
return [substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -382,6 +382,10 @@ class ErrorHandler
|
||||
*/
|
||||
public function handleError($type, $message, $file, $line)
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 70300 && E_WARNING === $type && '"' === $message[0] && false !== strpos($message, '" targeting switch is equivalent to "break')) {
|
||||
$type = E_DEPRECATED;
|
||||
}
|
||||
|
||||
// Level is the current error reporting level to manage silent error.
|
||||
$level = error_reporting();
|
||||
$silenced = 0 === ($level & $type);
|
||||
@@ -445,7 +449,7 @@ class ErrorHandler
|
||||
self::$silencedErrorCache[$id][$message] = $errorAsException;
|
||||
}
|
||||
if (null === $lightTrace) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ($scope) {
|
||||
@@ -465,7 +469,7 @@ class ErrorHandler
|
||||
}
|
||||
|
||||
if ($throw) {
|
||||
if (E_USER_ERROR & $type) {
|
||||
if (\PHP_VERSION_ID < 70400 && E_USER_ERROR & $type) {
|
||||
for ($i = 1; isset($backtrace[$i]); ++$i) {
|
||||
if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
|
||||
&& '__toString' === $backtrace[$i]['function']
|
||||
@@ -594,7 +598,9 @@ class ErrorHandler
|
||||
$this->exceptionHandler = null;
|
||||
try {
|
||||
if (null !== $exceptionHandler) {
|
||||
return \call_user_func($exceptionHandler, $exception);
|
||||
$exceptionHandler($exception);
|
||||
|
||||
return;
|
||||
}
|
||||
$handlerException = $handlerException ?: $exception;
|
||||
} catch (\Exception $handlerException) {
|
||||
|
||||
@@ -54,7 +54,7 @@ class SilencedErrorContext implements \JsonSerializable
|
||||
return $this->trace;
|
||||
}
|
||||
|
||||
public function JsonSerialize()
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return [
|
||||
'severity' => $this->severity,
|
||||
|
||||
@@ -33,11 +33,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
$notFoundSuffix = '\' not found';
|
||||
$notFoundSuffixLen = \strlen($notFoundSuffix);
|
||||
if ($notFoundSuffixLen > $messageLen) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (['class', 'interface', 'trait'] as $typeName) {
|
||||
@@ -71,6 +71,8 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
|
||||
return new ClassNotFoundException($message, $exception);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,13 +187,19 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
}
|
||||
}
|
||||
|
||||
require_once $file;
|
||||
try {
|
||||
require_once $file;
|
||||
} catch (\Throwable $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
if ($this->classExists($candidate)) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,17 +30,17 @@ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
$notFoundSuffix = '()';
|
||||
$notFoundSuffixLen = \strlen($notFoundSuffix);
|
||||
if ($notFoundSuffixLen > $messageLen) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$prefix = 'Call to undefined function ';
|
||||
$prefixLen = \strlen($prefix);
|
||||
if (0 !== strpos($error['message'], $prefix)) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);
|
||||
|
||||
@@ -28,7 +28,7 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
|
||||
{
|
||||
preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches);
|
||||
if (!$matches) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
$className = $matches[1];
|
||||
|
||||
@@ -59,12 +59,10 @@ class DebugClassLoaderTest extends TestCase
|
||||
$this->fail('DebugClassLoader did not register');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage boo
|
||||
*/
|
||||
public function testThrowingClass()
|
||||
{
|
||||
$this->expectException('Exception');
|
||||
$this->expectExceptionMessage('boo');
|
||||
try {
|
||||
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
|
||||
$this->fail('Exception expected');
|
||||
@@ -139,21 +137,17 @@ class DebugClassLoaderTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Case mismatch between loaded and declared class names
|
||||
*/
|
||||
public function testNameCaseMismatch()
|
||||
{
|
||||
$this->expectException('RuntimeException');
|
||||
$this->expectExceptionMessage('Case mismatch between loaded and declared class names');
|
||||
class_exists(__NAMESPACE__.'\TestingCaseMismatch', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Case mismatch between class and real file names
|
||||
*/
|
||||
public function testFileCaseMismatch()
|
||||
{
|
||||
$this->expectException('RuntimeException');
|
||||
$this->expectExceptionMessage('Case mismatch between class and real file names');
|
||||
if (!file_exists(__DIR__.'/Fixtures/CaseMismatch.php')) {
|
||||
$this->markTestSkipped('Can only be run on case insensitive filesystems');
|
||||
}
|
||||
@@ -161,12 +155,10 @@ class DebugClassLoaderTest extends TestCase
|
||||
class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Case mismatch between loaded and declared class names
|
||||
*/
|
||||
public function testPsr4CaseMismatch()
|
||||
{
|
||||
$this->expectException('RuntimeException');
|
||||
$this->expectExceptionMessage('Case mismatch between loaded and declared class names');
|
||||
class_exists(__NAMESPACE__.'\Fixtures\Psr4CaseMismatch', true);
|
||||
}
|
||||
|
||||
@@ -447,5 +439,7 @@ class ClassLoader
|
||||
} elseif ('Test\\'.__NAMESPACE__.'\UseTraitWithInternalMethod' === $class) {
|
||||
eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@ class ErrorHandlerTest extends TestCase
|
||||
|
||||
public function testErrorGetLast()
|
||||
{
|
||||
$handler = ErrorHandler::register();
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->setDefaultLogger($logger);
|
||||
$handler->screamAt(E_ALL);
|
||||
|
||||
@@ -143,9 +143,8 @@ class ErrorHandlerTest extends TestCase
|
||||
public function testDefaultLogger()
|
||||
{
|
||||
try {
|
||||
$handler = ErrorHandler::register();
|
||||
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$handler = ErrorHandler::register();
|
||||
|
||||
$handler->setDefaultLogger($logger, E_NOTICE);
|
||||
$handler->setDefaultLogger($logger, [E_USER_NOTICE => LogLevel::CRITICAL]);
|
||||
@@ -234,7 +233,7 @@ class ErrorHandlerTest extends TestCase
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
->will($this->returnCallback($warnArgCheck))
|
||||
->willReturnCallback($warnArgCheck)
|
||||
;
|
||||
|
||||
$handler = ErrorHandler::register();
|
||||
@@ -262,7 +261,7 @@ class ErrorHandlerTest extends TestCase
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
->will($this->returnCallback($logArgCheck))
|
||||
->willReturnCallback($logArgCheck)
|
||||
;
|
||||
|
||||
$handler = ErrorHandler::register();
|
||||
@@ -284,6 +283,10 @@ class ErrorHandlerTest extends TestCase
|
||||
|
||||
public function testHandleUserError()
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$this->markTestSkipped('PHP 7.4 allows __toString to throw exceptions');
|
||||
}
|
||||
|
||||
try {
|
||||
$handler = ErrorHandler::register();
|
||||
$handler->throwAt(0, true);
|
||||
@@ -318,7 +321,7 @@ class ErrorHandlerTest extends TestCase
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
->will($this->returnCallback($logArgCheck))
|
||||
->willReturnCallback($logArgCheck)
|
||||
;
|
||||
|
||||
$handler = new ErrorHandler();
|
||||
@@ -334,12 +337,11 @@ class ErrorHandlerTest extends TestCase
|
||||
public function testHandleException()
|
||||
{
|
||||
try {
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$handler = ErrorHandler::register();
|
||||
|
||||
$exception = new \Exception('foo');
|
||||
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertSame('Uncaught Exception: foo', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
@@ -349,7 +351,7 @@ class ErrorHandlerTest extends TestCase
|
||||
$logger
|
||||
->expects($this->exactly(2))
|
||||
->method('log')
|
||||
->will($this->returnCallback($logArgCheck))
|
||||
->willReturnCallback($logArgCheck)
|
||||
;
|
||||
|
||||
$handler->setDefaultLogger($logger, E_ERROR);
|
||||
@@ -483,6 +485,7 @@ class ErrorHandlerTest extends TestCase
|
||||
public function testHandleFatalError()
|
||||
{
|
||||
try {
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$handler = ErrorHandler::register();
|
||||
|
||||
$error = [
|
||||
@@ -492,8 +495,6 @@ class ErrorHandlerTest extends TestCase
|
||||
'line' => 123,
|
||||
];
|
||||
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
|
||||
$logArgCheck = function ($level, $message, $context) {
|
||||
$this->assertEquals('Fatal Parse Error: foo', $message);
|
||||
$this->assertArrayHasKey('exception', $context);
|
||||
@@ -503,7 +504,7 @@ class ErrorHandlerTest extends TestCase
|
||||
$logger
|
||||
->expects($this->once())
|
||||
->method('log')
|
||||
->will($this->returnCallback($logArgCheck))
|
||||
->willReturnCallback($logArgCheck)
|
||||
;
|
||||
|
||||
$handler->setDefaultLogger($logger, E_PARSE);
|
||||
@@ -576,11 +577,11 @@ class ErrorHandlerTest extends TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @group no-hhvm
|
||||
*/
|
||||
public function testCustomExceptionHandler()
|
||||
{
|
||||
$this->expectException('Exception');
|
||||
$handler = new ErrorHandler();
|
||||
$handler->setExceptionHandler(function ($e) use ($handler) {
|
||||
$handler->handleException($e);
|
||||
|
||||
@@ -256,7 +256,7 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
// assertEquals() does not like NAN values.
|
||||
$this->assertEquals($array[$i][0], 'float');
|
||||
$this->assertTrue(is_nan($array[$i++][1]));
|
||||
$this->assertNan($array[$i++][1]);
|
||||
}
|
||||
|
||||
public function testRecursionInArguments()
|
||||
@@ -267,7 +267,7 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
$flattened = FlattenException::create($exception);
|
||||
$trace = $flattened->getTrace();
|
||||
$this->assertContains('*DEEP NESTED ARRAY*', serialize($trace));
|
||||
$this->assertStringContainsString('*DEEP NESTED ARRAY*', serialize($trace));
|
||||
}
|
||||
|
||||
public function testTooBigArray()
|
||||
@@ -291,8 +291,8 @@ class FlattenExceptionTest extends TestCase
|
||||
|
||||
$serializeTrace = serialize($trace);
|
||||
|
||||
$this->assertContains('*SKIPPED over 10000 entries*', $serializeTrace);
|
||||
$this->assertNotContains('*value1*', $serializeTrace);
|
||||
$this->assertStringContainsString('*SKIPPED over 10000 entries*', $serializeTrace);
|
||||
$this->assertStringNotContainsString('*value1*', $serializeTrace);
|
||||
}
|
||||
|
||||
private function createException($foo)
|
||||
|
||||
@@ -39,8 +39,8 @@ class ExceptionHandlerTest extends TestCase
|
||||
$handler->sendPhpResponse(new \RuntimeException('Foo'));
|
||||
$response = ob_get_clean();
|
||||
|
||||
$this->assertContains('Whoops, looks like something went wrong.', $response);
|
||||
$this->assertNotContains('<div class="trace trace-as-html">', $response);
|
||||
$this->assertStringContainsString('Whoops, looks like something went wrong.', $response);
|
||||
$this->assertStringNotContainsString('<div class="trace trace-as-html">', $response);
|
||||
|
||||
$handler = new ExceptionHandler(true);
|
||||
|
||||
@@ -48,8 +48,8 @@ class ExceptionHandlerTest extends TestCase
|
||||
$handler->sendPhpResponse(new \RuntimeException('Foo'));
|
||||
$response = ob_get_clean();
|
||||
|
||||
$this->assertContains('Whoops, looks like something went wrong.', $response);
|
||||
$this->assertContains('<div class="trace trace-as-html">', $response);
|
||||
$this->assertStringContainsString('Whoops, looks like something went wrong.', $response);
|
||||
$this->assertStringContainsString('<div class="trace trace-as-html">', $response);
|
||||
}
|
||||
|
||||
public function testStatusCode()
|
||||
@@ -60,7 +60,7 @@ class ExceptionHandlerTest extends TestCase
|
||||
$handler->sendPhpResponse(new NotFoundHttpException('Foo'));
|
||||
$response = ob_get_clean();
|
||||
|
||||
$this->assertContains('Sorry, the page you are looking for could not be found.', $response);
|
||||
$this->assertStringContainsString('Sorry, the page you are looking for could not be found.', $response);
|
||||
|
||||
$expectedHeaders = [
|
||||
['HTTP/1.0 404', true, null],
|
||||
@@ -76,7 +76,7 @@ class ExceptionHandlerTest extends TestCase
|
||||
|
||||
ob_start();
|
||||
$handler->sendPhpResponse(new MethodNotAllowedHttpException(['POST']));
|
||||
$response = ob_get_clean();
|
||||
ob_get_clean();
|
||||
|
||||
$expectedHeaders = [
|
||||
['HTTP/1.0 405', true, null],
|
||||
@@ -99,35 +99,65 @@ class ExceptionHandlerTest extends TestCase
|
||||
|
||||
public function testHandle()
|
||||
{
|
||||
$exception = new \Exception('foo');
|
||||
$handler = new ExceptionHandler(true);
|
||||
ob_start();
|
||||
|
||||
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
|
||||
$handler
|
||||
->expects($this->exactly(2))
|
||||
->method('sendPhpResponse');
|
||||
$handler->handle(new \Exception('foo'));
|
||||
|
||||
$handler->handle($exception);
|
||||
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'foo');
|
||||
}
|
||||
|
||||
$handler->setHandler(function ($e) use ($exception) {
|
||||
$this->assertSame($exception, $e);
|
||||
public function testHandleWithACustomHandlerThatOutputsSomething()
|
||||
{
|
||||
$handler = new ExceptionHandler(true);
|
||||
ob_start();
|
||||
$handler->setHandler(function () {
|
||||
echo 'ccc';
|
||||
});
|
||||
|
||||
$handler->handle($exception);
|
||||
$handler->handle(new \Exception());
|
||||
ob_end_flush(); // Necessary because of this PHP bug : https://bugs.php.net/76563
|
||||
$this->assertSame('ccc', ob_get_clean());
|
||||
}
|
||||
|
||||
public function testHandleWithACustomHandlerThatOutputsNothing()
|
||||
{
|
||||
$handler = new ExceptionHandler(true);
|
||||
$handler->setHandler(function () {});
|
||||
|
||||
$handler->handle(new \Exception('ccc'));
|
||||
|
||||
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
|
||||
}
|
||||
|
||||
public function testHandleWithACustomHandlerThatFails()
|
||||
{
|
||||
$handler = new ExceptionHandler(true);
|
||||
$handler->setHandler(function () {
|
||||
throw new \RuntimeException();
|
||||
});
|
||||
|
||||
$handler->handle(new \Exception('ccc'));
|
||||
|
||||
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
|
||||
}
|
||||
|
||||
public function testHandleOutOfMemoryException()
|
||||
{
|
||||
$exception = new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__);
|
||||
|
||||
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
|
||||
$handler
|
||||
->expects($this->once())
|
||||
->method('sendPhpResponse');
|
||||
|
||||
$handler->setHandler(function ($e) {
|
||||
$handler = new ExceptionHandler(true);
|
||||
ob_start();
|
||||
$handler->setHandler(function () {
|
||||
$this->fail('OutOfMemoryException should bypass the handler');
|
||||
});
|
||||
|
||||
$handler->handle($exception);
|
||||
$handler->handle(new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__));
|
||||
|
||||
$this->assertThatTheExceptionWasOutput(ob_get_clean(), OutOfMemoryException::class, 'OutOfMemoryException', 'foo');
|
||||
}
|
||||
|
||||
private function assertThatTheExceptionWasOutput($content, $expectedClass, $expectedTitle, $expectedMessage)
|
||||
{
|
||||
$this->assertStringContainsString(sprintf('<span class="exception_title"><abbr title="%s">%s</abbr></span>', $expectedClass, $expectedTitle), $content);
|
||||
$this->assertStringContainsString(sprintf('<p class="break-long-words trace-message">%s</p>', $expectedMessage), $content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
}
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $exception);
|
||||
$this->assertSame($translatedMessage, $exception->getMessage());
|
||||
$this->assertRegExp($translatedMessage, $exception->getMessage());
|
||||
$this->assertSame($error['type'], $exception->getSeverity());
|
||||
$this->assertSame($error['file'], $exception->getFile());
|
||||
$this->assertSame($error['line'], $exception->getLine());
|
||||
@@ -71,6 +71,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
{
|
||||
$autoloader = new ComposerClassLoader();
|
||||
$autoloader->add('Symfony\Component\Debug\Exception\\', realpath(__DIR__.'/../../Exception'));
|
||||
$autoloader->add('Symfony_Component_Debug_Tests_Fixtures', realpath(__DIR__.'/../../Tests/Fixtures'));
|
||||
|
||||
$debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']);
|
||||
|
||||
@@ -82,7 +83,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'WhizBangFactory\' not found',
|
||||
],
|
||||
"Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement?",
|
||||
"/^Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement\?$/",
|
||||
],
|
||||
[
|
||||
[
|
||||
@@ -91,7 +92,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\WhizBangFactory\' not found',
|
||||
],
|
||||
"Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?",
|
||||
"/^Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
|
||||
],
|
||||
[
|
||||
[
|
||||
@@ -100,7 +101,8 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'UndefinedFunctionException\' not found',
|
||||
],
|
||||
"Attempted to load class \"UndefinedFunctionException\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
|
||||
"/^Attempted to load class \"UndefinedFunctionException\" from the global namespace.\nDid you forget a \"use\" statement for .*\"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/",
|
||||
[$debugClassLoader, 'loadClass'],
|
||||
],
|
||||
[
|
||||
[
|
||||
@@ -109,35 +111,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'PEARClass\' not found',
|
||||
],
|
||||
"Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_Debug_Tests_Fixtures_PEARClass\"?",
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => 1,
|
||||
'line' => 12,
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
],
|
||||
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => 1,
|
||||
'line' => 12,
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
],
|
||||
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
|
||||
[$autoloader, 'loadClass'],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => 1,
|
||||
'line' => 12,
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
],
|
||||
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
|
||||
"/^Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_Debug_Tests_Fixtures_PEARClass\"\?$/",
|
||||
[$debugClassLoader, 'loadClass'],
|
||||
],
|
||||
[
|
||||
@@ -147,7 +121,37 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
],
|
||||
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?",
|
||||
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for .*\"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/",
|
||||
[$debugClassLoader, 'loadClass'],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => 1,
|
||||
'line' => 12,
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
],
|
||||
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for \"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/",
|
||||
[$autoloader, 'loadClass'],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => 1,
|
||||
'line' => 12,
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
],
|
||||
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for \"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?/",
|
||||
[$debugClassLoader, 'loadClass'],
|
||||
],
|
||||
[
|
||||
[
|
||||
'type' => 1,
|
||||
'line' => 12,
|
||||
'file' => 'foo.php',
|
||||
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
|
||||
],
|
||||
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
|
||||
function ($className) { /* do nothing here */ },
|
||||
],
|
||||
];
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Debug\Tests;
|
||||
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
|
||||
class MockExceptionHandler extends ExceptionHandler
|
||||
{
|
||||
public $e;
|
||||
|
||||
public function handle(\Exception $e)
|
||||
{
|
||||
$this->e = $e;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user