mirror of
https://github.com/filp/whoops.git
synced 2026-09-05 23:18:08 +00:00
f41c4a2a5a
BREAKING CHANGE: since "pushHandler()" was actually prepending handlers it is now an alias for prependHandler but "popHandler()" is still removing the last handler.
459 lines
13 KiB
PHP
Executable File
459 lines
13 KiB
PHP
Executable File
<?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;
|
|
|
|
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 = null)
|
|
{
|
|
// 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->prependHandler($handlerOne);
|
|
$run->prependHandler($handlerTwo);
|
|
|
|
$handlers = $run->getHandlers();
|
|
|
|
$this->assertCount(2, $handlers);
|
|
$this->assertContains($handlerOne, $handlers);
|
|
$this->assertContains($handlerTwo, $handlers);
|
|
}
|
|
|
|
/**
|
|
* @expectedException InvalidArgumentException
|
|
* @covers Whoops\Run::pushHandler
|
|
*/
|
|
public function testPushInvalidHandler()
|
|
{
|
|
$run = $this->getRunInstance();
|
|
$run->prependHandler($banana = 'actually turnip');
|
|
}
|
|
|
|
/**
|
|
* @covers Whoops\Run::pushHandler
|
|
*/
|
|
public function testPushClosureBecomesHandler()
|
|
{
|
|
$run = $this->getRunInstance();
|
|
$run->prependHandler(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->appendHandler($handlerOne);
|
|
$run->appendHandler($handlerTwo);
|
|
$run->appendHandler($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::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
|
|
* @expectedException Exception
|
|
*/
|
|
public function testUnregisterHandler()
|
|
{
|
|
$run = $this->getRunInstance();
|
|
$run->register();
|
|
|
|
$handler = $this->getHandler();
|
|
$run->prependHandler($handler);
|
|
|
|
$run->unregister();
|
|
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->appendHandler($handlerOne);
|
|
$run->appendHandler($handlerTwo);
|
|
$run->appendHandler($handlerThree);
|
|
$run->appendHandler($handlerFour);
|
|
|
|
$handlers = $run->getHandlers();
|
|
|
|
$this->assertSame($handlers[0], $handlerOne);
|
|
$this->assertSame($handlers[1], $handlerTwo);
|
|
$this->assertSame($handlers[2], $handlerThree);
|
|
$this->assertSame($handlers[3], $handlerFour);
|
|
}
|
|
|
|
/**
|
|
* @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->prependHandler($handlerOne);
|
|
$run->prependHandler($handlerTwo);
|
|
$run->prependHandler($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();
|
|
|
|
$run->prependHandler($handlerOne);
|
|
$run->prependHandler($handlerTwo);
|
|
|
|
$test = $this;
|
|
$handlerOne
|
|
->shouldReceive('handle')
|
|
->andReturnUsing(function () use ($test) {
|
|
$test->fail('$handlerOne should not be called');
|
|
});
|
|
|
|
$handlerTwo
|
|
->shouldReceive('handle')
|
|
->andReturn(Handler::LAST_HANDLER);
|
|
|
|
$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->prependHandler($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->prependHandler($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->prependHandler($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->prependHandler($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
|
|
*/
|
|
public function testGetSilencedError()
|
|
{
|
|
$run = $this->getRunInstance();
|
|
$run->register();
|
|
|
|
$handler = $this->getHandler();
|
|
$run->prependHandler($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->prependHandler(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->prependHandler(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
|
|
* @expectedException InvalidArgumentException
|
|
*/
|
|
public function testSendHttpCodeWrongCode()
|
|
{
|
|
$this->getRunInstance()->sendHttpCode(1337);
|
|
}
|
|
}
|