ExceptionRendererTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. <?php
  2. /**
  3. * ExceptionRendererTest file
  4. *
  5. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  6. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  7. *
  8. * Licensed under The MIT License
  9. * For full copyright and license information, please see the LICENSE.txt
  10. * Redistributions of files must retain the above copyright notice
  11. *
  12. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  13. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  14. * @since 2.0.0
  15. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  16. */
  17. namespace Cake\Test\TestCase\Error;
  18. use Cake\Controller\Component;
  19. use Cake\Controller\Controller;
  20. use Cake\Controller\Error\MissingActionException;
  21. use Cake\Controller\Error\MissingComponentException;
  22. use Cake\Controller\Error\MissingControllerException;
  23. use Cake\Controller\Error\PrivateActionException;
  24. use Cake\Core\App;
  25. use Cake\Core\Configure;
  26. use Cake\Error;
  27. use Cake\Error\ExceptionRenderer;
  28. use Cake\Event\Event;
  29. use Cake\Network\Error\SocketException;
  30. use Cake\Network\Request;
  31. use Cake\ORM\Error\MissingBehaviorException;
  32. use Cake\Routing\Router;
  33. use Cake\TestSuite\TestCase;
  34. use Cake\View\Error\MissingHelperException;
  35. use Cake\View\Error\MissingLayoutException;
  36. use Cake\View\Error\MissingViewException;
  37. /**
  38. * BlueberryComponent class
  39. *
  40. */
  41. class BlueberryComponent extends Component {
  42. /**
  43. * testName property
  44. *
  45. * @return void
  46. */
  47. public $testName = null;
  48. /**
  49. * initialize method
  50. *
  51. * @param Event $event
  52. * @return void
  53. */
  54. public function initialize(Event $event) {
  55. $this->testName = 'BlueberryComponent';
  56. }
  57. }
  58. /**
  59. * TestErrorController class
  60. *
  61. */
  62. class TestErrorController extends Controller {
  63. /**
  64. * uses property
  65. *
  66. * @var array
  67. */
  68. public $uses = array();
  69. /**
  70. * components property
  71. *
  72. * @return void
  73. */
  74. public $components = array('Blueberry');
  75. /**
  76. * beforeRender method
  77. *
  78. * @return void
  79. */
  80. public function beforeRender(Event $event) {
  81. echo $this->Blueberry->testName;
  82. }
  83. /**
  84. * index method
  85. *
  86. * @return void
  87. */
  88. public function index() {
  89. $this->autoRender = false;
  90. return 'what up';
  91. }
  92. }
  93. /**
  94. * MyCustomExceptionRenderer class
  95. *
  96. */
  97. class MyCustomExceptionRenderer extends ExceptionRenderer {
  98. /**
  99. * custom error message type.
  100. *
  101. * @return void
  102. */
  103. public function missingWidgetThing() {
  104. echo 'widget thing is missing';
  105. }
  106. }
  107. /**
  108. * Exception class for testing app error handlers and custom errors.
  109. *
  110. */
  111. class MissingWidgetThingException extends Error\NotFoundException {
  112. }
  113. /**
  114. * ExceptionRendererTest class
  115. *
  116. */
  117. class ExceptionRendererTest extends TestCase {
  118. /**
  119. * @var bool
  120. */
  121. protected $_restoreError = false;
  122. /**
  123. * setup create a request object to get out of router later.
  124. *
  125. * @return void
  126. */
  127. public function setUp() {
  128. parent::setUp();
  129. Configure::write('Config.language', 'eng');
  130. Router::reload();
  131. $request = new Request();
  132. $request->base = '';
  133. Router::setRequestInfo($request);
  134. Configure::write('debug', true);
  135. }
  136. /**
  137. * tearDown
  138. *
  139. * @return void
  140. */
  141. public function tearDown() {
  142. parent::tearDown();
  143. if ($this->_restoreError) {
  144. restore_error_handler();
  145. }
  146. }
  147. /**
  148. * Mocks out the response on the ExceptionRenderer object so headers aren't modified.
  149. *
  150. * @return void
  151. */
  152. protected function _mockResponse($error) {
  153. $error->controller->response = $this->getMock('Cake\Network\Response', array('_sendHeader'));
  154. return $error;
  155. }
  156. /**
  157. * test that methods declared in an ExceptionRenderer subclass are not converted
  158. * into error400 when debug > 0
  159. *
  160. * @return void
  161. */
  162. public function testSubclassMethodsNotBeingConvertedToError() {
  163. Configure::write('debug', true);
  164. $exception = new MissingWidgetThingException('Widget not found');
  165. $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception));
  166. ob_start();
  167. $ExceptionRenderer->render();
  168. $result = ob_get_clean();
  169. $this->assertEquals('widget thing is missing', $result);
  170. }
  171. /**
  172. * test that subclass methods are not converted when debug = 0
  173. *
  174. * @return void
  175. */
  176. public function testSubclassMethodsNotBeingConvertedDebug0() {
  177. Configure::write('debug', false);
  178. $exception = new MissingWidgetThingException('Widget not found');
  179. $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception));
  180. ob_start();
  181. $ExceptionRenderer->render();
  182. $result = ob_get_clean();
  183. $this->assertEquals('missingWidgetThing', $ExceptionRenderer->method);
  184. $this->assertEquals('widget thing is missing', $result, 'Method declared in subclass converted to error400');
  185. }
  186. /**
  187. * test that ExceptionRenderer subclasses properly convert framework errors.
  188. *
  189. * @return void
  190. */
  191. public function testSubclassConvertingFrameworkErrors() {
  192. Configure::write('debug', false);
  193. $exception = new MissingControllerException('PostsController');
  194. $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception));
  195. ob_start();
  196. $ExceptionRenderer->render();
  197. $result = ob_get_clean();
  198. $this->assertRegExp('/Not Found/', $result, 'Method declared in error handler not converted to error400. %s');
  199. }
  200. /**
  201. * test things in the constructor.
  202. *
  203. * @return void
  204. */
  205. public function testConstruction() {
  206. $exception = new Error\NotFoundException('Page not found');
  207. $ExceptionRenderer = new ExceptionRenderer($exception);
  208. $this->assertInstanceOf('Cake\Controller\ErrorController', $ExceptionRenderer->controller);
  209. $this->assertEquals($exception, $ExceptionRenderer->error);
  210. }
  211. /**
  212. * test that exception message gets coerced when debug = 0
  213. *
  214. * @return void
  215. */
  216. public function testExceptionMessageCoercion() {
  217. Configure::write('debug', false);
  218. $exception = new MissingActionException('Secret info not to be leaked');
  219. $ExceptionRenderer = new ExceptionRenderer($exception);
  220. $this->assertInstanceOf('Cake\Controller\ErrorController', $ExceptionRenderer->controller);
  221. $this->assertEquals($exception, $ExceptionRenderer->error);
  222. ob_start();
  223. $ExceptionRenderer->render();
  224. $result = ob_get_clean();
  225. $this->assertEquals('error400', $ExceptionRenderer->template);
  226. $this->assertContains('Not Found', $result);
  227. $this->assertNotContains('Secret info not to be leaked', $result);
  228. }
  229. /**
  230. * test that helpers in custom CakeErrorController are not lost
  231. *
  232. * @return void
  233. */
  234. public function testCakeErrorHelpersNotLost() {
  235. Configure::write('App.namespace', 'TestApp');
  236. $exception = new SocketException('socket exception');
  237. $renderer = new \TestApp\Error\TestAppsExceptionRenderer($exception);
  238. ob_start();
  239. $renderer->render();
  240. $result = ob_get_clean();
  241. $this->assertContains('<b>peeled</b>', $result);
  242. }
  243. /**
  244. * test that unknown exception types with valid status codes are treated correctly.
  245. *
  246. * @return void
  247. */
  248. public function testUnknownExceptionTypeWithExceptionThatHasA400Code() {
  249. $exception = new MissingWidgetThingException('coding fail.');
  250. $ExceptionRenderer = new ExceptionRenderer($exception);
  251. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  252. $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(404);
  253. ob_start();
  254. $ExceptionRenderer->render();
  255. $result = ob_get_clean();
  256. $this->assertFalse(method_exists($ExceptionRenderer, 'missingWidgetThing'), 'no method should exist.');
  257. $this->assertContains('coding fail', $result, 'Text should show up.');
  258. }
  259. /**
  260. * test that unknown exception types with valid status codes are treated correctly.
  261. *
  262. * @return void
  263. */
  264. public function testUnknownExceptionTypeWithNoCodeIsA500() {
  265. $exception = new \OutOfBoundsException('foul ball.');
  266. $ExceptionRenderer = new ExceptionRenderer($exception);
  267. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  268. $ExceptionRenderer->controller->response->expects($this->once())
  269. ->method('statusCode')
  270. ->with(500);
  271. ob_start();
  272. $ExceptionRenderer->render();
  273. $result = ob_get_clean();
  274. $this->assertContains('foul ball.', $result, 'Text should show up as its debug mode.');
  275. }
  276. /**
  277. * test that unknown exceptions have messages ignored.
  278. *
  279. * @return void
  280. */
  281. public function testUnknownExceptionInProduction() {
  282. Configure::write('debug', false);
  283. $exception = new \OutOfBoundsException('foul ball.');
  284. $ExceptionRenderer = new ExceptionRenderer($exception);
  285. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  286. $ExceptionRenderer->controller->response->expects($this->once())
  287. ->method('statusCode')
  288. ->with(500);
  289. ob_start();
  290. $ExceptionRenderer->render();
  291. $result = ob_get_clean();
  292. $this->assertNotContains('foul ball.', $result, 'Text should no show up.');
  293. $this->assertContains('Internal Error', $result, 'Generic message only.');
  294. }
  295. /**
  296. * test that unknown exception types with valid status codes are treated correctly.
  297. *
  298. * @return void
  299. */
  300. public function testUnknownExceptionTypeWithCodeHigherThan500() {
  301. $exception = new \OutOfBoundsException('foul ball.', 501);
  302. $ExceptionRenderer = new ExceptionRenderer($exception);
  303. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  304. $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(501);
  305. ob_start();
  306. $ExceptionRenderer->render();
  307. $result = ob_get_clean();
  308. $this->assertContains('foul ball.', $result, 'Text should show up as its debug mode.');
  309. }
  310. /**
  311. * testerror400 method
  312. *
  313. * @return void
  314. */
  315. public function testError400() {
  316. Router::reload();
  317. $request = new Request('posts/view/1000');
  318. Router::setRequestInfo($request);
  319. $exception = new Error\NotFoundException('Custom message');
  320. $ExceptionRenderer = new ExceptionRenderer($exception);
  321. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  322. $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(404);
  323. ob_start();
  324. $ExceptionRenderer->render();
  325. $result = ob_get_clean();
  326. $this->assertRegExp('/<h2>Custom message<\/h2>/', $result);
  327. $this->assertRegExp("/<strong>'.*?\/posts\/view\/1000'<\/strong>/", $result);
  328. }
  329. /**
  330. * test that error400 only modifies the messages on Cake Exceptions.
  331. *
  332. * @return void
  333. */
  334. public function testerror400OnlyChangingCakeException() {
  335. Configure::write('debug', false);
  336. $exception = new Error\NotFoundException('Custom message');
  337. $ExceptionRenderer = $this->_mockResponse(new ExceptionRenderer($exception));
  338. ob_start();
  339. $ExceptionRenderer->render();
  340. $result = ob_get_clean();
  341. $this->assertContains('Custom message', $result);
  342. $exception = new MissingActionException(array('controller' => 'PostsController', 'action' => 'index'));
  343. $ExceptionRenderer = $this->_mockResponse(new ExceptionRenderer($exception));
  344. ob_start();
  345. $ExceptionRenderer->render();
  346. $result = ob_get_clean();
  347. $this->assertContains('Not Found', $result);
  348. }
  349. /**
  350. * test that error400 doesn't expose XSS
  351. *
  352. * @return void
  353. */
  354. public function testError400NoInjection() {
  355. Router::reload();
  356. $request = new Request('pages/<span id=333>pink</span></id><script>document.body.style.background = t=document.getElementById(333).innerHTML;window.alert(t);</script>');
  357. Router::setRequestInfo($request);
  358. $exception = new Error\NotFoundException('Custom message');
  359. $ExceptionRenderer = $this->_mockResponse(new ExceptionRenderer($exception));
  360. ob_start();
  361. $ExceptionRenderer->render();
  362. $result = ob_get_clean();
  363. $this->assertNotRegExp('#<script>document#', $result);
  364. $this->assertNotRegExp('#alert\(t\);</script>#', $result);
  365. }
  366. /**
  367. * testError500 method
  368. *
  369. * @return void
  370. */
  371. public function testError500Message() {
  372. $exception = new Error\InternalErrorException('An Internal Error Has Occurred');
  373. $ExceptionRenderer = new ExceptionRenderer($exception);
  374. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  375. $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(500);
  376. ob_start();
  377. $ExceptionRenderer->render();
  378. $result = ob_get_clean();
  379. $this->assertRegExp('/<h2>An Internal Error Has Occurred<\/h2>/', $result);
  380. }
  381. /**
  382. * testExceptionResponseHeader method
  383. *
  384. * @return void
  385. */
  386. public function testExceptionResponseHeader() {
  387. $exception = new Error\MethodNotAllowedException('Only allowing POST and DELETE');
  388. $exception->responseHeader(array('Allow: POST, DELETE'));
  389. $ExceptionRenderer = new ExceptionRenderer($exception);
  390. //Replace response object with mocked object add back the original headers which had been set in ExceptionRenderer constructor
  391. $headers = $ExceptionRenderer->controller->response->header();
  392. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('_sendHeader'));
  393. $ExceptionRenderer->controller->response->header($headers);
  394. $ExceptionRenderer->controller->response->expects($this->at(1))->method('_sendHeader')->with('Allow', 'POST, DELETE');
  395. ob_start();
  396. $ExceptionRenderer->render();
  397. ob_get_clean();
  398. }
  399. /**
  400. * testMissingController method
  401. *
  402. * @return void
  403. */
  404. public function testMissingController() {
  405. $exception = new MissingControllerException(array(
  406. 'class' => 'Posts',
  407. 'prefix' => '',
  408. 'plugin' => '',
  409. ));
  410. $ExceptionRenderer = $this->_mockResponse(new MyCustomExceptionRenderer($exception));
  411. ob_start();
  412. $ExceptionRenderer->render();
  413. $result = ob_get_clean();
  414. $this->assertEquals('missingController', $ExceptionRenderer->template);
  415. $this->assertRegExp('/<h2>Missing Controller<\/h2>/', $result);
  416. $this->assertRegExp('/<em>PostsController<\/em>/', $result);
  417. }
  418. /**
  419. * Returns an array of tests to run for the various Cake Exception classes.
  420. *
  421. * @return void
  422. */
  423. public static function testProvider() {
  424. return array(
  425. array(
  426. new MissingActionException(array(
  427. 'controller' => 'PostsController',
  428. 'action' => 'index',
  429. 'prefix' => '',
  430. 'plugin' => '',
  431. )),
  432. array(
  433. '/<h2>Missing Method in PostsController<\/h2>/',
  434. '/<em>PostsController::index\(\)<\/em>/'
  435. ),
  436. 404
  437. ),
  438. array(
  439. new PrivateActionException(array('controller' => 'PostsController', 'action' => '_secretSauce')),
  440. array(
  441. '/<h2>Private Method in PostsController<\/h2>/',
  442. '/<em>PostsController::_secretSauce\(\)<\/em>/'
  443. ),
  444. 404
  445. ),
  446. array(
  447. new MissingViewException(array('file' => '/posts/about.ctp')),
  448. array(
  449. "/posts\/about.ctp/"
  450. ),
  451. 500
  452. ),
  453. array(
  454. new MissingLayoutException(array('file' => 'layouts/my_layout.ctp')),
  455. array(
  456. "/Missing Layout/",
  457. "/layouts\/my_layout.ctp/"
  458. ),
  459. 500
  460. ),
  461. array(
  462. new MissingHelperException(array('class' => 'MyCustomHelper')),
  463. array(
  464. '/<h2>Missing Helper<\/h2>/',
  465. '/<em>MyCustomHelper<\/em> could not be found./',
  466. '/Create the class <em>MyCustomHelper<\/em> below in file:/',
  467. '/(\/|\\\)MyCustomHelper.php/'
  468. ),
  469. 500
  470. ),
  471. array(
  472. new MissingBehaviorException(array('class' => 'MyCustomBehavior')),
  473. array(
  474. '/<h2>Missing Behavior<\/h2>/',
  475. '/Create the class <em>MyCustomBehavior<\/em> below in file:/',
  476. '/(\/|\\\)MyCustomBehavior.php/'
  477. ),
  478. 500
  479. ),
  480. array(
  481. new MissingComponentException(array('class' => 'SideboxComponent')),
  482. array(
  483. '/<h2>Missing Component<\/h2>/',
  484. '/Create the class <em>SideboxComponent<\/em> below in file:/',
  485. '/(\/|\\\)SideboxComponent.php/'
  486. ),
  487. 500
  488. ),
  489. array(
  490. new \Exception('boom'),
  491. array(
  492. '/Internal Error/'
  493. ),
  494. 500
  495. ),
  496. array(
  497. new \RuntimeException('another boom'),
  498. array(
  499. '/Internal Error/'
  500. ),
  501. 500
  502. ),
  503. array(
  504. new Error\Exception('base class'),
  505. array('/Internal Error/'),
  506. 500
  507. )
  508. );
  509. }
  510. /**
  511. * Test the various Cake Exception sub classes
  512. *
  513. * @dataProvider testProvider
  514. * @return void
  515. */
  516. public function testCakeExceptionHandling($exception, $patterns, $code) {
  517. $ExceptionRenderer = new ExceptionRenderer($exception);
  518. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  519. $ExceptionRenderer->controller->response->expects($this->once())
  520. ->method('statusCode')
  521. ->with($code);
  522. ob_start();
  523. $ExceptionRenderer->render();
  524. $result = ob_get_clean();
  525. foreach ($patterns as $pattern) {
  526. $this->assertRegExp($pattern, $result);
  527. }
  528. }
  529. /**
  530. * Test exceptions being raised when helpers are missing.
  531. *
  532. * @return void
  533. */
  534. public function testMissingRenderSafe() {
  535. $exception = new MissingHelperException(array('class' => 'Fail'));
  536. $ExceptionRenderer = new ExceptionRenderer($exception);
  537. $ExceptionRenderer->controller = $this->getMock('Cake\Controller\Controller', array('render'));
  538. $ExceptionRenderer->controller->helpers = array('Fail', 'Boom');
  539. $ExceptionRenderer->controller->request = new Request;
  540. $ExceptionRenderer->controller->expects($this->at(0))
  541. ->method('render')
  542. ->with('missingHelper')
  543. ->will($this->throwException($exception));
  544. $response = $this->getMock('Cake\Network\Response');
  545. $response->expects($this->once())
  546. ->method('body')
  547. ->with($this->stringContains('Helper class Fail'));
  548. $ExceptionRenderer->controller->response = $response;
  549. $ExceptionRenderer->render();
  550. sort($ExceptionRenderer->controller->helpers);
  551. $this->assertEquals(array('Form', 'Html', 'Session'), $ExceptionRenderer->controller->helpers);
  552. }
  553. /**
  554. * Test that exceptions in beforeRender() are handled by outputMessageSafe
  555. *
  556. * @return void
  557. */
  558. public function testRenderExceptionInBeforeRender() {
  559. $exception = new Error\NotFoundException('Not there, sorry');
  560. $ExceptionRenderer = new ExceptionRenderer($exception);
  561. $ExceptionRenderer->controller = $this->getMock('Cake\Controller\Controller', array('beforeRender'));
  562. $ExceptionRenderer->controller->request = new Request;
  563. $ExceptionRenderer->controller->expects($this->any())
  564. ->method('beforeRender')
  565. ->will($this->throwException($exception));
  566. $response = $this->getMock('Cake\Network\Response');
  567. $response->expects($this->once())
  568. ->method('body')
  569. ->with($this->stringContains('Not there, sorry'));
  570. $ExceptionRenderer->controller->response = $response;
  571. $ExceptionRenderer->render();
  572. }
  573. /**
  574. * Test that missing subDir/layoutPath don't cause other fatal errors.
  575. *
  576. * @return void
  577. */
  578. public function testMissingSubdirRenderSafe() {
  579. $exception = new Error\NotFoundException();
  580. $ExceptionRenderer = new ExceptionRenderer($exception);
  581. $ExceptionRenderer->controller = $this->getMock('Cake\Controller\Controller', array('render'));
  582. $ExceptionRenderer->controller->helpers = array('Fail', 'Boom');
  583. $ExceptionRenderer->controller->layoutPath = 'boom';
  584. $ExceptionRenderer->controller->subDir = 'boom';
  585. $ExceptionRenderer->controller->request = new Request;
  586. $ExceptionRenderer->controller->expects($this->once())
  587. ->method('render')
  588. ->with('error400')
  589. ->will($this->throwException($exception));
  590. $response = $this->getMock('Cake\Network\Response');
  591. $response->expects($this->once())
  592. ->method('body')
  593. ->with($this->stringContains('Not Found'));
  594. $response->expects($this->once())
  595. ->method('type')
  596. ->with('html');
  597. $ExceptionRenderer->controller->response = $response;
  598. $ExceptionRenderer->render();
  599. $this->assertEquals('', $ExceptionRenderer->controller->layoutPath);
  600. $this->assertEquals('', $ExceptionRenderer->controller->subDir);
  601. $this->assertEquals('Error', $ExceptionRenderer->controller->viewPath);
  602. }
  603. /**
  604. * Test that exceptions can be rendered when an request hasn't been registered
  605. * with Router
  606. *
  607. * @return void
  608. */
  609. public function testRenderWithNoRequest() {
  610. Router::reload();
  611. $this->assertNull(Router::getRequest(false));
  612. $exception = new \Exception('Terrible');
  613. $ExceptionRenderer = new ExceptionRenderer($exception);
  614. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  615. $ExceptionRenderer->controller->response->expects($this->once())
  616. ->method('statusCode')
  617. ->with(500);
  618. ob_start();
  619. $ExceptionRenderer->render();
  620. $result = ob_get_clean();
  621. $this->assertContains('Internal Error', $result);
  622. }
  623. /**
  624. * Tests the output of rendering a PDOException
  625. *
  626. * @return void
  627. */
  628. public function testPDOException() {
  629. $exception = new \PDOException('There was an error in the SQL query');
  630. $exception->queryString = 'SELECT * from poo_query < 5 and :seven';
  631. $exception->params = array('seven' => 7);
  632. $ExceptionRenderer = new ExceptionRenderer($exception);
  633. $ExceptionRenderer->controller->response = $this->getMock('Cake\Network\Response', array('statusCode', '_sendHeader'));
  634. $ExceptionRenderer->controller->response->expects($this->once())->method('statusCode')->with(500);
  635. ob_start();
  636. $ExceptionRenderer->render();
  637. $result = ob_get_clean();
  638. $this->assertContains('<h2>Database Error</h2>', $result);
  639. $this->assertContains('There was an error in the SQL query', $result);
  640. $this->assertContains(h('SELECT * from poo_query < 5 and :seven'), $result);
  641. $this->assertContains("'seven' => (int) 7", $result);
  642. }
  643. }