Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

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