Upstream filp/whoops state of the touched files before 5805bc7620
This commit is contained in:
1 parent
7f2cd8f154
commit
a5b89f86ae
4 files changed
+1581
No files matched your search
@@ -0,0 +1,607 @@
|
||||
<?php
|
||||
/**
|
||||
* Whoops - php errors for cool kids
|
||||
* @author Filipe Dobreira <http://github.com/filp>
|
||||
*/
|
||||
|
||||
namespace Whoops;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
use Whoops\Exception\ErrorException;
|
||||
use Whoops\Handler\CallbackHandler;
|
||||
use Whoops\Handler\Handler;
|
||||
use Whoops\Handler\HandlerInterface;
|
||||
use Whoops\Inspector\CallableInspectorFactory;
|
||||
use Whoops\Inspector\InspectorFactory;
|
||||
use Whoops\Inspector\InspectorFactoryInterface;
|
||||
use Whoops\Inspector\InspectorInterface;
|
||||
use Whoops\Util\Misc;
|
||||
use Whoops\Util\SystemFacade;
|
||||
|
||||
final class Run implements RunInterface
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $isRegistered;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $allowQuit = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $sendOutput = true;
|
||||
|
||||
/**
|
||||
* @var integer|false
|
||||
*/
|
||||
private $sendHttpCode = 500;
|
||||
|
||||
/**
|
||||
* @var integer|false
|
||||
*/
|
||||
private $sendExitCode = 1;
|
||||
|
||||
/**
|
||||
* @var HandlerInterface[]
|
||||
*/
|
||||
private $handlerStack = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
* @psalm-var list<array{patterns: string, levels: int}>
|
||||
*/
|
||||
private $silencedPatterns = [];
|
||||
|
||||
/**
|
||||
* @var SystemFacade
|
||||
*/
|
||||
private $system;
|
||||
|
||||
/**
|
||||
* In certain scenarios, like in shutdown handler, we can not throw exceptions.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $canThrowExceptions = true;
|
||||
|
||||
/**
|
||||
* The inspector factory to create inspectors.
|
||||
*
|
||||
* @var InspectorFactoryInterface
|
||||
*/
|
||||
private $inspectorFactory;
|
||||
|
||||
/**
|
||||
* @var array<callable>
|
||||
*/
|
||||
private $frameFilters = [];
|
||||
|
||||
public function __construct(?SystemFacade $system = null)
|
||||
{
|
||||
$this->system = $system ?: new SystemFacade;
|
||||
$this->inspectorFactory = new InspectorFactory();
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->unregister();
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly request your handler runs as the last of all currently registered handlers.
|
||||
*
|
||||
* @param callable|HandlerInterface $handler
|
||||
*
|
||||
* @return Run
|
||||
*/
|
||||
public function appendHandler($handler)
|
||||
{
|
||||
array_unshift($this->handlerStack, $this->resolveHandler($handler));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly request your handler runs as the first of all currently registered handlers.
|
||||
*
|
||||
* @param callable|HandlerInterface $handler
|
||||
*
|
||||
* @return Run
|
||||
*/
|
||||
public function prependHandler($handler)
|
||||
{
|
||||
return $this->pushHandler($handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register your handler as the last of all currently registered handlers (to be executed first).
|
||||
* Prefer using appendHandler and prependHandler for clarity.
|
||||
*
|
||||
* @param callable|HandlerInterface $handler
|
||||
*
|
||||
* @return Run
|
||||
*
|
||||
* @throws InvalidArgumentException If argument is not callable or instance of HandlerInterface.
|
||||
*/
|
||||
public function pushHandler($handler)
|
||||
{
|
||||
$this->handlerStack[] = $this->resolveHandler($handler);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the last handler pushed to the handler stack.
|
||||
*
|
||||
* @see Run::removeFirstHandler(), Run::removeLastHandler()
|
||||
*
|
||||
* @return HandlerInterface|null
|
||||
*/
|
||||
public function popHandler()
|
||||
{
|
||||
return array_pop($this->handlerStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeFirstHandler()
|
||||
{
|
||||
array_pop($this->handlerStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function removeLastHandler()
|
||||
{
|
||||
array_shift($this->handlerStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all handlers, in the order they were added to the stack.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHandlers()
|
||||
{
|
||||
return $this->handlerStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all handlers in the handlerStack, including the default PrettyPage handler.
|
||||
*
|
||||
* @return Run
|
||||
*/
|
||||
public function clearHandlers()
|
||||
{
|
||||
$this->handlerStack = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFrameFilters()
|
||||
{
|
||||
return $this->frameFilters;
|
||||
}
|
||||
|
||||
public function clearFrameFilters()
|
||||
{
|
||||
$this->frameFilters = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this instance as an error handler.
|
||||
*
|
||||
* @return Run
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
if (!$this->isRegistered) {
|
||||
// Workaround PHP bug 42098
|
||||
// https://bugs.php.net/bug.php?id=42098
|
||||
class_exists("\\Whoops\\Exception\\ErrorException");
|
||||
class_exists("\\Whoops\\Exception\\FrameCollection");
|
||||
class_exists("\\Whoops\\Exception\\Frame");
|
||||
class_exists("\\Whoops\\Exception\\Inspector");
|
||||
class_exists("\\Whoops\\Inspector\\InspectorFactory");
|
||||
|
||||
$this->system->setErrorHandler([$this, self::ERROR_HANDLER]);
|
||||
$this->system->setExceptionHandler([$this, self::EXCEPTION_HANDLER]);
|
||||
$this->system->registerShutdownFunction([$this, self::SHUTDOWN_HANDLER]);
|
||||
|
||||
$this->isRegistered = true;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters all handlers registered by this Whoops\Run instance.
|
||||
*
|
||||
* @return Run
|
||||
*/
|
||||
public function unregister()
|
||||
{
|
||||
if ($this->isRegistered) {
|
||||
$this->system->restoreExceptionHandler();
|
||||
$this->system->restoreErrorHandler();
|
||||
|
||||
$this->isRegistered = false;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should Whoops allow Handlers to force the script to quit?
|
||||
*
|
||||
* @param bool|int $exit
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allowQuit($exit = null)
|
||||
{
|
||||
if (func_num_args() == 0) {
|
||||
return $this->allowQuit;
|
||||
}
|
||||
|
||||
return $this->allowQuit = (bool) $exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Silence particular errors in particular files.
|
||||
*
|
||||
* @param array|string $patterns List or a single regex pattern to match.
|
||||
* @param int $levels Defaults to E_STRICT | E_DEPRECATED.
|
||||
*
|
||||
* @return Run
|
||||
*/
|
||||
public function silenceErrorsInPaths($patterns, $levels = 10240)
|
||||
{
|
||||
$this->silencedPatterns = array_merge(
|
||||
$this->silencedPatterns,
|
||||
array_map(
|
||||
function ($pattern) use ($levels) {
|
||||
return [
|
||||
"pattern" => $pattern,
|
||||
"levels" => $levels,
|
||||
];
|
||||
},
|
||||
(array) $patterns
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with silent errors in path configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSilenceErrorsInPaths()
|
||||
{
|
||||
return $this->silencedPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should Whoops send HTTP error code to the browser if possible?
|
||||
* Whoops will by default send HTTP code 500, but you may wish to
|
||||
* use 502, 503, or another 5xx family code.
|
||||
*
|
||||
* @param bool|int $code
|
||||
*
|
||||
* @return int|false
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function sendHttpCode($code = null)
|
||||
{
|
||||
if (func_num_args() == 0) {
|
||||
return $this->sendHttpCode;
|
||||
}
|
||||
|
||||
if (!$code) {
|
||||
return $this->sendHttpCode = false;
|
||||
}
|
||||
|
||||
if ($code === true) {
|
||||
$code = 500;
|
||||
}
|
||||
|
||||
if ($code < 400 || 600 <= $code) {
|
||||
throw new InvalidArgumentException(
|
||||
"Invalid status code '$code', must be 4xx or 5xx"
|
||||
);
|
||||
}
|
||||
|
||||
return $this->sendHttpCode = $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should Whoops exit with a specific code on the CLI if possible?
|
||||
* Whoops will exit with 1 by default, but you can specify something else.
|
||||
*
|
||||
* @param int $code
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function sendExitCode($code = null)
|
||||
{
|
||||
if (func_num_args() == 0) {
|
||||
return $this->sendExitCode;
|
||||
}
|
||||
|
||||
if ($code < 0 || 255 <= $code) {
|
||||
throw new InvalidArgumentException(
|
||||
"Invalid status code '$code', must be between 0 and 254"
|
||||
);
|
||||
}
|
||||
|
||||
return $this->sendExitCode = (int) $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should Whoops push output directly to the client?
|
||||
* If this is false, output will be returned by handleException.
|
||||
*
|
||||
* @param bool|int $send
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function writeToOutput($send = null)
|
||||
{
|
||||
if (func_num_args() == 0) {
|
||||
return $this->sendOutput;
|
||||
}
|
||||
|
||||
return $this->sendOutput = (bool) $send;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an exception, ultimately generating a Whoops error page.
|
||||
*
|
||||
* @param Throwable $exception
|
||||
*
|
||||
* @return string Output generated by handlers.
|
||||
*/
|
||||
public function handleException($exception)
|
||||
{
|
||||
// Walk the registered handlers in the reverse order
|
||||
// they were registered, and pass off the exception
|
||||
$inspector = $this->getInspector($exception);
|
||||
|
||||
// Capture output produced while handling the exception,
|
||||
// we might want to send it straight away to the client,
|
||||
// or return it silently.
|
||||
$this->system->startOutputBuffering();
|
||||
|
||||
// Just in case there are no handlers:
|
||||
$handlerResponse = null;
|
||||
$handlerContentType = null;
|
||||
|
||||
try {
|
||||
foreach (array_reverse($this->handlerStack) as $handler) {
|
||||
$handler->setRun($this);
|
||||
$handler->setInspector($inspector);
|
||||
$handler->setException($exception);
|
||||
|
||||
// The HandlerInterface does not require an Exception passed to handle()
|
||||
// and neither of our bundled handlers use it.
|
||||
// However, 3rd party handlers may have already relied on this parameter,
|
||||
// and removing it would be possibly breaking for users.
|
||||
$handlerResponse = $handler->handle($exception);
|
||||
|
||||
// Collect the content type for possible sending in the headers.
|
||||
$handlerContentType = method_exists($handler, 'contentType') ? $handler->contentType() : null;
|
||||
|
||||
if (in_array($handlerResponse, [Handler::LAST_HANDLER, Handler::QUIT])) {
|
||||
// The Handler has handled the exception in some way, and
|
||||
// wishes to quit execution (Handler::QUIT), or skip any
|
||||
// other handlers (Handler::LAST_HANDLER). If $this->allowQuit
|
||||
// is false, Handler::QUIT behaves like Handler::LAST_HANDLER
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$willQuit = $handlerResponse == Handler::QUIT && $this->allowQuit();
|
||||
} finally {
|
||||
$output = $this->system->cleanOutputBuffer();
|
||||
}
|
||||
|
||||
// If we're allowed to, send output generated by handlers directly
|
||||
// to the output, otherwise, and if the script doesn't quit, return
|
||||
// it so that it may be used by the caller
|
||||
if ($this->writeToOutput()) {
|
||||
// @todo Might be able to clean this up a bit better
|
||||
if ($willQuit) {
|
||||
// Cleanup all other output buffers before sending our output:
|
||||
while ($this->system->getOutputBufferLevel() > 0) {
|
||||
$this->system->endOutputBuffering();
|
||||
}
|
||||
|
||||
// Send any headers if needed:
|
||||
if (Misc::canSendHeaders() && $handlerContentType) {
|
||||
header("Content-Type: {$handlerContentType}");
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeToOutputNow($output);
|
||||
}
|
||||
|
||||
if ($willQuit) {
|
||||
// HHVM fix for https://github.com/facebook/hhvm/issues/4055
|
||||
$this->system->flushOutputBuffer();
|
||||
|
||||
$this->system->stopExecution(
|
||||
$this->sendExitCode()
|
||||
);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts generic PHP errors to \ErrorException instances, before passing them off to be handled.
|
||||
*
|
||||
* This method MUST be compatible with set_error_handler.
|
||||
*
|
||||
* @param int $level
|
||||
* @param string $message
|
||||
* @param string|null $file
|
||||
* @param int|null $line
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws ErrorException
|
||||
*/
|
||||
public function handleError($level, $message, $file = null, $line = null)
|
||||
{
|
||||
if ($level & $this->system->getErrorReportingLevel()) {
|
||||
foreach ($this->silencedPatterns as $entry) {
|
||||
$pathMatches = (bool) preg_match($entry["pattern"], $file);
|
||||
$levelMatches = $level & $entry["levels"];
|
||||
if ($pathMatches && $levelMatches) {
|
||||
// Ignore the error, abort handling
|
||||
// See https://github.com/filp/whoops/issues/418
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX we pass $level for the "code" param only for BC reasons.
|
||||
// see https://github.com/filp/whoops/issues/267
|
||||
$exception = new ErrorException($message, /*code*/ $level, /*severity*/ $level, $file, $line);
|
||||
if ($this->canThrowExceptions) {
|
||||
throw $exception;
|
||||
} else {
|
||||
$this->handleException($exception);
|
||||
}
|
||||
// Do not propagate errors which were already handled by Whoops.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Propagate error to the next handler, allows error_get_last() to
|
||||
// work on silenced errors.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case to deal with Fatal errors and the like.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handleShutdown()
|
||||
{
|
||||
// If we reached this step, we are in shutdown handler.
|
||||
// An exception thrown in a shutdown handler will not be propagated
|
||||
// to the exception handler. Pass that information along.
|
||||
$this->canThrowExceptions = false;
|
||||
|
||||
// If we are not currently registered, we should not do anything
|
||||
if (!$this->isRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $this->system->getLastError();
|
||||
if ($error && Misc::isLevelFatal($error['type'])) {
|
||||
// If there was a fatal error,
|
||||
// it was not handled in handleError yet.
|
||||
$this->allowQuit = false;
|
||||
$this->handleError(
|
||||
$error['type'],
|
||||
$error['message'],
|
||||
$error['file'],
|
||||
$error['line']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param InspectorFactoryInterface $factory
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setInspectorFactory(InspectorFactoryInterface $factory)
|
||||
{
|
||||
$this->inspectorFactory = $factory;
|
||||
}
|
||||
|
||||
public function addFrameFilter($filterCallback)
|
||||
{
|
||||
if (!is_callable($filterCallback)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
"A frame filter must be of type callable, %s type given.",
|
||||
gettype($filterCallback)
|
||||
));
|
||||
}
|
||||
|
||||
$this->frameFilters[] = $filterCallback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Throwable $exception
|
||||
*
|
||||
* @return InspectorInterface
|
||||
*/
|
||||
private function getInspector($exception)
|
||||
{
|
||||
return $this->inspectorFactory->create($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the giving handler.
|
||||
*
|
||||
* @param callable|HandlerInterface $handler
|
||||
*
|
||||
* @return HandlerInterface
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function resolveHandler($handler)
|
||||
{
|
||||
if (is_callable($handler)) {
|
||||
$handler = new CallbackHandler($handler);
|
||||
}
|
||||
|
||||
if (!$handler instanceof HandlerInterface) {
|
||||
throw new InvalidArgumentException(
|
||||
"Handler must be a callable, or instance of "
|
||||
. "Whoops\\Handler\\HandlerInterface"
|
||||
);
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo something to the browser.
|
||||
*
|
||||
* @param string $output
|
||||
*
|
||||
* @return Run
|
||||
*/
|
||||
private function writeToOutputNow($output)
|
||||
{
|
||||
if ($this->sendHttpCode() && Misc::canSendHeaders()) {
|
||||
$this->system->setHttpResponseCode(
|
||||
$this->sendHttpCode()
|
||||
);
|
||||
}
|
||||
|
||||
echo $output;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* Whoops - php errors for cool kids
|
||||
* @author Filipe Dobreira <http://github.com/filp>
|
||||
*/
|
||||
|
||||
namespace Whoops\Util;
|
||||
|
||||
class SystemFacade
|
||||
{
|
||||
/**
|
||||
* Turns on output buffering.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function startOutputBuffering()
|
||||
{
|
||||
return ob_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $handler
|
||||
* @param int $types
|
||||
*
|
||||
* @return callable|null
|
||||
*/
|
||||
public function setErrorHandler(callable $handler, $types = 'use-php-defaults')
|
||||
{
|
||||
// Since PHP 5.4 the constant E_ALL contains all errors (even E_STRICT)
|
||||
if ($types === 'use-php-defaults') {
|
||||
$types = E_ALL;
|
||||
}
|
||||
return set_error_handler($handler, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $handler
|
||||
*
|
||||
* @return callable|null
|
||||
*/
|
||||
public function setExceptionHandler(callable $handler)
|
||||
{
|
||||
return set_exception_handler($handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function restoreExceptionHandler()
|
||||
{
|
||||
restore_exception_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function restoreErrorHandler()
|
||||
{
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $function
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerShutdownFunction(callable $function)
|
||||
{
|
||||
register_shutdown_function($function);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
public function cleanOutputBuffer()
|
||||
{
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getOutputBufferLevel()
|
||||
{
|
||||
return ob_get_level();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function endOutputBuffering()
|
||||
{
|
||||
return ob_end_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function flushOutputBuffer()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getErrorReportingLevel()
|
||||
{
|
||||
return error_reporting();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function getLastError()
|
||||
{
|
||||
return error_get_last();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $httpCode
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function setHttpResponseCode($httpCode)
|
||||
{
|
||||
if (!headers_sent()) {
|
||||
// Ensure that no 'location' header is present as otherwise this
|
||||
// will override the HTTP code being set here, and mask the
|
||||
// expected error page.
|
||||
header_remove('location');
|
||||
}
|
||||
|
||||
return http_response_code($httpCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $exitStatus
|
||||
*/
|
||||
public function stopExecution($exitStatus)
|
||||
{
|
||||
exit($exitStatus);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,609 @@
|
||||
<?php
|
||||
/**
|
||||
* Whoops - php errors for cool kids
|
||||
* @author Filipe Dobreira <http://github.com/filp>
|
||||
*/
|
||||
|
||||
namespace Whoops;
|
||||
|
||||
use ArrayObject;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Mockery as m;
|
||||
use RuntimeException;
|
||||
use Whoops\Handler\Handler;
|
||||
use Whoops\Handler\HandlerInterface;
|
||||
use Whoops\Handler\PrettyPageHandler;
|
||||
use Whoops\Exception\Frame;
|
||||
use Whoops\Util\SystemFacade;
|
||||
|
||||
class RunTest extends TestCase
|
||||
{
|
||||
public function testImplementsRunInterface()
|
||||
{
|
||||
$this->assertNotFalse(class_implements('Whoops\\Run', 'Whoops\\RunInterface'));
|
||||
}
|
||||
|
||||
public function testConstantsAreAccessibleFromTheClass()
|
||||
{
|
||||
$this->assertEquals(RunInterface::ERROR_HANDLER, Run::ERROR_HANDLER);
|
||||
$this->assertEquals(RunInterface::EXCEPTION_HANDLER, Run::EXCEPTION_HANDLER);
|
||||
$this->assertEquals(RunInterface::SHUTDOWN_HANDLER, Run::SHUTDOWN_HANDLER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @return Exception
|
||||
*/
|
||||
protected function getException($message = "")
|
||||
{
|
||||
// HHVM does not support mocking exceptions
|
||||
// Since we do not use any additional features of Mockery for exceptions,
|
||||
// we can just use native Exceptions instead.
|
||||
return new \Exception($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Handler
|
||||
*/
|
||||
protected function getHandler()
|
||||
{
|
||||
return m::mock('Whoops\\Handler\\Handler')
|
||||
->shouldReceive('setRun')
|
||||
->andReturn(null)
|
||||
->mock()
|
||||
|
||||
->shouldReceive('setInspector')
|
||||
->andReturn(null)
|
||||
->mock()
|
||||
|
||||
->shouldReceive('setException')
|
||||
->andReturn(null)
|
||||
->mock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::clearHandlers
|
||||
*/
|
||||
public function testClearHandlers()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->clearHandlers();
|
||||
|
||||
$handlers = $run->getHandlers();
|
||||
|
||||
$this->assertEmpty($handlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::pushHandler
|
||||
*/
|
||||
public function testPushHandler()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->clearHandlers();
|
||||
|
||||
$handlerOne = $this->getHandler();
|
||||
$handlerTwo = $this->getHandler();
|
||||
|
||||
$run->pushHandler($handlerOne);
|
||||
$run->pushHandler($handlerTwo);
|
||||
|
||||
$handlers = $run->getHandlers();
|
||||
|
||||
$this->assertCount(2, $handlers);
|
||||
$this->assertContains($handlerOne, $handlers);
|
||||
$this->assertContains($handlerTwo, $handlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::pushHandler
|
||||
*/
|
||||
public function testPushInvalidHandler()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
|
||||
$this->expectExceptionOfType('InvalidArgumentException');
|
||||
|
||||
$run->pushHandler('actually turnip');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::pushHandler
|
||||
*/
|
||||
public function testPushClosureBecomesHandler()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->pushHandler(function () {});
|
||||
$this->assertInstanceOf('Whoops\\Handler\\CallbackHandler', $run->popHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::popHandler
|
||||
* @covers Whoops\Run::getHandlers
|
||||
*/
|
||||
public function testPopHandler()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
|
||||
$handlerOne = $this->getHandler();
|
||||
$handlerTwo = $this->getHandler();
|
||||
$handlerThree = $this->getHandler();
|
||||
|
||||
$run->pushHandler($handlerOne);
|
||||
$run->pushHandler($handlerTwo);
|
||||
$run->pushHandler($handlerThree);
|
||||
|
||||
$this->assertSame($handlerThree, $run->popHandler());
|
||||
$this->assertSame($handlerTwo, $run->popHandler());
|
||||
$this->assertSame($handlerOne, $run->popHandler());
|
||||
|
||||
// Should return null if there's nothing else in
|
||||
// the stack
|
||||
$this->assertNull($run->popHandler());
|
||||
|
||||
// Should be empty since we popped everything off
|
||||
// the stack:
|
||||
$this->assertEmpty($run->getHandlers());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::removeFirstHandler
|
||||
* @covers Whoops\Run::removeLastHandler
|
||||
* @covers Whoops\Run::getHandlers
|
||||
*/
|
||||
public function testRemoveHandler()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
|
||||
$handlerOne = $this->getHandler();
|
||||
$handlerTwo = $this->getHandler();
|
||||
$handlerThree = $this->getHandler();
|
||||
|
||||
$run->pushHandler($handlerOne);
|
||||
$run->pushHandler($handlerTwo);
|
||||
$run->pushHandler($handlerThree);
|
||||
|
||||
$run->removeLastHandler();
|
||||
$this->assertSame($handlerTwo, $run->getHandlers()[0]);
|
||||
$run->removeFirstHandler();
|
||||
$this->assertSame($handlerTwo, $run->getHandlers()[0]);
|
||||
$this->assertCount(1, $run->getHandlers());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::register
|
||||
*/
|
||||
public function testRegisterHandler()
|
||||
{
|
||||
// It is impossible to test the Run::register method using phpunit,
|
||||
// as given how every test is always inside a giant try/catch block,
|
||||
// any thrown exception will never hit a global exception handler.
|
||||
// On the other hand, there is not much need in testing
|
||||
// a call to a native PHP function.
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::unregister
|
||||
*/
|
||||
public function testUnregisterHandler()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->register();
|
||||
|
||||
$handler = $this->getHandler();
|
||||
$run->pushHandler($handler);
|
||||
|
||||
$run->unregister();
|
||||
|
||||
$this->expectExceptionOfType('Exception');
|
||||
|
||||
throw $this->getException("I'm not supposed to be caught!");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::pushHandler
|
||||
* @covers Whoops\Run::getHandlers
|
||||
*/
|
||||
public function testHandlerHoldsOrder()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
|
||||
$handlerOne = $this->getHandler();
|
||||
$handlerTwo = $this->getHandler();
|
||||
$handlerThree = $this->getHandler();
|
||||
$handlerFour = $this->getHandler();
|
||||
|
||||
$run->pushHandler($handlerOne);
|
||||
$run->prependHandler($handlerTwo);
|
||||
$run->appendHandler($handlerThree);
|
||||
$run->appendHandler($handlerFour);
|
||||
|
||||
$handlers = $run->getHandlers();
|
||||
|
||||
$this->assertSame($handlers[0], $handlerFour);
|
||||
$this->assertSame($handlers[1], $handlerThree);
|
||||
$this->assertSame($handlers[2], $handlerOne);
|
||||
$this->assertSame($handlers[3], $handlerTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo possibly split this up a bit and move
|
||||
* some of this test to Handler unit tests?
|
||||
* @covers Whoops\Run::handleException
|
||||
*/
|
||||
public function testHandlersGonnaHandle()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$exception = $this->getException();
|
||||
$order = new ArrayObject();
|
||||
|
||||
$handlerOne = $this->getHandler();
|
||||
$handlerTwo = $this->getHandler();
|
||||
$handlerThree = $this->getHandler();
|
||||
|
||||
$handlerOne->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($order) { $order[] = 1; });
|
||||
$handlerTwo->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($order) { $order[] = 2; });
|
||||
$handlerThree->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($order) { $order[] = 3; });
|
||||
|
||||
$run->pushHandler($handlerOne);
|
||||
$run->pushHandler($handlerTwo);
|
||||
$run->pushHandler($handlerThree);
|
||||
|
||||
// Get an exception to be handled, and verify that the handlers
|
||||
// are given the handler, and in the inverse order they were
|
||||
// registered.
|
||||
$run->handleException($exception);
|
||||
$this->assertEquals((array) $order, [3, 2, 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::handleException
|
||||
*/
|
||||
public function testLastHandler()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
|
||||
$handlerOne = $this->getHandler();
|
||||
$handlerTwo = $this->getHandler();
|
||||
$handlerThree = $this->getHandler();
|
||||
$handlerFour = $this->getHandler();
|
||||
|
||||
$run->pushHandler($handlerOne);
|
||||
$run->prependHandler($handlerTwo);
|
||||
$run->appendHandler($handlerThree);
|
||||
$run->appendHandler($handlerFour);
|
||||
|
||||
$test = $this;
|
||||
$handlerFour
|
||||
->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($test) {
|
||||
$test->fail('$handlerFour should not be called');
|
||||
});
|
||||
|
||||
$handlerThree
|
||||
->shouldReceive('handle')
|
||||
->andReturn(Handler::LAST_HANDLER);
|
||||
|
||||
$twoRan = false;
|
||||
|
||||
$handlerOne
|
||||
->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($test, &$twoRan) {
|
||||
$test->assertTrue($twoRan);
|
||||
});
|
||||
|
||||
$handlerTwo
|
||||
->shouldReceive('handle')
|
||||
->andReturnUsing(function () use (&$twoRan) {
|
||||
$twoRan = true;
|
||||
});
|
||||
|
||||
$run->handleException($this->getException());
|
||||
|
||||
// Reached the end without errors
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test error suppression using @ operator.
|
||||
*/
|
||||
public function testErrorSuppression()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->register();
|
||||
|
||||
$handler = $this->getHandler();
|
||||
$run->pushHandler($handler);
|
||||
|
||||
$test = $this;
|
||||
$handler
|
||||
->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($test) {
|
||||
$test->fail('$handler should not be called, error not suppressed');
|
||||
});
|
||||
|
||||
@trigger_error("Test error suppression");
|
||||
|
||||
// Reached the end without errors
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testErrorCatching()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->register();
|
||||
|
||||
$handler = $this->getHandler();
|
||||
$run->pushHandler($handler);
|
||||
|
||||
$test = $this;
|
||||
$handler
|
||||
->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($test) {
|
||||
$test->fail('$handler should not be called error should be caught');
|
||||
});
|
||||
|
||||
try {
|
||||
trigger_error('foo', E_USER_NOTICE);
|
||||
$this->fail('Should not continue after error thrown');
|
||||
} catch (\ErrorException $e) {
|
||||
// Do nothing
|
||||
$this->assertTrue(true);
|
||||
return;
|
||||
}
|
||||
$this->fail('Should not continue here, should have been caught.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to make sure that error_reporting is respected.
|
||||
*/
|
||||
public function testErrorReporting()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->register();
|
||||
|
||||
$handler = $this->getHandler();
|
||||
$run->pushHandler($handler);
|
||||
|
||||
$test = $this;
|
||||
$handler
|
||||
->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($test) {
|
||||
$test->fail('$handler should not be called, error_reporting not respected');
|
||||
});
|
||||
|
||||
$oldLevel = error_reporting(E_ALL ^ E_USER_NOTICE);
|
||||
trigger_error("Test error reporting", E_USER_NOTICE);
|
||||
error_reporting($oldLevel);
|
||||
|
||||
// Reached the end without errors
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::silenceErrorsInPaths
|
||||
*/
|
||||
public function testSilenceErrorsInPaths()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->register();
|
||||
|
||||
$handler = $this->getHandler();
|
||||
$run->pushHandler($handler);
|
||||
|
||||
$test = $this;
|
||||
$handler
|
||||
->shouldReceive('handle')
|
||||
->andReturnUsing(function () use ($test) {
|
||||
$test->fail('$handler should not be called, silenceErrorsInPaths not respected');
|
||||
});
|
||||
|
||||
$run->silenceErrorsInPaths('@^'.preg_quote(__FILE__, '@').'$@', E_USER_NOTICE);
|
||||
trigger_error('Test', E_USER_NOTICE);
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::handleError
|
||||
* @requires PHP < 8
|
||||
*/
|
||||
public function testGetSilencedError()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->register();
|
||||
|
||||
$handler = $this->getHandler();
|
||||
$run->pushHandler($handler);
|
||||
|
||||
@strpos();
|
||||
|
||||
$error = error_get_last();
|
||||
|
||||
$this->assertTrue($error && strpos($error['message'], 'strpos()') !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::handleError
|
||||
* @see https://github.com/filp/whoops/issues/267
|
||||
*/
|
||||
public function testErrorWrappedInException()
|
||||
{
|
||||
try {
|
||||
$run = $this->getRunInstance();
|
||||
$run->handleError(E_WARNING, 'my message', 'my file', 99);
|
||||
$this->fail("missing expected exception");
|
||||
} catch (\ErrorException $e) {
|
||||
$this->assertSame(E_WARNING, $e->getSeverity());
|
||||
$this->assertSame(E_WARNING, $e->getCode(), "For BC reasons getCode() should match getSeverity()");
|
||||
$this->assertSame('my message', $e->getMessage());
|
||||
$this->assertSame('my file', $e->getFile());
|
||||
$this->assertSame(99, $e->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::handleException
|
||||
* @covers Whoops\Run::writeToOutput
|
||||
*/
|
||||
public function testOutputIsSent()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->pushHandler(function () {
|
||||
echo "hello there";
|
||||
});
|
||||
|
||||
ob_start();
|
||||
$run->handleException(new RuntimeException());
|
||||
$this->assertEquals("hello there", ob_get_clean());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::handleException
|
||||
* @covers Whoops\Run::writeToOutput
|
||||
*/
|
||||
public function testOutputIsNotSent()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->writeToOutput(false);
|
||||
$run->pushHandler(function () {
|
||||
echo "hello there";
|
||||
});
|
||||
|
||||
ob_start();
|
||||
$this->assertEquals("hello there", $run->handleException(new RuntimeException()));
|
||||
$this->assertEquals("", ob_get_clean());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::sendHttpCode
|
||||
*/
|
||||
public function testSendHttpCode()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->sendHttpCode(true);
|
||||
$this->assertEquals(500, $run->sendHttpCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::sendHttpCode
|
||||
*/
|
||||
public function testSendHttpCodeNullCode()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$this->assertEquals(false, $run->sendHttpCode(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::sendHttpCode
|
||||
*/
|
||||
public function testSendHttpCodeWrongCode()
|
||||
{
|
||||
$this->expectExceptionOfType('InvalidArgumentException');
|
||||
|
||||
$this->getRunInstance()->sendHttpCode(1337);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::sendHttpCode
|
||||
*/
|
||||
public function testSendExitCode()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->sendExitCode(42);
|
||||
$this->assertEquals(42, $run->sendExitCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::sendExitCode
|
||||
*/
|
||||
public function testSendExitCodeDefaultCode()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$this->assertEquals(1, $run->sendExitCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::sendExitCode
|
||||
*/
|
||||
public function testSendExitCodeWrongCode()
|
||||
{
|
||||
$this->expectExceptionOfType('InvalidArgumentException');
|
||||
|
||||
$this->getRunInstance()->sendExitCode(255);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::addFrameFilter
|
||||
* @covers Whoops\Run::getFrameFilters
|
||||
*/
|
||||
public function testAddFrameFilter()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
|
||||
$filterCallbackOne = function(Frame $frame) {};
|
||||
$filterCallbackTwo = function(Frame $frame) {};
|
||||
|
||||
$run
|
||||
->addFrameFilter($filterCallbackOne)
|
||||
->addFrameFilter($filterCallbackTwo);
|
||||
|
||||
$frameFilters = $run->getFrameFilters();
|
||||
|
||||
$this->assertCount(2, $frameFilters);
|
||||
$this->assertContains($filterCallbackOne, $frameFilters);
|
||||
$this->assertContains($filterCallbackTwo, $frameFilters);
|
||||
$this->assertInstanceOf("Whoops\\RunInterface", $run);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Whoops\Run::clearFrameFilters
|
||||
* @covers Whoops\Run::getFrameFilters
|
||||
*/
|
||||
public function testClearFrameFilters()
|
||||
{
|
||||
$run = $this->getRunInstance();
|
||||
$run->addFrameFilter(function(Frame $frame) {});
|
||||
|
||||
$run = $run->clearFrameFilters();
|
||||
|
||||
$this->assertEmpty($run->getFrameFilters());
|
||||
$this->assertInstanceOf("Whoops\\RunInterface", $run);
|
||||
}
|
||||
|
||||
public function testShutdownHandlerDoesNotRunIfUnregistered()
|
||||
{
|
||||
$system = m::mock('Whoops\Util\SystemFacade');
|
||||
|
||||
$run = new Run($system);
|
||||
$run->writeToOutput(false);
|
||||
$run->allowQuit(false);
|
||||
|
||||
$fatalError = [
|
||||
'type' => E_ERROR,
|
||||
'message' => 'Simulated fatal error for shutdown',
|
||||
'file' => 'somefile.php',
|
||||
'line' => 10,
|
||||
];
|
||||
$system->shouldReceive('getLastError')->andReturn($fatalError)->byDefault();
|
||||
|
||||
$mockHandler = m::mock('Whoops\Handler\HandlerInterface');
|
||||
$mockHandler->shouldNotReceive('handle');
|
||||
$mockHandler->shouldNotReceive('setRun');
|
||||
$mockHandler->shouldNotReceive('setInspector');
|
||||
$mockHandler->shouldNotReceive('setException');
|
||||
$run->pushHandler($mockHandler);
|
||||
|
||||
$run->unregister();
|
||||
|
||||
ob_start();
|
||||
$run->handleShutdown();
|
||||
$output = ob_get_clean();
|
||||
|
||||
$this->assertEquals('', $output, "Output buffer should be empty.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
namespace Whoops\Util;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SystemFacadeTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var \Mockery\Mock
|
||||
*/
|
||||
public static $runtime;
|
||||
|
||||
/**
|
||||
* @var SystemFacade
|
||||
*/
|
||||
private $facade;
|
||||
|
||||
public static function delegate($fn, array $args = [])
|
||||
{
|
||||
return self::$runtime
|
||||
? call_user_func_array([self::$runtime, $fn], $args)
|
||||
: call_user_func_array("\\$fn", $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @before
|
||||
*/
|
||||
public function getReady()
|
||||
{
|
||||
self::$runtime = \Mockery::mock(['ob_start' => true]);
|
||||
$this->facade = new SystemFacade();
|
||||
}
|
||||
|
||||
/**
|
||||
* @after
|
||||
*/
|
||||
public function finishUp()
|
||||
{
|
||||
self::$runtime = null;
|
||||
\Mockery::close();
|
||||
}
|
||||
|
||||
public function test_it_delegates_output_buffering_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('ob_start')->once();
|
||||
|
||||
$this->facade->startOutputBuffering();
|
||||
}
|
||||
|
||||
public function test_it_delegates_cleaning_output_buffering_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('ob_get_clean')->once();
|
||||
|
||||
$this->facade->cleanOutputBuffer();
|
||||
}
|
||||
|
||||
public function test_it_delegates_getting_the_current_buffer_level_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('ob_get_level')->once();
|
||||
|
||||
$this->facade->getOutputBufferLevel();
|
||||
}
|
||||
|
||||
public function test_it_delegates_ending_the_current_buffer_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('ob_end_clean')->once();
|
||||
|
||||
$this->facade->endOutputBuffering();
|
||||
}
|
||||
|
||||
public function test_it_delegates_flushing_the_current_buffer_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('flush')->once();
|
||||
|
||||
$this->facade->flushOutputBuffer();
|
||||
}
|
||||
|
||||
public function test_it_delegates_error_handling_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('set_error_handler')->once();
|
||||
|
||||
$this->facade->setErrorHandler(function(){});
|
||||
}
|
||||
|
||||
public function test_it_delegates_error_handling_with_level_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('set_error_handler')->once();
|
||||
|
||||
$this->facade->setErrorHandler(function(){}, E_CORE_ERROR);
|
||||
}
|
||||
|
||||
public function test_it_delegates_exception_handling_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('set_exception_handler')->once();
|
||||
|
||||
$this->facade->setExceptionHandler(function(){});
|
||||
}
|
||||
|
||||
public function test_it_delegates_restoring_the_exception_handler_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('restore_exception_handler')->once();
|
||||
|
||||
$this->facade->restoreExceptionHandler();
|
||||
}
|
||||
|
||||
public function test_it_delegates_restoring_the_error_handler_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('restore_error_handler')->once();
|
||||
|
||||
$this->facade->restoreErrorHandler();
|
||||
}
|
||||
|
||||
public function test_it_delegates_registering_a_shutdown_function_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('register_shutdown_function')->once();
|
||||
|
||||
$this->facade->registerShutdownFunction(function(){});
|
||||
}
|
||||
|
||||
public function test_it_delegates_error_reporting_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('error_reporting')->once()->withNoArgs();
|
||||
|
||||
$this->facade->getErrorReportingLevel();
|
||||
}
|
||||
|
||||
public function test_it_delegates_getting_the_last_error_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('error_get_last')->once()->withNoArgs();
|
||||
|
||||
$this->facade->getLastError();
|
||||
}
|
||||
|
||||
public function test_it_delegates_sending_an_http_response_code_to_the_native_implementation()
|
||||
{
|
||||
self::$runtime->shouldReceive('headers_sent')->once()->withNoArgs();
|
||||
self::$runtime->shouldReceive('header_remove')->once()->with('location');
|
||||
self::$runtime->shouldReceive('http_response_code')->once()->with(230);
|
||||
|
||||
$this->facade->setHttpResponseCode(230);
|
||||
}
|
||||
}
|
||||
|
||||
function ob_start()
|
||||
{
|
||||
return SystemFacadeTest::delegate('ob_start');
|
||||
}
|
||||
|
||||
function ob_get_clean()
|
||||
{
|
||||
return SystemFacadeTest::delegate('ob_get_clean');
|
||||
}
|
||||
|
||||
function ob_get_level()
|
||||
{
|
||||
return SystemFacadeTest::delegate('ob_get_level');
|
||||
}
|
||||
|
||||
function ob_end_clean()
|
||||
{
|
||||
return SystemFacadeTest::delegate('ob_end_clean');
|
||||
}
|
||||
|
||||
function flush()
|
||||
{
|
||||
return SystemFacadeTest::delegate('flush');
|
||||
}
|
||||
|
||||
function set_error_handler(callable $handler, $types = 'use-php-defaults')
|
||||
{
|
||||
// Workaround for PHP 5.5
|
||||
if ($types === 'use-php-defaults') {
|
||||
$types = E_ALL | E_STRICT;
|
||||
}
|
||||
return SystemFacadeTest::delegate('set_error_handler', func_get_args());
|
||||
}
|
||||
|
||||
function set_exception_handler(callable $handler)
|
||||
{
|
||||
return SystemFacadeTest::delegate('set_exception_handler', func_get_args());
|
||||
}
|
||||
|
||||
function restore_exception_handler()
|
||||
{
|
||||
return SystemFacadeTest::delegate('restore_exception_handler');
|
||||
}
|
||||
|
||||
function restore_error_handler()
|
||||
{
|
||||
return SystemFacadeTest::delegate('restore_error_handler');
|
||||
}
|
||||
|
||||
function register_shutdown_function()
|
||||
{
|
||||
return SystemFacadeTest::delegate('register_shutdown_function', func_get_args());
|
||||
}
|
||||
|
||||
function error_reporting($level = null)
|
||||
{
|
||||
return SystemFacadeTest::delegate('error_reporting', func_get_args());
|
||||
}
|
||||
|
||||
function error_get_last()
|
||||
{
|
||||
return SystemFacadeTest::delegate('error_get_last', func_get_args());
|
||||
}
|
||||
|
||||
function header_remove($header = null)
|
||||
{
|
||||
return SystemFacadeTest::delegate('header_remove', func_get_args());
|
||||
}
|
||||
|
||||
function headers_sent(&$filename = null, &$line = null)
|
||||
{
|
||||
return SystemFacadeTest::delegate('headers_sent', func_get_args());
|
||||
}
|
||||
|
||||
function http_response_code($code = null)
|
||||
{
|
||||
return SystemFacadeTest::delegate('http_response_code', func_get_args());
|
||||
}
|
||||
Reference in new issue
Block a user