Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11
 * @link          http://cakephp.org CakePHP(tm) Project
12
 * @package       Cake.Test.Case.Network
13
 * @since         CakePHP(tm) v 2.0
14
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
15
 */
16
 
17
App::uses('CakeResponse', 'Network');
18
App::uses('CakeRequest', 'Network');
19
 
20
/**
21
 * Class CakeResponseTest
22
 *
23
 * @package       Cake.Test.Case.Network
24
 */
25
class CakeResponseTest extends CakeTestCase {
26
 
27
/**
28
 * Setup for tests
29
 *
30
 * @return void
31
 */
32
	public function setUp() {
33
		parent::setUp();
34
		ob_start();
35
	}
36
 
37
/**
38
 * Cleanup after tests
39
 *
40
 * @return void
41
 */
42
	public function tearDown() {
43
		parent::tearDown();
44
		ob_end_clean();
45
	}
46
 
47
/**
48
 * Tests the request object constructor
49
 *
50
 * @return void
51
 */
52
	public function testConstruct() {
53
		$response = new CakeResponse();
54
		$this->assertNull($response->body());
55
		$this->assertEquals('UTF-8', $response->charset());
56
		$this->assertEquals('text/html', $response->type());
57
		$this->assertEquals(200, $response->statusCode());
58
 
59
		$options = array(
60
			'body' => 'This is the body',
61
			'charset' => 'my-custom-charset',
62
			'type' => 'mp3',
63
			'status' => '203'
64
		);
65
		$response = new CakeResponse($options);
66
		$this->assertEquals('This is the body', $response->body());
67
		$this->assertEquals('my-custom-charset', $response->charset());
68
		$this->assertEquals('audio/mpeg', $response->type());
69
		$this->assertEquals(203, $response->statusCode());
70
 
71
		$options = array(
72
			'body' => 'This is the body',
73
			'charset' => 'my-custom-charset',
74
			'type' => 'mp3',
75
			'status' => '422',
76
			'statusCodes' => array(
77
				422 => 'Unprocessable Entity'
78
			)
79
		);
80
		$response = new CakeResponse($options);
81
		$this->assertEquals($options['body'], $response->body());
82
		$this->assertEquals($options['charset'], $response->charset());
83
		$this->assertEquals($response->getMimeType($options['type']), $response->type());
84
		$this->assertEquals($options['status'], $response->statusCode());
85
	}
86
 
87
/**
88
 * Tests the body method
89
 *
90
 * @return void
91
 */
92
	public function testBody() {
93
		$response = new CakeResponse();
94
		$this->assertNull($response->body());
95
		$response->body('Response body');
96
		$this->assertEquals('Response body', $response->body());
97
		$this->assertEquals('Changed Body', $response->body('Changed Body'));
98
	}
99
 
100
/**
101
 * Tests the charset method
102
 *
103
 * @return void
104
 */
105
	public function testCharset() {
106
		$response = new CakeResponse();
107
		$this->assertEquals('UTF-8', $response->charset());
108
		$response->charset('iso-8859-1');
109
		$this->assertEquals('iso-8859-1', $response->charset());
110
		$this->assertEquals('UTF-16', $response->charset('UTF-16'));
111
	}
112
 
113
/**
114
 * Tests the statusCode method
115
 *
116
 * @expectedException CakeException
117
 * @return void
118
 */
119
	public function testStatusCode() {
120
		$response = new CakeResponse();
121
		$this->assertEquals(200, $response->statusCode());
122
		$response->statusCode(404);
123
		$this->assertEquals(404, $response->statusCode());
124
		$this->assertEquals(500, $response->statusCode(500));
125
 
126
		//Throws exception
127
		$response->statusCode(1001);
128
	}
129
 
130
/**
131
 * Tests the type method
132
 *
133
 * @return void
134
 */
135
	public function testType() {
136
		$response = new CakeResponse();
137
		$this->assertEquals('text/html', $response->type());
138
		$response->type('pdf');
139
		$this->assertEquals('application/pdf', $response->type());
140
		$this->assertEquals('application/crazy-mime', $response->type('application/crazy-mime'));
141
		$this->assertEquals('application/json', $response->type('json'));
142
		$this->assertEquals('text/vnd.wap.wml', $response->type('wap'));
143
		$this->assertEquals('application/vnd.wap.xhtml+xml', $response->type('xhtml-mobile'));
144
		$this->assertEquals('text/csv', $response->type('csv'));
145
 
146
		$response->type(array('keynote' => 'application/keynote', 'bat' => 'application/bat'));
147
		$this->assertEquals('application/keynote', $response->type('keynote'));
148
		$this->assertEquals('application/bat', $response->type('bat'));
149
 
150
		$this->assertFalse($response->type('wackytype'));
151
	}
152
 
153
/**
154
 * Tests the header method
155
 *
156
 * @return void
157
 */
158
	public function testHeader() {
159
		$response = new CakeResponse();
160
		$headers = array();
161
		$this->assertEquals($headers, $response->header());
162
 
163
		$response->header('Location', 'http://example.com');
164
		$headers += array('Location' => 'http://example.com');
165
		$this->assertEquals($headers, $response->header());
166
 
167
		//Headers with the same name are overwritten
168
		$response->header('Location', 'http://example2.com');
169
		$headers = array('Location' => 'http://example2.com');
170
		$this->assertEquals($headers, $response->header());
171
 
172
		$response->header(array('WWW-Authenticate' => 'Negotiate'));
173
		$headers += array('WWW-Authenticate' => 'Negotiate');
174
		$this->assertEquals($headers, $response->header());
175
 
176
		$response->header(array('WWW-Authenticate' => 'Not-Negotiate'));
177
		$headers['WWW-Authenticate'] = 'Not-Negotiate';
178
		$this->assertEquals($headers, $response->header());
179
 
180
		$response->header(array('Age' => 12, 'Allow' => 'GET, HEAD'));
181
		$headers += array('Age' => 12, 'Allow' => 'GET, HEAD');
182
		$this->assertEquals($headers, $response->header());
183
 
184
		// String headers are allowed
185
		$response->header('Content-Language: da');
186
		$headers += array('Content-Language' => 'da');
187
		$this->assertEquals($headers, $response->header());
188
 
189
		$response->header('Content-Language: da');
190
		$headers += array('Content-Language' => 'da');
191
		$this->assertEquals($headers, $response->header());
192
 
193
		$response->header(array('Content-Encoding: gzip', 'Vary: *', 'Pragma' => 'no-cache'));
194
		$headers += array('Content-Encoding' => 'gzip', 'Vary' => '*', 'Pragma' => 'no-cache');
195
		$this->assertEquals($headers, $response->header());
196
 
197
		$response->header('Access-Control-Allow-Origin', array('domain1', 'domain2'));
198
		$headers += array('Access-Control-Allow-Origin' => array('domain1', 'domain2'));
199
		$this->assertEquals($headers, $response->header());
200
	}
201
 
202
/**
203
 * Tests the send method
204
 *
205
 * @return void
206
 */
207
	public function testSend() {
208
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent', '_setCookies'));
209
		$response->header(array(
210
			'Content-Language' => 'es',
211
			'WWW-Authenticate' => 'Negotiate',
212
			'Access-Control-Allow-Origin' => array('domain1', 'domain2'),
213
		));
214
		$response->body('the response body');
215
		$response->expects($this->once())->method('_sendContent')->with('the response body');
216
		$response->expects($this->at(0))->method('_setCookies');
217
		$response->expects($this->at(1))
218
			->method('_sendHeader')->with('HTTP/1.1 200 OK');
219
		$response->expects($this->at(2))
220
			->method('_sendHeader')->with('Content-Language', 'es');
221
		$response->expects($this->at(3))
222
			->method('_sendHeader')->with('WWW-Authenticate', 'Negotiate');
223
		$response->expects($this->at(4))
224
			->method('_sendHeader')->with('Access-Control-Allow-Origin', 'domain1');
225
		$response->expects($this->at(5))
226
			->method('_sendHeader')->with('Access-Control-Allow-Origin', 'domain2');
227
		$response->expects($this->at(6))
228
			->method('_sendHeader')->with('Content-Length', 17);
229
		$response->expects($this->at(7))
230
			->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
231
		$response->send();
232
	}
233
 
234
/**
235
 * Data provider for content type tests.
236
 *
237
 * @return array
238
 */
239
	public static function charsetTypeProvider() {
240
		return array(
241
			array('mp3', 'audio/mpeg'),
242
			array('js', 'application/javascript; charset=UTF-8'),
243
			array('json', 'application/json; charset=UTF-8'),
244
			array('xml', 'application/xml; charset=UTF-8'),
245
			array('txt', 'text/plain; charset=UTF-8'),
246
		);
247
	}
248
 
249
/**
250
 * Tests the send method and changing the content type
251
 *
252
 * @dataProvider charsetTypeProvider
253
 * @return void
254
 */
255
	public function testSendChangingContentType($original, $expected) {
256
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent', '_setCookies'));
257
		$response->type($original);
258
		$response->body('the response body');
259
		$response->expects($this->once())->method('_sendContent')->with('the response body');
260
		$response->expects($this->at(0))->method('_setCookies');
261
		$response->expects($this->at(1))
262
			->method('_sendHeader')->with('HTTP/1.1 200 OK');
263
		$response->expects($this->at(2))
264
			->method('_sendHeader')->with('Content-Length', 17);
265
		$response->expects($this->at(3))
266
			->method('_sendHeader')->with('Content-Type', $expected);
267
		$response->send();
268
	}
269
 
270
/**
271
 * Tests the send method and changing the content type to JS without adding the charset
272
 *
273
 * @return void
274
 */
275
	public function testSendChangingContentTypeWithoutCharset() {
276
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent', '_setCookies'));
277
		$response->type('js');
278
		$response->charset('');
279
 
280
		$response->body('var $foo = "bar";');
281
		$response->expects($this->once())->method('_sendContent')->with('var $foo = "bar";');
282
		$response->expects($this->at(0))->method('_setCookies');
283
		$response->expects($this->at(1))
284
			->method('_sendHeader')->with('HTTP/1.1 200 OK');
285
		$response->expects($this->at(2))
286
			->method('_sendHeader')->with('Content-Length', 17);
287
		$response->expects($this->at(3))
288
			->method('_sendHeader')->with('Content-Type', 'application/javascript');
289
		$response->send();
290
	}
291
 
292
/**
293
 * Tests the send method and changing the content type
294
 *
295
 * @return void
296
 */
297
	public function testSendWithLocation() {
298
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent', '_setCookies'));
299
		$response->header('Location', 'http://www.example.com');
300
		$response->expects($this->at(0))->method('_setCookies');
301
		$response->expects($this->at(1))
302
			->method('_sendHeader')->with('HTTP/1.1 302 Found');
303
		$response->expects($this->at(2))
304
			->method('_sendHeader')->with('Location', 'http://www.example.com');
305
		$response->expects($this->at(3))
306
			->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
307
		$response->send();
308
	}
309
 
310
/**
311
 * Tests the disableCache method
312
 *
313
 * @return void
314
 */
315
	public function testDisableCache() {
316
		$response = new CakeResponse();
317
		$expected = array(
318
			'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT',
319
			'Last-Modified' => gmdate("D, d M Y H:i:s") . " GMT",
320
			'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
321
		);
322
		$response->disableCache();
323
		$this->assertEquals($expected, $response->header());
324
	}
325
 
326
/**
327
 * Tests the cache method
328
 *
329
 * @return void
330
 */
331
	public function testCache() {
332
		$response = new CakeResponse();
333
		$since = time();
334
		$time = new DateTime('+1 day', new DateTimeZone('UTC'));
335
		$response->expires('+1 day');
336
		$expected = array(
337
			'Date' => gmdate("D, j M Y G:i:s ", $since) . 'GMT',
338
			'Last-Modified' => gmdate("D, j M Y H:i:s ", $since) . 'GMT',
339
			'Expires' => $time->format('D, j M Y H:i:s') . ' GMT',
340
			'Cache-Control' => 'public, max-age=' . ($time->format('U') - time())
341
		);
342
		$response->cache($since);
343
		$this->assertEquals($expected, $response->header());
344
 
345
		$response = new CakeResponse();
346
		$since = time();
347
		$time = '+5 day';
348
		$expected = array(
349
			'Date' => gmdate("D, j M Y G:i:s ", $since) . 'GMT',
350
			'Last-Modified' => gmdate("D, j M Y H:i:s ", $since) . 'GMT',
351
			'Expires' => gmdate("D, j M Y H:i:s", strtotime($time)) . " GMT",
352
			'Cache-Control' => 'public, max-age=' . (strtotime($time) - time())
353
		);
354
		$response->cache($since, $time);
355
		$this->assertEquals($expected, $response->header());
356
 
357
		$response = new CakeResponse();
358
		$since = time();
359
		$time = time();
360
		$expected = array(
361
			'Date' => gmdate("D, j M Y G:i:s ", $since) . 'GMT',
362
			'Last-Modified' => gmdate("D, j M Y H:i:s ", $since) . 'GMT',
363
			'Expires' => gmdate("D, j M Y H:i:s", $time) . " GMT",
364
			'Cache-Control' => 'public, max-age=0'
365
		);
366
		$response->cache($since, $time);
367
		$this->assertEquals($expected, $response->header());
368
	}
369
 
370
/**
371
 * Tests the compress method
372
 *
373
 * @return void
374
 */
375
	public function testCompress() {
376
		if (PHP_SAPI !== 'cli') {
377
			$this->markTestSkipped('The response compression can only be tested in cli.');
378
		}
379
 
380
		$response = new CakeResponse();
381
		if (ini_get("zlib.output_compression") === '1' || !extension_loaded("zlib")) {
382
			$this->assertFalse($response->compress());
383
			$this->markTestSkipped('Is not possible to test output compression');
384
		}
385
 
386
		$_SERVER['HTTP_ACCEPT_ENCODING'] = '';
387
		$result = $response->compress();
388
		$this->assertFalse($result);
389
 
390
		$_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip';
391
		$result = $response->compress();
392
		$this->assertTrue($result);
393
		$this->assertTrue(in_array('ob_gzhandler', ob_list_handlers()));
394
 
395
		ob_get_clean();
396
	}
397
 
398
/**
399
 * Tests the httpCodes method
400
 *
401
 * @expectedException CakeException
402
 * @return void
403
 */
404
	public function testHttpCodes() {
405
		$response = new CakeResponse();
406
		$result = $response->httpCodes();
407
		$this->assertEquals(41, count($result));
408
 
409
		$result = $response->httpCodes(100);
410
		$expected = array(100 => 'Continue');
411
		$this->assertEquals($expected, $result);
412
 
413
		$codes = array(
414
			381 => 'Unicorn Moved',
415
			555 => 'Unexpected Minotaur'
416
		);
417
 
418
		$result = $response->httpCodes($codes);
419
		$this->assertTrue($result);
420
		$this->assertEquals(43, count($response->httpCodes()));
421
 
422
		$result = $response->httpCodes(381);
423
		$expected = array(381 => 'Unicorn Moved');
424
		$this->assertEquals($expected, $result);
425
 
426
		$codes = array(404 => 'Sorry Bro');
427
		$result = $response->httpCodes($codes);
428
		$this->assertTrue($result);
429
		$this->assertEquals(43, count($response->httpCodes()));
430
 
431
		$result = $response->httpCodes(404);
432
		$expected = array(404 => 'Sorry Bro');
433
		$this->assertEquals($expected, $result);
434
 
435
		//Throws exception
436
		$response->httpCodes(array(
437
 
438
			-1 => 'Reverse Infinity',
439
			12345 => 'Universal Password',
440
			'Hello' => 'World'
441
		));
442
	}
443
 
444
/**
445
 * Tests the download method
446
 *
447
 * @return void
448
 */
449
	public function testDownload() {
450
		$response = new CakeResponse();
451
		$expected = array(
452
			'Content-Disposition' => 'attachment; filename="myfile.mp3"'
453
		);
454
		$response->download('myfile.mp3');
455
		$this->assertEquals($expected, $response->header());
456
	}
457
 
458
/**
459
 * Tests the mapType method
460
 *
461
 * @return void
462
 */
463
	public function testMapType() {
464
		$response = new CakeResponse();
465
		$this->assertEquals('wav', $response->mapType('audio/x-wav'));
466
		$this->assertEquals('pdf', $response->mapType('application/pdf'));
467
		$this->assertEquals('xml', $response->mapType('text/xml'));
468
		$this->assertEquals('html', $response->mapType('*/*'));
469
		$this->assertEquals('csv', $response->mapType('application/vnd.ms-excel'));
470
		$expected = array('json', 'xhtml', 'css');
471
		$result = $response->mapType(array('application/json', 'application/xhtml+xml', 'text/css'));
472
		$this->assertEquals($expected, $result);
473
	}
474
 
475
/**
476
 * Tests the outputCompressed method
477
 *
478
 * @return void
479
 */
480
	public function testOutputCompressed() {
481
		$response = new CakeResponse();
482
 
483
		$_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip';
484
		$result = $response->outputCompressed();
485
		$this->assertFalse($result);
486
 
487
		$_SERVER['HTTP_ACCEPT_ENCODING'] = '';
488
		$result = $response->outputCompressed();
489
		$this->assertFalse($result);
490
 
491
		if (!extension_loaded("zlib")) {
492
			$this->markTestSkipped('Skipping further tests for outputCompressed as zlib extension is not loaded');
493
		}
494
		if (PHP_SAPI !== 'cli') {
495
			$this->markTestSkipped('Testing outputCompressed method with compression enabled done only in cli');
496
		}
497
 
498
		if (ini_get("zlib.output_compression") !== '1') {
499
			ob_start('ob_gzhandler');
500
		}
501
		$_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip';
502
		$result = $response->outputCompressed();
503
		$this->assertTrue($result);
504
 
505
		$_SERVER['HTTP_ACCEPT_ENCODING'] = '';
506
		$result = $response->outputCompressed();
507
		$this->assertFalse($result);
508
		if (ini_get("zlib.output_compression") !== '1') {
509
			ob_get_clean();
510
		}
511
	}
512
 
513
/**
514
 * Tests the send and setting of Content-Length
515
 *
516
 * @return void
517
 */
518
	public function testSendContentLength() {
519
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
520
		$response->body('the response body');
521
		$response->expects($this->once())->method('_sendContent')->with('the response body');
522
		$response->expects($this->at(0))
523
			->method('_sendHeader')->with('HTTP/1.1 200 OK');
524
		$response->expects($this->at(2))
525
			->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
526
		$response->expects($this->at(1))
527
			->method('_sendHeader')->with('Content-Length', strlen('the response body'));
528
		$response->send();
529
 
530
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
531
		$body = '長い長い長いSubjectの場合はfoldingするのが正しいんだけどいったいどうなるんだろう?';
532
		$response->body($body);
533
		$response->expects($this->once())->method('_sendContent')->with($body);
534
		$response->expects($this->at(0))
535
			->method('_sendHeader')->with('HTTP/1.1 200 OK');
536
		$response->expects($this->at(2))
537
			->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
538
		$response->expects($this->at(1))
539
			->method('_sendHeader')->with('Content-Length', 116);
540
		$response->send();
541
 
542
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent', 'outputCompressed'));
543
		$body = '長い長い長いSubjectの場合はfoldingするのが正しいんだけどいったいどうなるんだろう?';
544
		$response->body($body);
545
		$response->expects($this->once())->method('outputCompressed')->will($this->returnValue(true));
546
		$response->expects($this->once())->method('_sendContent')->with($body);
547
		$response->expects($this->exactly(2))->method('_sendHeader');
548
		$response->send();
549
 
550
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent', 'outputCompressed'));
551
		$body = 'hwy';
552
		$response->body($body);
553
		$response->header('Content-Length', 1);
554
		$response->expects($this->never())->method('outputCompressed');
555
		$response->expects($this->once())->method('_sendContent')->with($body);
556
		$response->expects($this->at(1))
557
				->method('_sendHeader')->with('Content-Length', 1);
558
		$response->send();
559
 
560
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
561
		$body = 'content';
562
		$response->statusCode(301);
563
		$response->body($body);
564
		$response->expects($this->once())->method('_sendContent')->with($body);
565
		$response->expects($this->exactly(2))->method('_sendHeader');
566
		$response->send();
567
 
568
		ob_start();
569
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
570
		$goofyOutput = 'I am goofily sending output in the controller';
571
		echo $goofyOutput;
572
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
573
		$body = '長い長い長いSubjectの場合はfoldingするのが正しいんだけどいったいどうなるんだろう?';
574
		$response->body($body);
575
		$response->expects($this->once())->method('_sendContent')->with($body);
576
		$response->expects($this->at(0))
577
			->method('_sendHeader')->with('HTTP/1.1 200 OK');
578
		$response->expects($this->at(1))
579
			->method('_sendHeader')->with('Content-Length', strlen($goofyOutput) + 116);
580
		$response->expects($this->at(2))
581
			->method('_sendHeader')->with('Content-Type', 'text/html; charset=UTF-8');
582
		$response->send();
583
		ob_end_clean();
584
	}
585
 
586
/**
587
 * Tests getting/setting the protocol
588
 *
589
 * @return void
590
 */
591
	public function testProtocol() {
592
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
593
		$response->protocol('HTTP/1.0');
594
		$this->assertEquals('HTTP/1.0', $response->protocol());
595
		$response->expects($this->at(0))
596
			->method('_sendHeader')->with('HTTP/1.0 200 OK');
597
		$response->send();
598
	}
599
 
600
/**
601
 * Tests getting/setting the Content-Length
602
 *
603
 * @return void
604
 */
605
	public function testLength() {
606
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
607
		$response->length(100);
608
		$this->assertEquals(100, $response->length());
609
		$response->expects($this->at(1))
610
			->method('_sendHeader')->with('Content-Length', 100);
611
		$response->send();
612
 
613
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
614
		$response->length(false);
615
		$this->assertFalse($response->length());
616
		$response->expects($this->exactly(2))
617
			->method('_sendHeader');
618
		$response->send();
619
	}
620
 
621
/**
622
 * Tests that the response body is unset if the status code is 304 or 204
623
 *
624
 * @return void
625
 */
626
	public function testUnmodifiedContent() {
627
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
628
		$response->body('This is a body');
629
		$response->statusCode(204);
630
		$response->expects($this->once())
631
			->method('_sendContent')->with('');
632
		$response->send();
633
		$this->assertFalse(array_key_exists('Content-Type', $response->header()));
634
 
635
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
636
		$response->body('This is a body');
637
		$response->statusCode(304);
638
		$response->expects($this->once())
639
			->method('_sendContent')->with('');
640
		$response->send();
641
 
642
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
643
		$response->body('This is a body');
644
		$response->statusCode(200);
645
		$response->expects($this->once())
646
			->method('_sendContent')->with('This is a body');
647
		$response->send();
648
	}
649
 
650
/**
651
 * Tests setting the expiration date
652
 *
653
 * @return void
654
 */
655
	public function testExpires() {
656
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
657
		$now = new DateTime('now', new DateTimeZone('America/Los_Angeles'));
658
		$response->expires($now);
659
		$now->setTimeZone(new DateTimeZone('UTC'));
660
		$this->assertEquals($now->format('D, j M Y H:i:s') . ' GMT', $response->expires());
661
		$response->expects($this->at(1))
662
			->method('_sendHeader')->with('Expires', $now->format('D, j M Y H:i:s') . ' GMT');
663
		$response->send();
664
 
665
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
666
		$now = time();
667
		$response->expires($now);
668
		$this->assertEquals(gmdate('D, j M Y H:i:s', $now) . ' GMT', $response->expires());
669
		$response->expects($this->at(1))
670
			->method('_sendHeader')->with('Expires', gmdate('D, j M Y H:i:s', $now) . ' GMT');
671
		$response->send();
672
 
673
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
674
		$time = new DateTime('+1 day', new DateTimeZone('UTC'));
675
		$response->expires('+1 day');
676
		$this->assertEquals($time->format('D, j M Y H:i:s') . ' GMT', $response->expires());
677
		$response->expects($this->at(1))
678
			->method('_sendHeader')->with('Expires', $time->format('D, j M Y H:i:s') . ' GMT');
679
		$response->send();
680
	}
681
 
682
/**
683
 * Tests setting the modification date
684
 *
685
 * @return void
686
 */
687
	public function testModified() {
688
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
689
		$now = new DateTime('now', new DateTimeZone('America/Los_Angeles'));
690
		$response->modified($now);
691
		$now->setTimeZone(new DateTimeZone('UTC'));
692
		$this->assertEquals($now->format('D, j M Y H:i:s') . ' GMT', $response->modified());
693
		$response->expects($this->at(1))
694
			->method('_sendHeader')->with('Last-Modified', $now->format('D, j M Y H:i:s') . ' GMT');
695
		$response->send();
696
 
697
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
698
		$now = time();
699
		$response->modified($now);
700
		$this->assertEquals(gmdate('D, j M Y H:i:s', $now) . ' GMT', $response->modified());
701
		$response->expects($this->at(1))
702
			->method('_sendHeader')->with('Last-Modified', gmdate('D, j M Y H:i:s', $now) . ' GMT');
703
		$response->send();
704
 
705
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
706
		$time = new DateTime('+1 day', new DateTimeZone('UTC'));
707
		$response->modified('+1 day');
708
		$this->assertEquals($time->format('D, j M Y H:i:s') . ' GMT', $response->modified());
709
		$response->expects($this->at(1))
710
			->method('_sendHeader')->with('Last-Modified', $time->format('D, j M Y H:i:s') . ' GMT');
711
		$response->send();
712
	}
713
 
714
/**
715
 * Tests setting of public/private Cache-Control directives
716
 *
717
 * @return void
718
 */
719
	public function testSharable() {
720
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
721
		$this->assertNull($response->sharable());
722
		$response->sharable(true);
723
		$headers = $response->header();
724
		$this->assertEquals('public', $headers['Cache-Control']);
725
		$response->expects($this->at(1))
726
			->method('_sendHeader')->with('Cache-Control', 'public');
727
		$response->send();
728
 
729
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
730
		$response->sharable(false);
731
		$headers = $response->header();
732
		$this->assertEquals('private', $headers['Cache-Control']);
733
		$response->expects($this->at(1))
734
			->method('_sendHeader')->with('Cache-Control', 'private');
735
		$response->send();
736
 
737
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
738
		$response->sharable(true);
739
		$headers = $response->header();
740
		$this->assertEquals('public', $headers['Cache-Control']);
741
		$response->sharable(false);
742
		$headers = $response->header();
743
		$this->assertEquals('private', $headers['Cache-Control']);
744
		$response->expects($this->at(1))
745
			->method('_sendHeader')->with('Cache-Control', 'private');
746
		$response->send();
747
		$this->assertFalse($response->sharable());
748
		$response->sharable(true);
749
		$this->assertTrue($response->sharable());
750
 
751
		$response = new CakeResponse;
752
		$response->sharable(true, 3600);
753
		$headers = $response->header();
754
		$this->assertEquals('public, max-age=3600', $headers['Cache-Control']);
755
 
756
		$response = new CakeResponse;
757
		$response->sharable(false, 3600);
758
		$headers = $response->header();
759
		$this->assertEquals('private, max-age=3600', $headers['Cache-Control']);
760
		$response->send();
761
	}
762
 
763
/**
764
 * Tests setting of max-age Cache-Control directive
765
 *
766
 * @return void
767
 */
768
	public function testMaxAge() {
769
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
770
		$this->assertNull($response->maxAge());
771
		$response->maxAge(3600);
772
		$this->assertEquals(3600, $response->maxAge());
773
		$headers = $response->header();
774
		$this->assertEquals('max-age=3600', $headers['Cache-Control']);
775
		$response->expects($this->at(1))
776
			->method('_sendHeader')->with('Cache-Control', 'max-age=3600');
777
		$response->send();
778
 
779
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
780
		$response->maxAge(3600);
781
		$response->sharable(false);
782
		$headers = $response->header();
783
		$this->assertEquals('max-age=3600, private', $headers['Cache-Control']);
784
		$response->expects($this->at(1))
785
			->method('_sendHeader')->with('Cache-Control', 'max-age=3600, private');
786
		$response->send();
787
	}
788
 
789
/**
790
 * Tests setting of s-maxage Cache-Control directive
791
 *
792
 * @return void
793
 */
794
	public function testSharedMaxAge() {
795
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
796
		$this->assertNull($response->maxAge());
797
		$response->sharedMaxAge(3600);
798
		$this->assertEquals(3600, $response->sharedMaxAge());
799
		$headers = $response->header();
800
		$this->assertEquals('s-maxage=3600', $headers['Cache-Control']);
801
		$response->expects($this->at(1))
802
			->method('_sendHeader')->with('Cache-Control', 's-maxage=3600');
803
		$response->send();
804
 
805
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
806
		$response->sharedMaxAge(3600);
807
		$response->sharable(true);
808
		$headers = $response->header();
809
		$this->assertEquals('s-maxage=3600, public', $headers['Cache-Control']);
810
		$response->expects($this->at(1))
811
			->method('_sendHeader')->with('Cache-Control', 's-maxage=3600, public');
812
		$response->send();
813
	}
814
 
815
/**
816
 * Tests setting of must-revalidate Cache-Control directive
817
 *
818
 * @return void
819
 */
820
	public function testMustRevalidate() {
821
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
822
		$this->assertFalse($response->mustRevalidate());
823
		$response->mustRevalidate(true);
824
		$this->assertTrue($response->mustRevalidate());
825
		$headers = $response->header();
826
		$this->assertEquals('must-revalidate', $headers['Cache-Control']);
827
		$response->expects($this->at(1))
828
			->method('_sendHeader')->with('Cache-Control', 'must-revalidate');
829
		$response->send();
830
		$response->mustRevalidate(false);
831
		$this->assertFalse($response->mustRevalidate());
832
 
833
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
834
		$response->sharedMaxAge(3600);
835
		$response->mustRevalidate(true);
836
		$headers = $response->header();
837
		$this->assertEquals('s-maxage=3600, must-revalidate', $headers['Cache-Control']);
838
		$response->expects($this->at(1))
839
			->method('_sendHeader')->with('Cache-Control', 's-maxage=3600, must-revalidate');
840
		$response->send();
841
	}
842
 
843
/**
844
 * Tests getting/setting the Vary header
845
 *
846
 * @return void
847
 */
848
	public function testVary() {
849
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
850
		$response->vary('Accept-encoding');
851
		$this->assertEquals(array('Accept-encoding'), $response->vary());
852
		$response->expects($this->at(1))
853
			->method('_sendHeader')->with('Vary', 'Accept-encoding');
854
		$response->send();
855
 
856
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
857
		$response->vary(array('Accept-language', 'Accept-encoding'));
858
		$response->expects($this->at(1))
859
			->method('_sendHeader')->with('Vary', 'Accept-language, Accept-encoding');
860
		$response->send();
861
		$this->assertEquals(array('Accept-language', 'Accept-encoding'), $response->vary());
862
	}
863
 
864
/**
865
 * Tests getting/setting the Etag header
866
 *
867
 * @return void
868
 */
869
	public function testEtag() {
870
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
871
		$response->etag('something');
872
		$this->assertEquals('"something"', $response->etag());
873
		$response->expects($this->at(1))
874
			->method('_sendHeader')->with('Etag', '"something"');
875
		$response->send();
876
 
877
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
878
		$response->etag('something', true);
879
		$this->assertEquals('W/"something"', $response->etag());
880
		$response->expects($this->at(1))
881
			->method('_sendHeader')->with('Etag', 'W/"something"');
882
		$response->send();
883
	}
884
 
885
/**
886
 * Tests that the response is able to be marked as not modified
887
 *
888
 * @return void
889
 */
890
	public function testNotModified() {
891
		$response = $this->getMock('CakeResponse', array('_sendHeader', '_sendContent'));
892
		$response->body('something');
893
		$response->statusCode(200);
894
		$response->length(100);
895
		$response->modified('now');
896
		$response->notModified();
897
 
898
		$this->assertEmpty($response->header());
899
		$this->assertEmpty($response->body());
900
		$this->assertEquals(304, $response->statusCode());
901
	}
902
 
903
/**
904
 * Test checkNotModified method
905
 *
906
 * @return void
907
 */
908
	public function testCheckNotModifiedByEtagStar() {
909
		$_SERVER['HTTP_IF_NONE_MATCH'] = '*';
910
		$response = $this->getMock('CakeResponse', array('notModified'));
911
		$response->etag('something');
912
		$response->expects($this->once())->method('notModified');
913
		$response->checkNotModified(new CakeRequest);
914
	}
915
 
916
/**
917
 * Test checkNotModified method
918
 *
919
 * @return void
920
 */
921
	public function testCheckNotModifiedByEtagExact() {
922
		$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
923
		$response = $this->getMock('CakeResponse', array('notModified'));
924
		$response->etag('something', true);
925
		$response->expects($this->once())->method('notModified');
926
		$this->assertTrue($response->checkNotModified(new CakeRequest));
927
	}
928
 
929
/**
930
 * Test checkNotModified method
931
 *
932
 * @return void
933
 */
934
	public function testCheckNotModifiedByEtagAndTime() {
935
		$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
936
		$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
937
		$response = $this->getMock('CakeResponse', array('notModified'));
938
		$response->etag('something', true);
939
		$response->modified('2012-01-01 00:00:00');
940
		$response->expects($this->once())->method('notModified');
941
		$this->assertTrue($response->checkNotModified(new CakeRequest));
942
	}
943
 
944
/**
945
 * Test checkNotModified method
946
 *
947
 * @return void
948
 */
949
	public function testCheckNotModifiedByEtagAndTimeMismatch() {
950
		$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
951
		$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
952
		$response = $this->getMock('CakeResponse', array('notModified'));
953
		$response->etag('something', true);
954
		$response->modified('2012-01-01 00:00:01');
955
		$response->expects($this->never())->method('notModified');
956
		$this->assertFalse($response->checkNotModified(new CakeRequest));
957
	}
958
 
959
/**
960
 * Test checkNotModified method
961
 *
962
 * @return void
963
 */
964
	public function testCheckNotModifiedByEtagMismatch() {
965
		$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something-else", "other"';
966
		$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
967
		$response = $this->getMock('CakeResponse', array('notModified'));
968
		$response->etag('something', true);
969
		$response->modified('2012-01-01 00:00:00');
970
		$response->expects($this->never())->method('notModified');
971
		$this->assertFalse($response->checkNotModified(new CakeRequest));
972
	}
973
 
974
/**
975
 * Test checkNotModified method
976
 *
977
 * @return void
978
 */
979
	public function testCheckNotModifiedByTime() {
980
		$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
981
		$response = $this->getMock('CakeResponse', array('notModified'));
982
		$response->modified('2012-01-01 00:00:00');
983
		$response->expects($this->once())->method('notModified');
984
		$this->assertTrue($response->checkNotModified(new CakeRequest));
985
	}
986
 
987
/**
988
 * Test checkNotModified method
989
 *
990
 * @return void
991
 */
992
	public function testCheckNotModifiedNoHints() {
993
		$_SERVER['HTTP_IF_NONE_MATCH'] = 'W/"something", "other"';
994
		$_SERVER['HTTP_IF_MODIFIED_SINCE'] = '2012-01-01 00:00:00';
995
		$response = $this->getMock('CakeResponse', array('notModified'));
996
		$response->expects($this->never())->method('notModified');
997
		$this->assertFalse($response->checkNotModified(new CakeRequest));
998
	}
999
 
1000
/**
1001
 * Test cookie setting
1002
 *
1003
 * @return void
1004
 */
1005
	public function testCookieSettings() {
1006
		$response = new CakeResponse();
1007
		$cookie = array(
1008
			'name' => 'CakeTestCookie[Testing]'
1009
		);
1010
		$response->cookie($cookie);
1011
		$expected = array(
1012
			'name' => 'CakeTestCookie[Testing]',
1013
			'value' => '',
1014
			'expire' => 0,
1015
			'path' => '/',
1016
			'domain' => '',
1017
			'secure' => false,
1018
			'httpOnly' => false);
1019
		$result = $response->cookie('CakeTestCookie[Testing]');
1020
		$this->assertEquals($expected, $result);
1021
 
1022
		$cookie = array(
1023
			'name' => 'CakeTestCookie[Testing2]',
1024
			'value' => '[a,b,c]',
1025
			'expire' => 1000,
1026
			'path' => '/test',
1027
			'secure' => true
1028
		);
1029
		$response->cookie($cookie);
1030
		$expected = array(
1031
			'CakeTestCookie[Testing]' => array(
1032
				'name' => 'CakeTestCookie[Testing]',
1033
				'value' => '',
1034
				'expire' => 0,
1035
				'path' => '/',
1036
				'domain' => '',
1037
				'secure' => false,
1038
				'httpOnly' => false
1039
			),
1040
			'CakeTestCookie[Testing2]' => array(
1041
				'name' => 'CakeTestCookie[Testing2]',
1042
				'value' => '[a,b,c]',
1043
				'expire' => 1000,
1044
				'path' => '/test',
1045
				'domain' => '',
1046
				'secure' => true,
1047
				'httpOnly' => false
1048
			)
1049
		);
1050
 
1051
		$result = $response->cookie();
1052
		$this->assertEquals($expected, $result);
1053
 
1054
		$cookie = $expected['CakeTestCookie[Testing]'];
1055
		$cookie['value'] = 'test';
1056
		$response->cookie($cookie);
1057
		$expected = array(
1058
			'CakeTestCookie[Testing]' => array(
1059
				'name' => 'CakeTestCookie[Testing]',
1060
				'value' => 'test',
1061
				'expire' => 0,
1062
				'path' => '/',
1063
				'domain' => '',
1064
				'secure' => false,
1065
				'httpOnly' => false
1066
			),
1067
			'CakeTestCookie[Testing2]' => array(
1068
				'name' => 'CakeTestCookie[Testing2]',
1069
				'value' => '[a,b,c]',
1070
				'expire' => 1000,
1071
				'path' => '/test',
1072
				'domain' => '',
1073
				'secure' => true,
1074
				'httpOnly' => false
1075
			)
1076
		);
1077
 
1078
		$result = $response->cookie();
1079
		$this->assertEquals($expected, $result);
1080
	}
1081
 
1082
/**
1083
 * Test CORS
1084
 *
1085
 * @dataProvider corsData
1086
 * @param CakeRequest $request
1087
 * @param string $origin
1088
 * @param string|array $domains
1089
 * @param string|array $methods
1090
 * @param string|array $headers
1091
 * @param string|bool $expectedOrigin
1092
 * @param string|bool $expectedMethods
1093
 * @param string|bool $expectedHeaders
1094
 * @return void
1095
 */
1096
	public function testCors($request, $origin, $domains, $methods, $headers, $expectedOrigin, $expectedMethods = false, $expectedHeaders = false) {
1097
		$_SERVER['HTTP_ORIGIN'] = $origin;
1098
 
1099
		$response = $this->getMock('CakeResponse', array('header'));
1100
 
1101
		$method = $response->expects(!$expectedOrigin ? $this->never() : $this->at(0))->method('header');
1102
		$expectedOrigin && $method->with('Access-Control-Allow-Origin', $expectedOrigin ? $expectedOrigin : $this->anything());
1103
 
1104
		$i = 1;
1105
		if ($expectedMethods) {
1106
			$response->expects($this->at($i++))
1107
				->method('header')
1108
				->with('Access-Control-Allow-Methods', $expectedMethods ? $expectedMethods : $this->anything());
1109
		}
1110
		if ($expectedHeaders) {
1111
			$response->expects($this->at($i++))
1112
				->method('header')
1113
				->with('Access-Control-Allow-Headers', $expectedHeaders ? $expectedHeaders : $this->anything());
1114
		}
1115
 
1116
		$response->cors($request, $domains, $methods, $headers);
1117
		unset($_SERVER['HTTP_ORIGIN']);
1118
	}
1119
 
1120
/**
1121
 * Feed for testCors
1122
 *
1123
 * @return array
1124
 */
1125
	public function corsData() {
1126
		$fooRequest = new CakeRequest();
1127
 
1128
		$secureRequest = $this->getMock('CakeRequest', array('is'));
1129
		$secureRequest->expects($this->any())
1130
			->method('is')
1131
			->with('ssl')
1132
			->will($this->returnValue(true));
1133
 
1134
		return array(
1135
			array($fooRequest, null, '*', '', '', false, false),
1136
			array($fooRequest, 'http://www.foo.com', '*', '', '', '*', false),
1137
			array($fooRequest, 'http://www.foo.com', 'www.foo.com', '', '', 'http://www.foo.com', false),
1138
			array($fooRequest, 'http://www.foo.com', '*.foo.com', '', '', 'http://www.foo.com', false),
1139
			array($fooRequest, 'http://www.foo.com', 'http://*.foo.com', '', '', 'http://www.foo.com', false),
1140
			array($fooRequest, 'http://www.foo.com', 'https://www.foo.com', '', '', false, false),
1141
			array($fooRequest, 'http://www.foo.com', 'https://*.foo.com', '', '', false, false),
1142
			array($fooRequest, 'http://www.foo.com', array('*.bar.com', '*.foo.com'), '', '', 'http://www.foo.com', false),
1143
 
1144
			array($secureRequest, 'https://www.bar.com', 'www.bar.com', '', '', 'https://www.bar.com', false),
1145
			array($secureRequest, 'https://www.bar.com', 'http://www.bar.com', '', '', false, false),
1146
			array($secureRequest, 'https://www.bar.com', '*.bar.com', '', '', 'https://www.bar.com', false),
1147
 
1148
			array($fooRequest, 'http://www.foo.com', '*', 'GET', '', '*', 'GET'),
1149
			array($fooRequest, 'http://www.foo.com', '*.foo.com', 'GET', '', 'http://www.foo.com', 'GET'),
1150
			array($fooRequest, 'http://www.foo.com', '*.foo.com', array('GET', 'POST'), '', 'http://www.foo.com', 'GET, POST'),
1151
 
1152
			array($fooRequest, 'http://www.foo.com', '*', '', 'X-CakePHP', '*', false, 'X-CakePHP'),
1153
			array($fooRequest, 'http://www.foo.com', '*', '', array('X-CakePHP', 'X-MyApp'), '*', false, 'X-CakePHP, X-MyApp'),
1154
			array($fooRequest, 'http://www.foo.com', '*', array('GET', 'OPTIONS'), array('X-CakePHP', 'X-MyApp'), '*', 'GET, OPTIONS', 'X-CakePHP, X-MyApp'),
1155
		);
1156
	}
1157
 
1158
/**
1159
 * testFileNotFound
1160
 *
1161
 * @expectedException NotFoundException
1162
 * @return void
1163
 */
1164
	public function testFileNotFound() {
1165
		$response = new CakeResponse();
1166
		$response->file('/some/missing/folder/file.jpg');
1167
	}
1168
 
1169
/**
1170
 * test file with ../
1171
 *
1172
 * @expectedException NotFoundException
1173
 * @expectedExceptionMessage The requested file contains `..` and will not be read.
1174
 * @return void
1175
 */
1176
	public function testFileWithForwardSlashPathTraversal() {
1177
		$response = new CakeResponse();
1178
		$response->file('my/../cat.gif');
1179
	}
1180
 
1181
/**
1182
 * test file with ..\
1183
 *
1184
 * @expectedException NotFoundException
1185
 * @expectedExceptionMessage The requested file contains `..` and will not be read.
1186
 * @return void
1187
 */
1188
	public function testFileWithBackwardSlashPathTraversal() {
1189
		$response = new CakeResponse();
1190
		$response->file('my\..\cat.gif');
1191
	}
1192
 
1193
/**
1194
 * Although unlikely, a file may contain dots in its filename.
1195
 * This should be allowed, as long as the dots doesn't specify a path (../ or ..\)
1196
 *
1197
 * @expectedException NotFoundException
1198
 * @execptedExceptionMessageRegExp #The requested file .+my/Some..cat.gif was not found or not readable#
1199
 * @return void
1200
 */
1201
	public function testFileWithDotsInFilename() {
1202
		$response = new CakeResponse();
1203
		$response->file('my/Some..cat.gif');
1204
	}
1205
 
1206
/**
1207
 * testFile method
1208
 *
1209
 * @return void
1210
 */
1211
	public function testFile() {
1212
		$response = $this->getMock('CakeResponse', array(
1213
			'header',
1214
			'type',
1215
			'_sendHeader',
1216
			'_setContentType',
1217
			'_isActive',
1218
			'_clearBuffer',
1219
			'_flushBuffer'
1220
		));
1221
 
1222
		$response->expects($this->exactly(1))
1223
			->method('type')
1224
			->with('css')
1225
			->will($this->returnArgument(0));
1226
 
1227
		$response->expects($this->at(1))
1228
			->method('header')
1229
			->with('Accept-Ranges', 'bytes');
1230
 
1231
		$response->expects($this->at(2))
1232
			->method('header')
1233
			->with('Content-Length', 38);
1234
 
1235
		$response->expects($this->once())->method('_clearBuffer');
1236
		$response->expects($this->once())->method('_flushBuffer');
1237
 
1238
		$response->expects($this->exactly(1))
1239
			->method('_isActive')
1240
			->will($this->returnValue(true));
1241
 
1242
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css');
1243
 
1244
		ob_start();
1245
		$result = $response->send();
1246
		$output = ob_get_clean();
1247
		$this->assertEquals("/* this is the test asset css file */\n", $output);
1248
		$this->assertNotSame(false, $result);
1249
	}
1250
 
1251
/**
1252
 * testFileWithUnknownFileTypeGeneric method
1253
 *
1254
 * @return void
1255
 */
1256
	public function testFileWithUnknownFileTypeGeneric() {
1257
		$currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
1258
		$_SERVER['HTTP_USER_AGENT'] = 'Some generic browser';
1259
 
1260
		$response = $this->getMock('CakeResponse', array(
1261
			'header',
1262
			'type',
1263
			'download',
1264
			'_sendHeader',
1265
			'_setContentType',
1266
			'_isActive',
1267
			'_clearBuffer',
1268
			'_flushBuffer'
1269
		));
1270
 
1271
		$response->expects($this->exactly(1))
1272
			->method('type')
1273
			->with('ini')
1274
			->will($this->returnValue(false));
1275
 
1276
		$response->expects($this->once())
1277
			->method('download')
1278
			->with('no_section.ini');
1279
 
1280
		$response->expects($this->at(2))
1281
			->method('header')
1282
			->with('Content-Transfer-Encoding', 'binary');
1283
 
1284
		$response->expects($this->at(3))
1285
			->method('header')
1286
			->with('Accept-Ranges', 'bytes');
1287
 
1288
		$response->expects($this->at(4))
1289
			->method('header')
1290
			->with('Content-Length', 35);
1291
 
1292
		$response->expects($this->once())->method('_clearBuffer');
1293
		$response->expects($this->once())->method('_flushBuffer');
1294
 
1295
		$response->expects($this->exactly(1))
1296
			->method('_isActive')
1297
			->will($this->returnValue(true));
1298
 
1299
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini');
1300
 
1301
		ob_start();
1302
		$result = $response->send();
1303
		$output = ob_get_clean();
1304
		$this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
1305
		$this->assertNotSame(false, $result);
1306
		if ($currentUserAgent !== null) {
1307
			$_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
1308
		}
1309
	}
1310
 
1311
/**
1312
 * testFileWithUnknownFileTypeOpera method
1313
 *
1314
 * @return void
1315
 */
1316
	public function testFileWithUnknownFileTypeOpera() {
1317
		$currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
1318
		$_SERVER['HTTP_USER_AGENT'] = 'Opera/9.80 (Windows NT 6.0; U; en) Presto/2.8.99 Version/11.10';
1319
 
1320
		$response = $this->getMock('CakeResponse', array(
1321
			'header',
1322
			'type',
1323
			'download',
1324
			'_sendHeader',
1325
			'_setContentType',
1326
			'_isActive',
1327
			'_clearBuffer',
1328
			'_flushBuffer'
1329
		));
1330
 
1331
		$response->expects($this->at(0))
1332
			->method('type')
1333
			->with('ini')
1334
			->will($this->returnValue(false));
1335
 
1336
		$response->expects($this->at(1))
1337
			->method('type')
1338
			->with('application/octet-stream')
1339
			->will($this->returnValue(false));
1340
 
1341
		$response->expects($this->once())
1342
			->method('download')
1343
			->with('no_section.ini');
1344
 
1345
		$response->expects($this->at(3))
1346
			->method('header')
1347
			->with('Content-Transfer-Encoding', 'binary');
1348
 
1349
		$response->expects($this->at(4))
1350
			->method('header')
1351
			->with('Accept-Ranges', 'bytes');
1352
 
1353
		$response->expects($this->at(5))
1354
			->method('header')
1355
			->with('Content-Length', 35);
1356
 
1357
		$response->expects($this->once())->method('_clearBuffer');
1358
		$response->expects($this->once())->method('_flushBuffer');
1359
		$response->expects($this->exactly(1))
1360
			->method('_isActive')
1361
			->will($this->returnValue(true));
1362
 
1363
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini');
1364
 
1365
		ob_start();
1366
		$result = $response->send();
1367
		$output = ob_get_clean();
1368
		$this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
1369
		$this->assertNotSame(false, $result);
1370
		if ($currentUserAgent !== null) {
1371
			$_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
1372
		}
1373
	}
1374
 
1375
/**
1376
 * testFileWithUnknownFileTypeIE method
1377
 *
1378
 * @return void
1379
 */
1380
	public function testFileWithUnknownFileTypeIE() {
1381
		$currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
1382
		$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)';
1383
 
1384
		$response = $this->getMock('CakeResponse', array(
1385
			'header',
1386
			'type',
1387
			'download',
1388
			'_sendHeader',
1389
			'_setContentType',
1390
			'_isActive',
1391
			'_clearBuffer',
1392
			'_flushBuffer'
1393
		));
1394
 
1395
		$response->expects($this->at(0))
1396
			->method('type')
1397
			->with('ini')
1398
			->will($this->returnValue(false));
1399
 
1400
		$response->expects($this->at(1))
1401
			->method('type')
1402
			->with('application/force-download')
1403
			->will($this->returnValue(false));
1404
 
1405
		$response->expects($this->once())
1406
			->method('download')
1407
			->with('config.ini');
1408
 
1409
		$response->expects($this->at(3))
1410
			->method('header')
1411
			->with('Content-Transfer-Encoding', 'binary');
1412
 
1413
		$response->expects($this->at(4))
1414
			->method('header')
1415
			->with('Accept-Ranges', 'bytes');
1416
 
1417
		$response->expects($this->at(5))
1418
			->method('header')
1419
			->with('Content-Length', 35);
1420
 
1421
		$response->expects($this->once())->method('_clearBuffer');
1422
		$response->expects($this->once())->method('_flushBuffer');
1423
		$response->expects($this->exactly(1))
1424
			->method('_isActive')
1425
			->will($this->returnValue(true));
1426
 
1427
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini', array(
1428
			'name' => 'config.ini'
1429
		));
1430
 
1431
		ob_start();
1432
		$result = $response->send();
1433
		$output = ob_get_clean();
1434
		$this->assertEquals("some_key = some_value\nbool_key = 1\n", $output);
1435
		$this->assertNotSame(false, $result);
1436
		if ($currentUserAgent !== null) {
1437
			$_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
1438
		}
1439
	}
1440
/**
1441
 * testFileWithUnknownFileNoDownload method
1442
 *
1443
 * @return void
1444
 */
1445
	public function testFileWithUnknownFileNoDownload() {
1446
		$currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
1447
		$_SERVER['HTTP_USER_AGENT'] = 'Some generic browser';
1448
 
1449
		$response = $this->getMock('CakeResponse', array(
1450
			'header',
1451
			'type',
1452
			'download',
1453
			'_sendHeader',
1454
			'_setContentType',
1455
			'_isActive',
1456
			'_clearBuffer',
1457
			'_flushBuffer'
1458
		));
1459
 
1460
		$response->expects($this->exactly(1))
1461
			->method('type')
1462
			->with('ini')
1463
			->will($this->returnValue(false));
1464
 
1465
		$response->expects($this->at(1))
1466
			->method('header')
1467
			->with('Accept-Ranges', 'bytes');
1468
 
1469
		$response->expects($this->never())
1470
			->method('download');
1471
 
1472
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini', array(
1473
			'download' => false
1474
		));
1475
 
1476
		if ($currentUserAgent !== null) {
1477
			$_SERVER['HTTP_USER_AGENT'] = $currentUserAgent;
1478
		}
1479
	}
1480
 
1481
/**
1482
 * testConnectionAbortedOnBuffering method
1483
 *
1484
 * @return void
1485
 */
1486
	public function testConnectionAbortedOnBuffering() {
1487
		$response = $this->getMock('CakeResponse', array(
1488
			'header',
1489
			'type',
1490
			'download',
1491
			'_sendHeader',
1492
			'_setContentType',
1493
			'_isActive',
1494
			'_clearBuffer',
1495
			'_flushBuffer'
1496
		));
1497
 
1498
		$response->expects($this->any())
1499
			->method('type')
1500
			->with('css')
1501
			->will($this->returnArgument(0));
1502
 
1503
		$response->expects($this->at(0))
1504
			->method('_isActive')
1505
			->will($this->returnValue(false));
1506
 
1507
		$response->expects($this->once())->method('_clearBuffer');
1508
		$response->expects($this->never())->method('_flushBuffer');
1509
 
1510
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css');
1511
 
1512
		$result = $response->send();
1513
		$this->assertNull($result);
1514
	}
1515
 
1516
/**
1517
 * Test downloading files with UPPERCASE extensions.
1518
 *
1519
 * @return void
1520
 */
1521
	public function testFileUpperExtension() {
1522
		$response = $this->getMock('CakeResponse', array(
1523
			'header',
1524
			'type',
1525
			'download',
1526
			'_sendHeader',
1527
			'_setContentType',
1528
			'_isActive',
1529
			'_clearBuffer',
1530
			'_flushBuffer'
1531
		));
1532
 
1533
		$response->expects($this->any())
1534
			->method('type')
1535
			->with('jpg')
1536
			->will($this->returnArgument(0));
1537
 
1538
		$response->expects($this->at(0))
1539
			->method('_isActive')
1540
			->will($this->returnValue(true));
1541
 
1542
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS . 'test_2.JPG');
1543
	}
1544
 
1545
/**
1546
 * Test downloading files with extension not explicitly set.
1547
 *
1548
 * @return void
1549
 */
1550
	public function testFileExtensionNotSet() {
1551
		$response = $this->getMock('CakeResponse', array(
1552
			'header',
1553
			'type',
1554
			'download',
1555
			'_sendHeader',
1556
			'_setContentType',
1557
			'_isActive',
1558
			'_clearBuffer',
1559
			'_flushBuffer'
1560
		));
1561
 
1562
		$response->expects($this->any())
1563
			->method('type')
1564
			->with('jpg')
1565
			->will($this->returnArgument(0));
1566
 
1567
		$response->expects($this->at(0))
1568
			->method('_isActive')
1569
			->will($this->returnValue(true));
1570
 
1571
		$response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS . 'test_2.JPG');
1572
	}
1573
 
1574
/**
1575
 * A data provider for testing various ranges
1576
 *
1577
 * @return array
1578
 */
1579
	public static function rangeProvider() {
1580
		return array(
1581
			// suffix-byte-range
1582
			array(
1583
				'bytes=-25', 25, 'bytes 13-37/38'
1584
			),
1585
 
1586
			array(
1587
				'bytes=0-', 38, 'bytes 0-37/38'
1588
			),
1589
			array(
1590
				'bytes=10-', 28, 'bytes 10-37/38'
1591
			),
1592
			array(
1593
				'bytes=10-20', 11, 'bytes 10-20/38'
1594
			),
1595
		);
1596
	}
1597
 
1598
/**
1599
 * Test the various range offset types.
1600
 *
1601
 * @dataProvider rangeProvider
1602
 * @return void
1603
 */
1604
	public function testFileRangeOffsets($range, $length, $offsetResponse) {
1605
		$_SERVER['HTTP_RANGE'] = $range;
1606
		$response = $this->getMock('CakeResponse', array(
1607
			'header',
1608
			'type',
1609
			'_sendHeader',
1610
			'_isActive',
1611
			'_clearBuffer',
1612
			'_flushBuffer'
1613
		));
1614
 
1615
		$response->expects($this->at(1))
1616
			->method('header')
1617
			->with('Content-Disposition', 'attachment; filename="test_asset.css"');
1618
 
1619
		$response->expects($this->at(2))
1620
			->method('header')
1621
			->with('Content-Transfer-Encoding', 'binary');
1622
 
1623
		$response->expects($this->at(3))
1624
			->method('header')
1625
			->with('Accept-Ranges', 'bytes');
1626
 
1627
		$response->expects($this->at(4))
1628
			->method('header')
1629
			->with(array(
1630
				'Content-Length' => $length,
1631
				'Content-Range' => $offsetResponse,
1632
			));
1633
 
1634
		$response->expects($this->any())
1635
			->method('_isActive')
1636
			->will($this->returnValue(true));
1637
 
1638
		$response->file(
1639
			CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
1640
			array('download' => true)
1641
		);
1642
 
1643
		ob_start();
1644
		$result = $response->send();
1645
		ob_get_clean();
1646
	}
1647
 
1648
/**
1649
 * Test fetching ranges from a file.
1650
 *
1651
 * @return void
1652
 */
1653
	public function testFileRange() {
1654
		$_SERVER['HTTP_RANGE'] = 'bytes=8-25';
1655
		$response = $this->getMock('CakeResponse', array(
1656
			'header',
1657
			'type',
1658
			'_sendHeader',
1659
			'_setContentType',
1660
			'_isActive',
1661
			'_clearBuffer',
1662
			'_flushBuffer'
1663
		));
1664
 
1665
		$response->expects($this->exactly(1))
1666
			->method('type')
1667
			->with('css')
1668
			->will($this->returnArgument(0));
1669
 
1670
		$response->expects($this->at(1))
1671
			->method('header')
1672
			->with('Content-Disposition', 'attachment; filename="test_asset.css"');
1673
 
1674
		$response->expects($this->at(2))
1675
			->method('header')
1676
			->with('Content-Transfer-Encoding', 'binary');
1677
 
1678
		$response->expects($this->at(3))
1679
			->method('header')
1680
			->with('Accept-Ranges', 'bytes');
1681
 
1682
		$response->expects($this->at(4))
1683
			->method('header')
1684
			->with(array(
1685
				'Content-Length' => 18,
1686
				'Content-Range' => 'bytes 8-25/38',
1687
			));
1688
 
1689
		$response->expects($this->once())->method('_clearBuffer');
1690
 
1691
		$response->expects($this->any())
1692
			->method('_isActive')
1693
			->will($this->returnValue(true));
1694
 
1695
		$response->file(
1696
			CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
1697
			array('download' => true)
1698
		);
1699
 
1700
		ob_start();
1701
		$result = $response->send();
1702
		$output = ob_get_clean();
1703
		$this->assertEquals(206, $response->statusCode());
1704
		$this->assertEquals("is the test asset ", $output);
1705
		$this->assertNotSame(false, $result);
1706
	}
1707
 
1708
/**
1709
 * Test invalid file ranges.
1710
 *
1711
 * @return void
1712
 */
1713
	public function testFileRangeInvalid() {
1714
		$_SERVER['HTTP_RANGE'] = 'bytes=30-2';
1715
		$response = $this->getMock('CakeResponse', array(
1716
			'header',
1717
			'type',
1718
			'_sendHeader',
1719
			'_setContentType',
1720
			'_isActive',
1721
			'_clearBuffer',
1722
			'_flushBuffer'
1723
		));
1724
 
1725
		$response->expects($this->at(1))
1726
			->method('header')
1727
			->with('Content-Disposition', 'attachment; filename="test_asset.css"');
1728
 
1729
		$response->expects($this->at(2))
1730
			->method('header')
1731
			->with('Content-Transfer-Encoding', 'binary');
1732
 
1733
		$response->expects($this->at(3))
1734
			->method('header')
1735
			->with('Accept-Ranges', 'bytes');
1736
 
1737
		$response->expects($this->at(4))
1738
			->method('header')
1739
			->with(array(
1740
				'Content-Range' => 'bytes 0-37/38',
1741
			));
1742
 
1743
		$response->file(
1744
			CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
1745
			array('download' => true)
1746
		);
1747
 
1748
		$this->assertEquals(416, $response->statusCode());
1749
		$result = $response->send();
1750
	}
1751
 
1752
/**
1753
 * testFileRangeOffsetsNoDownload method
1754
 *
1755
 * @dataProvider rangeProvider
1756
 * @return void
1757
 */
1758
	public function testFileRangeOffsetsNoDownload($range, $length, $offsetResponse) {
1759
		$_SERVER['HTTP_RANGE'] = $range;
1760
		$response = $this->getMock('CakeResponse', array(
1761
			'header',
1762
			'type',
1763
			'_sendHeader',
1764
			'_isActive',
1765
			'_clearBuffer',
1766
			'_flushBuffer'
1767
		));
1768
 
1769
		$response->expects($this->at(1))
1770
			->method('header')
1771
			->with('Accept-Ranges', 'bytes');
1772
 
1773
		$response->expects($this->at(2))
1774
			->method('header')
1775
			->with(array(
1776
				'Content-Length' => $length,
1777
				'Content-Range' => $offsetResponse,
1778
			));
1779
 
1780
		$response->expects($this->any())
1781
			->method('_isActive')
1782
			->will($this->returnValue(true));
1783
 
1784
		$response->file(
1785
			CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
1786
			array('download' => false)
1787
		);
1788
 
1789
		ob_start();
1790
		$result = $response->send();
1791
		ob_get_clean();
1792
	}
1793
 
1794
/**
1795
 * testFileRangeNoDownload method
1796
 *
1797
 * @return void
1798
 */
1799
	public function testFileRangeNoDownload() {
1800
		$_SERVER['HTTP_RANGE'] = 'bytes=8-25';
1801
		$response = $this->getMock('CakeResponse', array(
1802
			'header',
1803
			'type',
1804
			'_sendHeader',
1805
			'_setContentType',
1806
			'_isActive',
1807
			'_clearBuffer',
1808
			'_flushBuffer'
1809
		));
1810
 
1811
		$response->expects($this->exactly(1))
1812
			->method('type')
1813
			->with('css')
1814
			->will($this->returnArgument(0));
1815
 
1816
		$response->expects($this->at(1))
1817
			->method('header')
1818
			->with('Accept-Ranges', 'bytes');
1819
 
1820
		$response->expects($this->at(2))
1821
			->method('header')
1822
			->with(array(
1823
				'Content-Length' => 18,
1824
				'Content-Range' => 'bytes 8-25/38',
1825
			));
1826
 
1827
		$response->expects($this->once())->method('_clearBuffer');
1828
 
1829
		$response->expects($this->any())
1830
			->method('_isActive')
1831
			->will($this->returnValue(true));
1832
 
1833
		$response->file(
1834
			CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
1835
			array('download' => false)
1836
		);
1837
 
1838
		ob_start();
1839
		$result = $response->send();
1840
		$output = ob_get_clean();
1841
		$this->assertEquals(206, $response->statusCode());
1842
		$this->assertEquals("is the test asset ", $output);
1843
		$this->assertNotSame(false, $result);
1844
	}
1845
 
1846
/**
1847
 * testFileRangeInvalidNoDownload method
1848
 *
1849
 * @return void
1850
 */
1851
	public function testFileRangeInvalidNoDownload() {
1852
		$_SERVER['HTTP_RANGE'] = 'bytes=30-2';
1853
		$response = $this->getMock('CakeResponse', array(
1854
			'header',
1855
			'type',
1856
			'_sendHeader',
1857
			'_setContentType',
1858
			'_isActive',
1859
			'_clearBuffer',
1860
			'_flushBuffer'
1861
		));
1862
 
1863
		$response->expects($this->at(1))
1864
			->method('header')
1865
			->with('Accept-Ranges', 'bytes');
1866
 
1867
		$response->expects($this->at(2))
1868
			->method('header')
1869
			->with(array(
1870
				'Content-Range' => 'bytes 0-37/38',
1871
			));
1872
 
1873
		$response->file(
1874
			CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css',
1875
			array('download' => false)
1876
		);
1877
 
1878
		$this->assertEquals(416, $response->statusCode());
1879
		$result = $response->send();
1880
	}
1881
 
1882
/**
1883
 * Test the location method.
1884
 *
1885
 * @return void
1886
 */
1887
	public function testLocation() {
1888
		$response = new CakeResponse();
1889
		$this->assertNull($response->location(), 'No header should be set.');
1890
		$this->assertNull($response->location('http://example.org'), 'Setting a location should return null');
1891
		$this->assertEquals('http://example.org', $response->location(), 'Reading a location should return the value.');
1892
	}
1893
 
1894
}