<?php
/**
* Whoops - php errors for cool kids
* @author Filipe Dobreira <http://github.com/filp>
*/
namespace Whoops;
use Whoops\TestCase;
use Whoops\Run;
use Whoops\Handler\Handler;
use ArrayObject;
use Mockery as m;
use InvalidArgumentException;
use RuntimeException;
use Exception;
class RunTest extends TestCase
{
/**
* @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->pushHandler($handlerOne);
$run->pushHandler($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->pushHandler($banana = '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::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->pushHandler($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->pushHandler($handlerOne);
$run->pushHandler($handlerTwo);
$run->pushHandler($handlerThree);
$run->pushHandler($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->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, array(3, 2, 1));
}
/**
* @covers Whoops\Run::handleException
*/
public function testLastHandler()
{
$run = $this->getRunInstance();
$handlerOne = $this->getHandler();
$handlerTwo = $this->getHandler();
$run->pushHandler($handlerOne);
$run->pushHandler($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->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::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
* @expectedException InvalidArgumentException
*/
public function testSendHttpCodeWrongCode()
{
$this->getRunInstance()->sendHttpCode(1337);
}
}