PageRenderTime 40ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/Cake/Test/Case/Error/ExceptionRendererTest.php

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