* Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice * * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests * @package Cake.Test.Case.Error * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ App::uses('ExceptionRenderer', 'Error'); App::uses('Controller', 'Controller'); App::uses('AppController', 'Controller'); App::uses('Component', 'Controller'); App::uses('Router', 'Routing'); /** * Short description for class. * * @package Cake.Test.Case.Error */ class AuthBlueberryUser extends CakeTestModel { /** * name property * * @var string 'AuthBlueberryUser' */ public $name = 'AuthBlueberryUser'; /** * useTable property * * @var string */ public $useTable = false; } /** * BlueberryComponent class * * @package Cake.Test.Case.Error */ class BlueberryComponent extends Component { /** * testName property * * @return void */ public $testName = null; /** * initialize method * * @return void */ public function initialize(Controller $controller) { $this->testName = 'BlueberryComponent'; } } /** * TestErrorController class * * @package Cake.Test.Case.Error */ class TestErrorController extends Controller { /** * uses property * * @var array */ public $uses = array(); /** * components property * * @return void */ public $components = array('Blueberry'); /** * beforeRender method * * @return void */ public function beforeRender() { echo $this->Blueberry->testName; } /** * index method * * @return void */ public function index() { $this->autoRender = false; return 'what up'; } } /** * MyCustomExceptionRenderer class * * @package Cake.Test.Case.Error */ class MyCustomExceptionRenderer extends ExceptionRenderer { /** * custom error message type. * * @return void */ public function missingWidgetThing() { echo 'widget thing is missing'; } } /** * Exception class for testing app error handlers and custom errors. * * @package Cake.Test.Case.Error */ class MissingWidgetThingException extends NotFoundException { } /** * ExceptionRendererTest class * * @package Cake.Test.Case.Error */ class ExceptionRendererTest extends CakeTestCase { protected $_restoreError = false; /** * setup create a request object to get out of router later. * * @return void */ public function setUp() { parent::setUp(); App::build(array( 'View' => array( CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS ) ), App::RESET); Router::reload(); $request = new CakeRequest(null, false); $request->base = ''; Router::setRequestInfo($request); Configure::write('debug', 2); } /** * tearDown * * @return void */ public function tearDown() { parent::tearDown(); if ($this->_restoreError) { restore_error_handler(); } } /** * Mocks out the response on the ExceptionRenderer object so headers aren't modified. * * @return void */ protected function _mockResponse($error) { $error->controller->response = $this->getMock('CakeResponse', array('_sendHeader')); return $error; } /** * test that methods declared in an ExceptionRenderer subclass are not converted * into error400 when debug > 0 * * @return void */ public function testSubclassMethodsNotBeingConvertedToError() { Configure::write('debug', 2); $exception = new MissingWidgetThingException('Widget not found'); $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception)); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertEquals('widget thing is missing', $result); } /** * test that subclass methods are not converted when debug = 0 * * @return void */ public function testSubclassMethodsNotBeingConvertedDebug0() { Configure::write('debug', 0); $exception = new MissingWidgetThingException('Widget not found'); $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception)); $this->assertEquals('missingWidgetThing', $ExceptionRenderer->method); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertEquals('widget thing is missing', $result, 'Method declared in subclass converted to error400'); } /** * test that ExceptionRenderer subclasses properly convert framework errors. * * @return void */ public function testSubclassConvertingFrameworkErrors() { Configure::write('debug', 0); $exception = new MissingControllerException('PostsController'); $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception)); $this->assertEquals('error400', $ExceptionRenderer->method); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertRegExp('/Not Found/', $result, 'Method declared in error handler not converted to error400. %s'); } /** * test things in the constructor. * * @return void */ public function testConstruction() { $exception = new NotFoundException('Page not found'); $ExceptionRenderer = new ExceptionRenderer($exception); $this->assertInstanceOf('CakeErrorController', $ExceptionRenderer->controller); $this->assertEquals('error400', $ExceptionRenderer->method); $this->assertEquals($exception, $ExceptionRenderer->error); } /** * test that method gets coerced when debug = 0 * * @return void */ public function testErrorMethodCoercion() { Configure::write('debug', 0); $exception = new MissingActionException('Page not found'); $ExceptionRenderer = new ExceptionRenderer($exception); $this->assertInstanceOf('CakeErrorController', $ExceptionRenderer->controller); $this->assertEquals('error400', $ExceptionRenderer->method); $this->assertEquals($exception, $ExceptionRenderer->error); } /** * test that helpers in custom CakeErrorController are not lost */ public function testCakeErrorHelpersNotLost() { $testApp = CAKE . 'Test' . DS . 'test_app' . DS; App::build(array( 'Controller' => array( $testApp . 'Controller' . DS ), 'View/Helper' => array( $testApp . 'View' . DS . 'Helper' . DS ), 'View/Layouts' => array( $testApp . 'View' . DS . 'Layouts' . DS ), 'Error' => array( $testApp . 'Error' . DS ), ), App::RESET); App::uses('TestAppsExceptionRenderer', 'Error'); $exception = new SocketException('socket exception'); $renderer = new TestAppsExceptionRenderer($exception); ob_start(); $renderer->render(); $result = ob_get_clean(); $this->assertContains('peeled', $result); } /** * test that unknown exception types with valid status codes are treated correctly. * * @return void */ public function testUnknownExceptionTypeWithExceptionThatHasA400Code() { $exception = new MissingWidgetThingException('coding fail.'); $ExceptionRenderer = new ExceptionRenderer($exception); $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader')); $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(404); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertFalse(method_exists($ExceptionRenderer, 'missingWidgetThing'), 'no method should exist.'); $this->assertEquals('error400', $ExceptionRenderer->method, 'incorrect method coercion.'); $this->assertContains('coding fail', $result, 'Text should show up.'); } /** * test that unknown exception types with valid status codes are treated correctly. * * @return void */ public function testUnknownExceptionTypeWithNoCodeIsA500() { $exception = new OutOfBoundsException('foul ball.'); $ExceptionRenderer = new ExceptionRenderer($exception); $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader')); $ExceptionRenderer->controller->response->expects($this->once()) ->method('statusCode') ->with(500); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.'); $this->assertContains('foul ball.', $result, 'Text should show up as its debug mode.'); } /** * test that unknown exceptions have messages ignored. * * @return void */ public function testUnknownExceptionInProduction() { Configure::write('debug', 0); $exception = new OutOfBoundsException('foul ball.'); $ExceptionRenderer = new ExceptionRenderer($exception); $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader')); $ExceptionRenderer->controller->response->expects($this->once()) ->method('statusCode') ->with(500); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.'); $this->assertNotContains('foul ball.', $result, 'Text should no show up.'); $this->assertContains('Internal Error', $result, 'Generic message only.'); } /** * test that unknown exception types with valid status codes are treated correctly. * * @return void */ public function testUnknownExceptionTypeWithCodeHigherThan500() { $exception = new OutOfBoundsException('foul ball.', 501); $ExceptionRenderer = new ExceptionRenderer($exception); $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader')); $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(501); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertEquals('error500', $ExceptionRenderer->method, 'incorrect method coercion.'); $this->assertContains('foul ball.', $result, 'Text should show up as its debug mode.'); } /** * testerror400 method * * @return void */ public function testError400() { Router::reload(); $request = new CakeRequest('posts/view/1000', false); Router::setRequestInfo($request); $exception = new NotFoundException('Custom message'); $ExceptionRenderer = new ExceptionRenderer($exception); $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('statusCode', '_sendHeader')); $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(404); ob_start(); $ExceptionRenderer->render(); $result = ob_get_clean(); $this->assertRegExp('/