ExceptionRendererTest.php 21 KB

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