Yaffs site version 1.1
[yaffs-website] / vendor / symfony / http-foundation / Tests / ResponseTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpFoundation\Tests;
13
14 use Symfony\Component\HttpFoundation\Request;
15 use Symfony\Component\HttpFoundation\Response;
16
17 /**
18  * @group time-sensitive
19  */
20 class ResponseTest extends ResponseTestCase
21 {
22     public function testCreate()
23     {
24         $response = Response::create('foo', 301, array('Foo' => 'bar'));
25
26         $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response);
27         $this->assertEquals(301, $response->getStatusCode());
28         $this->assertEquals('bar', $response->headers->get('foo'));
29     }
30
31     public function testToString()
32     {
33         $response = new Response();
34         $response = explode("\r\n", $response);
35         $this->assertEquals('HTTP/1.0 200 OK', $response[0]);
36         $this->assertEquals('Cache-Control: no-cache', $response[1]);
37     }
38
39     public function testClone()
40     {
41         $response = new Response();
42         $responseClone = clone $response;
43         $this->assertEquals($response, $responseClone);
44     }
45
46     public function testSendHeaders()
47     {
48         $response = new Response();
49         $headers = $response->sendHeaders();
50         $this->assertObjectHasAttribute('headers', $headers);
51         $this->assertObjectHasAttribute('content', $headers);
52         $this->assertObjectHasAttribute('version', $headers);
53         $this->assertObjectHasAttribute('statusCode', $headers);
54         $this->assertObjectHasAttribute('statusText', $headers);
55         $this->assertObjectHasAttribute('charset', $headers);
56     }
57
58     public function testSend()
59     {
60         $response = new Response();
61         $responseSend = $response->send();
62         $this->assertObjectHasAttribute('headers', $responseSend);
63         $this->assertObjectHasAttribute('content', $responseSend);
64         $this->assertObjectHasAttribute('version', $responseSend);
65         $this->assertObjectHasAttribute('statusCode', $responseSend);
66         $this->assertObjectHasAttribute('statusText', $responseSend);
67         $this->assertObjectHasAttribute('charset', $responseSend);
68     }
69
70     public function testGetCharset()
71     {
72         $response = new Response();
73         $charsetOrigin = 'UTF-8';
74         $response->setCharset($charsetOrigin);
75         $charset = $response->getCharset();
76         $this->assertEquals($charsetOrigin, $charset);
77     }
78
79     public function testIsCacheable()
80     {
81         $response = new Response();
82         $this->assertFalse($response->isCacheable());
83     }
84
85     public function testIsCacheableWithErrorCode()
86     {
87         $response = new Response('', 500);
88         $this->assertFalse($response->isCacheable());
89     }
90
91     public function testIsCacheableWithNoStoreDirective()
92     {
93         $response = new Response();
94         $response->headers->set('cache-control', 'private');
95         $this->assertFalse($response->isCacheable());
96     }
97
98     public function testIsCacheableWithSetTtl()
99     {
100         $response = new Response();
101         $response->setTtl(10);
102         $this->assertTrue($response->isCacheable());
103     }
104
105     public function testMustRevalidate()
106     {
107         $response = new Response();
108         $this->assertFalse($response->mustRevalidate());
109     }
110
111     public function testMustRevalidateWithMustRevalidateCacheControlHeader()
112     {
113         $response = new Response();
114         $response->headers->set('cache-control', 'must-revalidate');
115
116         $this->assertTrue($response->mustRevalidate());
117     }
118
119     public function testMustRevalidateWithProxyRevalidateCacheControlHeader()
120     {
121         $response = new Response();
122         $response->headers->set('cache-control', 'proxy-revalidate');
123
124         $this->assertTrue($response->mustRevalidate());
125     }
126
127     public function testSetNotModified()
128     {
129         $response = new Response();
130         $modified = $response->setNotModified();
131         $this->assertObjectHasAttribute('headers', $modified);
132         $this->assertObjectHasAttribute('content', $modified);
133         $this->assertObjectHasAttribute('version', $modified);
134         $this->assertObjectHasAttribute('statusCode', $modified);
135         $this->assertObjectHasAttribute('statusText', $modified);
136         $this->assertObjectHasAttribute('charset', $modified);
137         $this->assertEquals(304, $modified->getStatusCode());
138     }
139
140     public function testIsSuccessful()
141     {
142         $response = new Response();
143         $this->assertTrue($response->isSuccessful());
144     }
145
146     public function testIsNotModified()
147     {
148         $response = new Response();
149         $modified = $response->isNotModified(new Request());
150         $this->assertFalse($modified);
151     }
152
153     public function testIsNotModifiedNotSafe()
154     {
155         $request = Request::create('/homepage', 'POST');
156
157         $response = new Response();
158         $this->assertFalse($response->isNotModified($request));
159     }
160
161     public function testIsNotModifiedLastModified()
162     {
163         $before = 'Sun, 25 Aug 2013 18:32:31 GMT';
164         $modified = 'Sun, 25 Aug 2013 18:33:31 GMT';
165         $after = 'Sun, 25 Aug 2013 19:33:31 GMT';
166
167         $request = new Request();
168         $request->headers->set('If-Modified-Since', $modified);
169
170         $response = new Response();
171
172         $response->headers->set('Last-Modified', $modified);
173         $this->assertTrue($response->isNotModified($request));
174
175         $response->headers->set('Last-Modified', $before);
176         $this->assertTrue($response->isNotModified($request));
177
178         $response->headers->set('Last-Modified', $after);
179         $this->assertFalse($response->isNotModified($request));
180
181         $response->headers->set('Last-Modified', '');
182         $this->assertFalse($response->isNotModified($request));
183     }
184
185     public function testIsNotModifiedEtag()
186     {
187         $etagOne = 'randomly_generated_etag';
188         $etagTwo = 'randomly_generated_etag_2';
189
190         $request = new Request();
191         $request->headers->set('if_none_match', sprintf('%s, %s, %s', $etagOne, $etagTwo, 'etagThree'));
192
193         $response = new Response();
194
195         $response->headers->set('ETag', $etagOne);
196         $this->assertTrue($response->isNotModified($request));
197
198         $response->headers->set('ETag', $etagTwo);
199         $this->assertTrue($response->isNotModified($request));
200
201         $response->headers->set('ETag', '');
202         $this->assertFalse($response->isNotModified($request));
203     }
204
205     public function testIsNotModifiedLastModifiedAndEtag()
206     {
207         $before = 'Sun, 25 Aug 2013 18:32:31 GMT';
208         $modified = 'Sun, 25 Aug 2013 18:33:31 GMT';
209         $after = 'Sun, 25 Aug 2013 19:33:31 GMT';
210         $etag = 'randomly_generated_etag';
211
212         $request = new Request();
213         $request->headers->set('if_none_match', sprintf('%s, %s', $etag, 'etagThree'));
214         $request->headers->set('If-Modified-Since', $modified);
215
216         $response = new Response();
217
218         $response->headers->set('ETag', $etag);
219         $response->headers->set('Last-Modified', $after);
220         $this->assertFalse($response->isNotModified($request));
221
222         $response->headers->set('ETag', 'non-existent-etag');
223         $response->headers->set('Last-Modified', $before);
224         $this->assertFalse($response->isNotModified($request));
225
226         $response->headers->set('ETag', $etag);
227         $response->headers->set('Last-Modified', $modified);
228         $this->assertTrue($response->isNotModified($request));
229     }
230
231     public function testIsNotModifiedIfModifiedSinceAndEtagWithoutLastModified()
232     {
233         $modified = 'Sun, 25 Aug 2013 18:33:31 GMT';
234         $etag = 'randomly_generated_etag';
235
236         $request = new Request();
237         $request->headers->set('if_none_match', sprintf('%s, %s', $etag, 'etagThree'));
238         $request->headers->set('If-Modified-Since', $modified);
239
240         $response = new Response();
241
242         $response->headers->set('ETag', $etag);
243         $this->assertTrue($response->isNotModified($request));
244
245         $response->headers->set('ETag', 'non-existent-etag');
246         $this->assertFalse($response->isNotModified($request));
247     }
248
249     public function testIsValidateable()
250     {
251         $response = new Response('', 200, array('Last-Modified' => $this->createDateTimeOneHourAgo()->format(DATE_RFC2822)));
252         $this->assertTrue($response->isValidateable(), '->isValidateable() returns true if Last-Modified is present');
253
254         $response = new Response('', 200, array('ETag' => '"12345"'));
255         $this->assertTrue($response->isValidateable(), '->isValidateable() returns true if ETag is present');
256
257         $response = new Response();
258         $this->assertFalse($response->isValidateable(), '->isValidateable() returns false when no validator is present');
259     }
260
261     public function testGetDate()
262     {
263         $oneHourAgo = $this->createDateTimeOneHourAgo();
264         $response = new Response('', 200, array('Date' => $oneHourAgo->format(DATE_RFC2822)));
265         $date = $response->getDate();
266         $this->assertEquals($oneHourAgo->getTimestamp(), $date->getTimestamp(), '->getDate() returns the Date header if present');
267
268         $response = new Response();
269         $date = $response->getDate();
270         $this->assertEquals(time(), $date->getTimestamp(), '->getDate() returns the current Date if no Date header present');
271
272         $response = new Response('', 200, array('Date' => $this->createDateTimeOneHourAgo()->format(DATE_RFC2822)));
273         $now = $this->createDateTimeNow();
274         $response->headers->set('Date', $now->format(DATE_RFC2822));
275         $date = $response->getDate();
276         $this->assertEquals($now->getTimestamp(), $date->getTimestamp(), '->getDate() returns the date when the header has been modified');
277
278         $response = new Response('', 200);
279         $now = $this->createDateTimeNow();
280         $response->headers->remove('Date');
281         $date = $response->getDate();
282         $this->assertEquals($now->getTimestamp(), $date->getTimestamp(), '->getDate() returns the current Date when the header has previously been removed');
283     }
284
285     public function testGetMaxAge()
286     {
287         $response = new Response();
288         $response->headers->set('Cache-Control', 's-maxage=600, max-age=0');
289         $this->assertEquals(600, $response->getMaxAge(), '->getMaxAge() uses s-maxage cache control directive when present');
290
291         $response = new Response();
292         $response->headers->set('Cache-Control', 'max-age=600');
293         $this->assertEquals(600, $response->getMaxAge(), '->getMaxAge() falls back to max-age when no s-maxage directive present');
294
295         $response = new Response();
296         $response->headers->set('Cache-Control', 'must-revalidate');
297         $response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(DATE_RFC2822));
298         $this->assertEquals(3600, $response->getMaxAge(), '->getMaxAge() falls back to Expires when no max-age or s-maxage directive present');
299
300         $response = new Response();
301         $response->headers->set('Cache-Control', 'must-revalidate');
302         $response->headers->set('Expires', -1);
303         $this->assertEquals('Sat, 01 Jan 00 00:00:00 +0000', $response->getExpires()->format(DATE_RFC822));
304
305         $response = new Response();
306         $this->assertNull($response->getMaxAge(), '->getMaxAge() returns null if no freshness information available');
307     }
308
309     public function testSetSharedMaxAge()
310     {
311         $response = new Response();
312         $response->setSharedMaxAge(20);
313
314         $cacheControl = $response->headers->get('Cache-Control');
315         $this->assertEquals('public, s-maxage=20', $cacheControl);
316     }
317
318     public function testIsPrivate()
319     {
320         $response = new Response();
321         $response->headers->set('Cache-Control', 'max-age=100');
322         $response->setPrivate();
323         $this->assertEquals(100, $response->headers->getCacheControlDirective('max-age'), '->isPrivate() adds the private Cache-Control directive when set to true');
324         $this->assertTrue($response->headers->getCacheControlDirective('private'), '->isPrivate() adds the private Cache-Control directive when set to true');
325
326         $response = new Response();
327         $response->headers->set('Cache-Control', 'public, max-age=100');
328         $response->setPrivate();
329         $this->assertEquals(100, $response->headers->getCacheControlDirective('max-age'), '->isPrivate() adds the private Cache-Control directive when set to true');
330         $this->assertTrue($response->headers->getCacheControlDirective('private'), '->isPrivate() adds the private Cache-Control directive when set to true');
331         $this->assertFalse($response->headers->hasCacheControlDirective('public'), '->isPrivate() removes the public Cache-Control directive');
332     }
333
334     public function testExpire()
335     {
336         $response = new Response();
337         $response->headers->set('Cache-Control', 'max-age=100');
338         $response->expire();
339         $this->assertEquals(100, $response->headers->get('Age'), '->expire() sets the Age to max-age when present');
340
341         $response = new Response();
342         $response->headers->set('Cache-Control', 'max-age=100, s-maxage=500');
343         $response->expire();
344         $this->assertEquals(500, $response->headers->get('Age'), '->expire() sets the Age to s-maxage when both max-age and s-maxage are present');
345
346         $response = new Response();
347         $response->headers->set('Cache-Control', 'max-age=5, s-maxage=500');
348         $response->headers->set('Age', '1000');
349         $response->expire();
350         $this->assertEquals(1000, $response->headers->get('Age'), '->expire() does nothing when the response is already stale/expired');
351
352         $response = new Response();
353         $response->expire();
354         $this->assertFalse($response->headers->has('Age'), '->expire() does nothing when the response does not include freshness information');
355
356         $response = new Response();
357         $response->headers->set('Expires', -1);
358         $response->expire();
359         $this->assertNull($response->headers->get('Age'), '->expire() does not set the Age when the response is expired');
360     }
361
362     public function testGetTtl()
363     {
364         $response = new Response();
365         $this->assertNull($response->getTtl(), '->getTtl() returns null when no Expires or Cache-Control headers are present');
366
367         $response = new Response();
368         $response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(DATE_RFC2822));
369         $this->assertEquals(3600, $response->getTtl(), '->getTtl() uses the Expires header when no max-age is present');
370
371         $response = new Response();
372         $response->headers->set('Expires', $this->createDateTimeOneHourAgo()->format(DATE_RFC2822));
373         $this->assertLessThan(0, $response->getTtl(), '->getTtl() returns negative values when Expires is in past');
374
375         $response = new Response();
376         $response->headers->set('Expires', $response->getDate()->format(DATE_RFC2822));
377         $response->headers->set('Age', 0);
378         $this->assertSame(0, $response->getTtl(), '->getTtl() correctly handles zero');
379
380         $response = new Response();
381         $response->headers->set('Cache-Control', 'max-age=60');
382         $this->assertEquals(60, $response->getTtl(), '->getTtl() uses Cache-Control max-age when present');
383     }
384
385     public function testSetClientTtl()
386     {
387         $response = new Response();
388         $response->setClientTtl(10);
389
390         $this->assertEquals($response->getMaxAge(), $response->getAge() + 10);
391     }
392
393     public function testGetSetProtocolVersion()
394     {
395         $response = new Response();
396
397         $this->assertEquals('1.0', $response->getProtocolVersion());
398
399         $response->setProtocolVersion('1.1');
400
401         $this->assertEquals('1.1', $response->getProtocolVersion());
402     }
403
404     public function testGetVary()
405     {
406         $response = new Response();
407         $this->assertEquals(array(), $response->getVary(), '->getVary() returns an empty array if no Vary header is present');
408
409         $response = new Response();
410         $response->headers->set('Vary', 'Accept-Language');
411         $this->assertEquals(array('Accept-Language'), $response->getVary(), '->getVary() parses a single header name value');
412
413         $response = new Response();
414         $response->headers->set('Vary', 'Accept-Language User-Agent    X-Foo');
415         $this->assertEquals(array('Accept-Language', 'User-Agent', 'X-Foo'), $response->getVary(), '->getVary() parses multiple header name values separated by spaces');
416
417         $response = new Response();
418         $response->headers->set('Vary', 'Accept-Language,User-Agent,    X-Foo');
419         $this->assertEquals(array('Accept-Language', 'User-Agent', 'X-Foo'), $response->getVary(), '->getVary() parses multiple header name values separated by commas');
420
421         $vary = array('Accept-Language', 'User-Agent', 'X-foo');
422
423         $response = new Response();
424         $response->headers->set('Vary', $vary);
425         $this->assertEquals($vary, $response->getVary(), '->getVary() parses multiple header name values in arrays');
426
427         $response = new Response();
428         $response->headers->set('Vary', 'Accept-Language, User-Agent, X-foo');
429         $this->assertEquals($vary, $response->getVary(), '->getVary() parses multiple header name values in arrays');
430     }
431
432     public function testSetVary()
433     {
434         $response = new Response();
435         $response->setVary('Accept-Language');
436         $this->assertEquals(array('Accept-Language'), $response->getVary());
437
438         $response->setVary('Accept-Language, User-Agent');
439         $this->assertEquals(array('Accept-Language', 'User-Agent'), $response->getVary(), '->setVary() replace the vary header by default');
440
441         $response->setVary('X-Foo', false);
442         $this->assertEquals(array('Accept-Language', 'User-Agent', 'X-Foo'), $response->getVary(), '->setVary() doesn\'t wipe out earlier Vary headers if replace is set to false');
443     }
444
445     public function testDefaultContentType()
446     {
447         $headerMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\ResponseHeaderBag')->setMethods(array('set'))->getMock();
448         $headerMock->expects($this->at(0))
449             ->method('set')
450             ->with('Content-Type', 'text/html');
451         $headerMock->expects($this->at(1))
452             ->method('set')
453             ->with('Content-Type', 'text/html; charset=UTF-8');
454
455         $response = new Response('foo');
456         $response->headers = $headerMock;
457
458         $response->prepare(new Request());
459     }
460
461     public function testContentTypeCharset()
462     {
463         $response = new Response();
464         $response->headers->set('Content-Type', 'text/css');
465
466         // force fixContentType() to be called
467         $response->prepare(new Request());
468
469         $this->assertEquals('text/css; charset=UTF-8', $response->headers->get('Content-Type'));
470     }
471
472     public function testPrepareDoesNothingIfContentTypeIsSet()
473     {
474         $response = new Response('foo');
475         $response->headers->set('Content-Type', 'text/plain');
476
477         $response->prepare(new Request());
478
479         $this->assertEquals('text/plain; charset=UTF-8', $response->headers->get('content-type'));
480     }
481
482     public function testPrepareDoesNothingIfRequestFormatIsNotDefined()
483     {
484         $response = new Response('foo');
485
486         $response->prepare(new Request());
487
488         $this->assertEquals('text/html; charset=UTF-8', $response->headers->get('content-type'));
489     }
490
491     public function testPrepareSetContentType()
492     {
493         $response = new Response('foo');
494         $request = Request::create('/');
495         $request->setRequestFormat('json');
496
497         $response->prepare($request);
498
499         $this->assertEquals('application/json', $response->headers->get('content-type'));
500     }
501
502     public function testPrepareRemovesContentForHeadRequests()
503     {
504         $response = new Response('foo');
505         $request = Request::create('/', 'HEAD');
506
507         $length = 12345;
508         $response->headers->set('Content-Length', $length);
509         $response->prepare($request);
510
511         $this->assertEquals('', $response->getContent());
512         $this->assertEquals($length, $response->headers->get('Content-Length'), 'Content-Length should be as if it was GET; see RFC2616 14.13');
513     }
514
515     public function testPrepareRemovesContentForInformationalResponse()
516     {
517         $response = new Response('foo');
518         $request = Request::create('/');
519
520         $response->setContent('content');
521         $response->setStatusCode(101);
522         $response->prepare($request);
523         $this->assertEquals('', $response->getContent());
524         $this->assertFalse($response->headers->has('Content-Type'));
525         $this->assertFalse($response->headers->has('Content-Type'));
526
527         $response->setContent('content');
528         $response->setStatusCode(304);
529         $response->prepare($request);
530         $this->assertEquals('', $response->getContent());
531         $this->assertFalse($response->headers->has('Content-Type'));
532         $this->assertFalse($response->headers->has('Content-Length'));
533     }
534
535     public function testPrepareRemovesContentLength()
536     {
537         $response = new Response('foo');
538         $request = Request::create('/');
539
540         $response->headers->set('Content-Length', 12345);
541         $response->prepare($request);
542         $this->assertEquals(12345, $response->headers->get('Content-Length'));
543
544         $response->headers->set('Transfer-Encoding', 'chunked');
545         $response->prepare($request);
546         $this->assertFalse($response->headers->has('Content-Length'));
547     }
548
549     public function testPrepareSetsPragmaOnHttp10Only()
550     {
551         $request = Request::create('/', 'GET');
552         $request->server->set('SERVER_PROTOCOL', 'HTTP/1.0');
553
554         $response = new Response('foo');
555         $response->prepare($request);
556         $this->assertEquals('no-cache', $response->headers->get('pragma'));
557         $this->assertEquals('-1', $response->headers->get('expires'));
558
559         $request->server->set('SERVER_PROTOCOL', 'HTTP/1.1');
560         $response = new Response('foo');
561         $response->prepare($request);
562         $this->assertFalse($response->headers->has('pragma'));
563         $this->assertFalse($response->headers->has('expires'));
564     }
565
566     public function testSetCache()
567     {
568         $response = new Response();
569         //array('etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public')
570         try {
571             $response->setCache(array('wrong option' => 'value'));
572             $this->fail('->setCache() throws an InvalidArgumentException if an option is not supported');
573         } catch (\Exception $e) {
574             $this->assertInstanceOf('InvalidArgumentException', $e, '->setCache() throws an InvalidArgumentException if an option is not supported');
575             $this->assertContains('"wrong option"', $e->getMessage());
576         }
577
578         $options = array('etag' => '"whatever"');
579         $response->setCache($options);
580         $this->assertEquals($response->getEtag(), '"whatever"');
581
582         $now = $this->createDateTimeNow();
583         $options = array('last_modified' => $now);
584         $response->setCache($options);
585         $this->assertEquals($response->getLastModified()->getTimestamp(), $now->getTimestamp());
586
587         $options = array('max_age' => 100);
588         $response->setCache($options);
589         $this->assertEquals($response->getMaxAge(), 100);
590
591         $options = array('s_maxage' => 200);
592         $response->setCache($options);
593         $this->assertEquals($response->getMaxAge(), 200);
594
595         $this->assertTrue($response->headers->hasCacheControlDirective('public'));
596         $this->assertFalse($response->headers->hasCacheControlDirective('private'));
597
598         $response->setCache(array('public' => true));
599         $this->assertTrue($response->headers->hasCacheControlDirective('public'));
600         $this->assertFalse($response->headers->hasCacheControlDirective('private'));
601
602         $response->setCache(array('public' => false));
603         $this->assertFalse($response->headers->hasCacheControlDirective('public'));
604         $this->assertTrue($response->headers->hasCacheControlDirective('private'));
605
606         $response->setCache(array('private' => true));
607         $this->assertFalse($response->headers->hasCacheControlDirective('public'));
608         $this->assertTrue($response->headers->hasCacheControlDirective('private'));
609
610         $response->setCache(array('private' => false));
611         $this->assertTrue($response->headers->hasCacheControlDirective('public'));
612         $this->assertFalse($response->headers->hasCacheControlDirective('private'));
613     }
614
615     public function testSendContent()
616     {
617         $response = new Response('test response rendering', 200);
618
619         ob_start();
620         $response->sendContent();
621         $string = ob_get_clean();
622         $this->assertContains('test response rendering', $string);
623     }
624
625     public function testSetPublic()
626     {
627         $response = new Response();
628         $response->setPublic();
629
630         $this->assertTrue($response->headers->hasCacheControlDirective('public'));
631         $this->assertFalse($response->headers->hasCacheControlDirective('private'));
632     }
633
634     public function testSetExpires()
635     {
636         $response = new Response();
637         $response->setExpires(null);
638
639         $this->assertNull($response->getExpires(), '->setExpires() remove the header when passed null');
640
641         $now = $this->createDateTimeNow();
642         $response->setExpires($now);
643
644         $this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp());
645     }
646
647     public function testSetLastModified()
648     {
649         $response = new Response();
650         $response->setLastModified($this->createDateTimeNow());
651         $this->assertNotNull($response->getLastModified());
652
653         $response->setLastModified(null);
654         $this->assertNull($response->getLastModified());
655     }
656
657     public function testIsInvalid()
658     {
659         $response = new Response();
660
661         try {
662             $response->setStatusCode(99);
663             $this->fail();
664         } catch (\InvalidArgumentException $e) {
665             $this->assertTrue($response->isInvalid());
666         }
667
668         try {
669             $response->setStatusCode(650);
670             $this->fail();
671         } catch (\InvalidArgumentException $e) {
672             $this->assertTrue($response->isInvalid());
673         }
674
675         $response = new Response('', 200);
676         $this->assertFalse($response->isInvalid());
677     }
678
679     /**
680      * @dataProvider getStatusCodeFixtures
681      */
682     public function testSetStatusCode($code, $text, $expectedText)
683     {
684         $response = new Response();
685
686         $response->setStatusCode($code, $text);
687
688         $statusText = new \ReflectionProperty($response, 'statusText');
689         $statusText->setAccessible(true);
690
691         $this->assertEquals($expectedText, $statusText->getValue($response));
692     }
693
694     public function getStatusCodeFixtures()
695     {
696         return array(
697             array('200', null, 'OK'),
698             array('200', false, ''),
699             array('200', 'foo', 'foo'),
700             array('199', null, 'unknown status'),
701             array('199', false, ''),
702             array('199', 'foo', 'foo'),
703         );
704     }
705
706     public function testIsInformational()
707     {
708         $response = new Response('', 100);
709         $this->assertTrue($response->isInformational());
710
711         $response = new Response('', 200);
712         $this->assertFalse($response->isInformational());
713     }
714
715     public function testIsRedirectRedirection()
716     {
717         foreach (array(301, 302, 303, 307) as $code) {
718             $response = new Response('', $code);
719             $this->assertTrue($response->isRedirection());
720             $this->assertTrue($response->isRedirect());
721         }
722
723         $response = new Response('', 304);
724         $this->assertTrue($response->isRedirection());
725         $this->assertFalse($response->isRedirect());
726
727         $response = new Response('', 200);
728         $this->assertFalse($response->isRedirection());
729         $this->assertFalse($response->isRedirect());
730
731         $response = new Response('', 404);
732         $this->assertFalse($response->isRedirection());
733         $this->assertFalse($response->isRedirect());
734
735         $response = new Response('', 301, array('Location' => '/good-uri'));
736         $this->assertFalse($response->isRedirect('/bad-uri'));
737         $this->assertTrue($response->isRedirect('/good-uri'));
738     }
739
740     public function testIsNotFound()
741     {
742         $response = new Response('', 404);
743         $this->assertTrue($response->isNotFound());
744
745         $response = new Response('', 200);
746         $this->assertFalse($response->isNotFound());
747     }
748
749     public function testIsEmpty()
750     {
751         foreach (array(204, 304) as $code) {
752             $response = new Response('', $code);
753             $this->assertTrue($response->isEmpty());
754         }
755
756         $response = new Response('', 200);
757         $this->assertFalse($response->isEmpty());
758     }
759
760     public function testIsForbidden()
761     {
762         $response = new Response('', 403);
763         $this->assertTrue($response->isForbidden());
764
765         $response = new Response('', 200);
766         $this->assertFalse($response->isForbidden());
767     }
768
769     public function testIsOk()
770     {
771         $response = new Response('', 200);
772         $this->assertTrue($response->isOk());
773
774         $response = new Response('', 404);
775         $this->assertFalse($response->isOk());
776     }
777
778     public function testIsServerOrClientError()
779     {
780         $response = new Response('', 404);
781         $this->assertTrue($response->isClientError());
782         $this->assertFalse($response->isServerError());
783
784         $response = new Response('', 500);
785         $this->assertFalse($response->isClientError());
786         $this->assertTrue($response->isServerError());
787     }
788
789     public function testHasVary()
790     {
791         $response = new Response();
792         $this->assertFalse($response->hasVary());
793
794         $response->setVary('User-Agent');
795         $this->assertTrue($response->hasVary());
796     }
797
798     public function testSetEtag()
799     {
800         $response = new Response('', 200, array('ETag' => '"12345"'));
801         $response->setEtag();
802
803         $this->assertNull($response->headers->get('Etag'), '->setEtag() removes Etags when call with null');
804     }
805
806     /**
807      * @dataProvider validContentProvider
808      */
809     public function testSetContent($content)
810     {
811         $response = new Response();
812         $response->setContent($content);
813         $this->assertEquals((string) $content, $response->getContent());
814     }
815
816     /**
817      * @expectedException \UnexpectedValueException
818      * @dataProvider invalidContentProvider
819      */
820     public function testSetContentInvalid($content)
821     {
822         $response = new Response();
823         $response->setContent($content);
824     }
825
826     public function testSettersAreChainable()
827     {
828         $response = new Response();
829
830         $setters = array(
831             'setProtocolVersion' => '1.0',
832             'setCharset' => 'UTF-8',
833             'setPublic' => null,
834             'setPrivate' => null,
835             'setDate' => $this->createDateTimeNow(),
836             'expire' => null,
837             'setMaxAge' => 1,
838             'setSharedMaxAge' => 1,
839             'setTtl' => 1,
840             'setClientTtl' => 1,
841         );
842
843         foreach ($setters as $setter => $arg) {
844             $this->assertEquals($response, $response->{$setter}($arg));
845         }
846     }
847
848     public function validContentProvider()
849     {
850         return array(
851             'obj' => array(new StringableObject()),
852             'string' => array('Foo'),
853             'int' => array(2),
854         );
855     }
856
857     public function invalidContentProvider()
858     {
859         return array(
860             'obj' => array(new \stdClass()),
861             'array' => array(array()),
862             'bool' => array(true, '1'),
863         );
864     }
865
866     protected function createDateTimeOneHourAgo()
867     {
868         return $this->createDateTimeNow()->sub(new \DateInterval('PT1H'));
869     }
870
871     protected function createDateTimeOneHourLater()
872     {
873         return $this->createDateTimeNow()->add(new \DateInterval('PT1H'));
874     }
875
876     protected function createDateTimeNow()
877     {
878         $date = new \DateTime();
879
880         return $date->setTimestamp(time());
881     }
882
883     protected function provideResponse()
884     {
885         return new Response();
886     }
887
888     /**
889      * @see       http://github.com/zendframework/zend-diactoros for the canonical source repository
890      *
891      * @author    Fábio Pacheco
892      * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
893      * @license   https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
894      */
895     public function ianaCodesReasonPhrasesProvider()
896     {
897         if (!in_array('https', stream_get_wrappers(), true)) {
898             $this->markTestSkipped('The "https" wrapper is not available');
899         }
900
901         $ianaHttpStatusCodes = new \DOMDocument();
902
903         libxml_set_streams_context(stream_context_create(array(
904             'http' => array(
905                 'method' => 'GET',
906                 'timeout' => 30,
907             ),
908         )));
909
910         $ianaHttpStatusCodes->load('https://www.iana.org/assignments/http-status-codes/http-status-codes.xml');
911         if (!$ianaHttpStatusCodes->relaxNGValidate(__DIR__.'/schema/http-status-codes.rng')) {
912             self::fail('Invalid IANA\'s HTTP status code list.');
913         }
914
915         $ianaCodesReasonPhrases = array();
916
917         $xpath = new \DomXPath($ianaHttpStatusCodes);
918         $xpath->registerNamespace('ns', 'http://www.iana.org/assignments');
919
920         $records = $xpath->query('//ns:record');
921         foreach ($records as $record) {
922             $value = $xpath->query('.//ns:value', $record)->item(0)->nodeValue;
923             $description = $xpath->query('.//ns:description', $record)->item(0)->nodeValue;
924
925             if (in_array($description, array('Unassigned', '(Unused)'), true)) {
926                 continue;
927             }
928
929             if (preg_match('/^([0-9]+)\s*\-\s*([0-9]+)$/', $value, $matches)) {
930                 for ($value = $matches[1]; $value <= $matches[2]; ++$value) {
931                     $ianaCodesReasonPhrases[] = array($value, $description);
932                 }
933             } else {
934                 $ianaCodesReasonPhrases[] = array($value, $description);
935             }
936         }
937
938         return $ianaCodesReasonPhrases;
939     }
940
941     /**
942      * @dataProvider ianaCodesReasonPhrasesProvider
943      */
944     public function testReasonPhraseDefaultsAgainstIana($code, $reasonPhrase)
945     {
946         $this->assertEquals($reasonPhrase, Response::$statusTexts[$code]);
947     }
948 }
949
950 class StringableObject
951 {
952     public function __toString()
953     {
954         return 'Foo';
955     }
956 }