[FEATURE] Introduce Request/Response based on PSR-7
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Http / ResponseTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Http;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Http\Response;
18 use TYPO3\CMS\Core\Http\Stream;
19
20 /**
21 * Testcase for \TYPO3\CMS\Core\Http\Response
22 *
23 * Adapted from https://github.com/phly/http/
24 */
25 class ResponseTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
26
27 /**
28 * @var Response
29 */
30 protected $response;
31
32 public function setUp() {
33 $this->response = new Response();
34 }
35
36 /**
37 * @test
38 */
39 public function testStatusCodeIs200ByDefault() {
40 $this->assertEquals(200, $this->response->getStatusCode());
41 }
42
43 /**
44 * @test
45 */
46 public function testStatusCodeMutatorReturnsCloneWithChanges() {
47 $response = $this->response->withStatus(400);
48 $this->assertNotSame($this->response, $response);
49 $this->assertEquals(400, $response->getStatusCode());
50 }
51
52 /**
53 * @return array
54 */
55 public function invalidStatusCodesDataProvider() {
56 return [
57 'too-low' => [99],
58 'too-high' => [600],
59 'null' => [NULL],
60 'bool' => [TRUE],
61 'string' => ['foo'],
62 'array' => [[200]],
63 'object' => [(object) [200]],
64 ];
65 }
66
67 /**
68 * @dataProvider invalidStatusCodesDataProvider
69 * @test
70 */
71 public function testCannotSetInvalidStatusCode($code) {
72 $this->setExpectedException('InvalidArgumentException');
73 $response = $this->response->withStatus($code);
74 }
75
76 /**
77 * @test
78 */
79 public function testReasonPhraseDefaultsToStandards() {
80 $response = $this->response->withStatus(422);
81 $this->assertEquals('Unprocessable Entity', $response->getReasonPhrase());
82 }
83
84 /**
85 * @test
86 */
87 public function testCanSetCustomReasonPhrase() {
88 $response = $this->response->withStatus(422, 'Foo Bar!');
89 $this->assertEquals('Foo Bar!', $response->getReasonPhrase());
90 }
91
92 /**
93 * @test
94 */
95 public function testConstructorRaisesExceptionForInvalidStream() {
96 $this->setExpectedException('InvalidArgumentException');
97 new Response(['TOTALLY INVALID']);
98 }
99
100 /**
101 * @test
102 */
103 public function testConstructorCanAcceptAllMessageParts() {
104 $body = new Stream('php://memory');
105 $status = 302;
106 $headers = [
107 'location' => ['http://example.com/'],
108 ];
109
110 $response = new Response($body, $status, $headers);
111 $this->assertSame($body, $response->getBody());
112 $this->assertEquals(302, $response->getStatusCode());
113 $this->assertEquals($headers, $response->getHeaders());
114 }
115
116 /**
117 * @return array
118 */
119 public function invalidStatusDataProvider() {
120 return [
121 'true' => [TRUE],
122 'false' => [FALSE],
123 'float' => [100.1],
124 'bad-string' => ['Two hundred'],
125 'array' => [[200]],
126 'object' => [(object) ['statusCode' => 200]],
127 'too-small' => [1],
128 'too-big' => [600],
129 ];
130 }
131
132 /**
133 * @dataProvider invalidStatusDataProvider
134 * @test
135 */
136 public function testConstructorRaisesExceptionForInvalidStatus($code) {
137 $this->setExpectedException('InvalidArgumentException', 'The given status code is not a valid HTTP status code.');
138 new Response('php://memory', $code);
139 }
140
141 /**
142 * @return array
143 */
144 public function invalidResponseBodyDataProvider() {
145 return [
146 'true' => [TRUE],
147 'false' => [FALSE],
148 'int' => [1],
149 'float' => [1.1],
150 'array' => [['BODY']],
151 'stdClass' => [(object) ['body' => 'BODY']],
152 ];
153 }
154
155 /**
156 * @dataProvider invalidResponseBodyDataProvider
157 * @test
158 */
159 public function testConstructorRaisesExceptionForInvalidBody($body) {
160 $this->setExpectedException('InvalidArgumentException', 'stream');
161 new Response($body);
162 }
163
164 /**
165 * @test
166 */
167 public function constructorIgonoresInvalidHeaders() {
168 $headers = [
169 ['INVALID'],
170 'x-invalid-null' => NULL,
171 'x-invalid-true' => TRUE,
172 'x-invalid-false' => FALSE,
173 'x-invalid-int' => 1,
174 'x-invalid-object' => (object) ['INVALID'],
175 'x-valid-string' => 'VALID',
176 'x-valid-array' => ['VALID'],
177 ];
178 $expected = [
179 'x-valid-string' => ['VALID'],
180 'x-valid-array' => ['VALID'],
181 ];
182 $response = new Response('php://memory', 200, $headers);
183 $this->assertEquals($expected, $response->getHeaders());
184 }
185
186 /**
187 * @return array
188 */
189 public function headersWithInjectionVectorsDataProvider() {
190 return [
191 'name-with-cr' => ["X-Foo\r-Bar", 'value'],
192 'name-with-lf' => ["X-Foo\n-Bar", 'value'],
193 'name-with-crlf' => ["X-Foo\r\n-Bar", 'value'],
194 'name-with-2crlf' => ["X-Foo\r\n\r\n-Bar", 'value'],
195 'value-with-cr' => ['X-Foo-Bar', "value\rinjection"],
196 'value-with-lf' => ['X-Foo-Bar', "value\ninjection"],
197 'value-with-crlf' => ['X-Foo-Bar', "value\r\ninjection"],
198 'value-with-2crlf' => ['X-Foo-Bar', "value\r\n\r\ninjection"],
199 'array-value-with-cr' => ['X-Foo-Bar', ["value\rinjection"]],
200 'array-value-with-lf' => ['X-Foo-Bar', ["value\ninjection"]],
201 'array-value-with-crlf' => ['X-Foo-Bar', ["value\r\ninjection"]],
202 'array-value-with-2crlf' => ['X-Foo-Bar', ["value\r\n\r\ninjection"]],
203 ];
204 }
205
206 /**
207 * @test
208 * @dataProvider headersWithInjectionVectorsDataProvider
209 */
210 public function cnstructorRaisesExceptionForHeadersWithCRLFVectors($name, $value) {
211 $this->setExpectedException('InvalidArgumentException');
212 $request = new Response('php://memory', 200, [$name => $value]);
213 }
214 }