ExceptionRendererTest.php 21 KB

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