[TASK] Use single quotes instead of double quotes
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Http / UriTest.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\Uri;
18
19 /**
20 * Testcase for \TYPO3\CMS\Core\Http\Uri
21 *
22 * Adapted from https://github.com/phly/http/
23 */
24 class UriTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
25 {
26 /**
27 * @test
28 */
29 public function constructorSetsAllProperties()
30 {
31 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
32 $this->assertEquals('https', $uri->getScheme());
33 $this->assertEquals('user:pass', $uri->getUserInfo());
34 $this->assertEquals('local.example.com', $uri->getHost());
35 $this->assertEquals(3001, $uri->getPort());
36 $this->assertEquals('user:pass@local.example.com:3001', $uri->getAuthority());
37 $this->assertEquals('/foo', $uri->getPath());
38 $this->assertEquals('bar=baz', $uri->getQuery());
39 $this->assertEquals('quz', $uri->getFragment());
40 }
41
42 /**
43 * @test
44 */
45 public function canSerializeToString()
46 {
47 $url = 'https://user:pass@local.example.com:3001/foo?bar=baz#quz';
48 $uri = new Uri($url);
49 $this->assertEquals($url, (string) $uri);
50 }
51
52 /**
53 * @test
54 */
55 public function withSchemeReturnsNewInstanceWithNewScheme()
56 {
57 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
58 $new = $uri->withScheme('http');
59 $this->assertNotSame($uri, $new);
60 $this->assertEquals('http', $new->getScheme());
61 $this->assertEquals('http://user:pass@local.example.com:3001/foo?bar=baz#quz', (string) $new);
62 }
63
64 /**
65 * @test
66 */
67 public function withUserInfoReturnsNewInstanceWithProvidedUser()
68 {
69 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
70 $new = $uri->withUserInfo('matthew');
71 $this->assertNotSame($uri, $new);
72 $this->assertEquals('matthew', $new->getUserInfo());
73 $this->assertEquals('https://matthew@local.example.com:3001/foo?bar=baz#quz', (string) $new);
74 }
75
76 /**
77 * @test
78 */
79 public function withUserInfoReturnsNewInstanceWithProvidedUserAndPassword()
80 {
81 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
82 $new = $uri->withUserInfo('matthew', 'zf2');
83 $this->assertNotSame($uri, $new);
84 $this->assertEquals('matthew:zf2', $new->getUserInfo());
85 $this->assertEquals('https://matthew:zf2@local.example.com:3001/foo?bar=baz#quz', (string) $new);
86 }
87
88 /**
89 * @test
90 */
91 public function withHostReturnsNewInstanceWithProvidedHost()
92 {
93 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
94 $new = $uri->withHost('framework.zend.com');
95 $this->assertNotSame($uri, $new);
96 $this->assertEquals('framework.zend.com', $new->getHost());
97 $this->assertEquals('https://user:pass@framework.zend.com:3001/foo?bar=baz#quz', (string) $new);
98 }
99
100 /**
101 * @return array
102 */
103 public function validPortsDataProvider()
104 {
105 return [
106 'int' => [3000],
107 'string' => ['3000']
108 ];
109 }
110
111 /**
112 * @dataProvider validPortsDataProvider
113 * @test
114 */
115 public function withPortReturnsNewInstanceWithProvidedPort($port)
116 {
117 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
118 $new = $uri->withPort($port);
119 $this->assertNotSame($uri, $new);
120 $this->assertEquals($port, $new->getPort());
121 $this->assertEquals(
122 sprintf('https://user:pass@local.example.com:%d/foo?bar=baz#quz', $port),
123 (string) $new
124 );
125 }
126
127 /**
128 * @return array
129 */
130 public function invalidPortsDataProvider()
131 {
132 return [
133 'null' => [null],
134 'true' => [true],
135 'false' => [false],
136 'string' => ['string'],
137 'array' => [[3000]],
138 'object' => [(object) [3000]],
139 'zero' => [0],
140 'too-small' => [-1],
141 'too-big' => [65536],
142 ];
143 }
144
145 /**
146 * @dataProvider invalidPortsDataProvider
147 */
148 public function withPortRaisesExceptionForInvalidPorts($port)
149 {
150 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
151 $this->setExpectedException('InvalidArgumentException', 'Invalid port');
152 $new = $uri->withPort($port);
153 }
154
155 /**
156 * @test
157 */
158 public function withPathReturnsNewInstanceWithProvidedPath()
159 {
160 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
161 $new = $uri->withPath('/bar/baz');
162 $this->assertNotSame($uri, $new);
163 $this->assertEquals('/bar/baz', $new->getPath());
164 $this->assertEquals('https://user:pass@local.example.com:3001/bar/baz?bar=baz#quz', (string) $new);
165 }
166
167 /**
168 * @return array
169 */
170 public function invalidPathsDataProvider()
171 {
172 return [
173 'null' => [null],
174 'true' => [true],
175 'false' => [false],
176 'array' => [['/bar/baz']],
177 'object' => [(object) ['/bar/baz']],
178 'query' => ['/bar/baz?bat=quz'],
179 'fragment' => ['/bar/baz#bat'],
180 ];
181 }
182
183 /**
184 * @dataProvider invalidPathsDataProvider
185 * @test
186 */
187 public function withPathRaisesExceptionForInvalidPaths($path)
188 {
189 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
190 $this->setExpectedException('InvalidArgumentException', 'Invalid path');
191 $new = $uri->withPath($path);
192 }
193
194 /**
195 * @test
196 */
197 public function withQueryReturnsNewInstanceWithProvidedQuery()
198 {
199 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
200 $new = $uri->withQuery('baz=bat');
201 $this->assertNotSame($uri, $new);
202 $this->assertEquals('baz=bat', $new->getQuery());
203 $this->assertEquals('https://user:pass@local.example.com:3001/foo?baz=bat#quz', (string) $new);
204 }
205
206 /**
207 * @return array
208 */
209 public function invalidQueryStringsDataProvider()
210 {
211 return [
212 'null' => [null],
213 'true' => [true],
214 'false' => [false],
215 'array' => [['baz=bat']],
216 'object' => [(object) ['baz=bat']],
217 'fragment' => ['baz=bat#quz'],
218 ];
219 }
220
221 /**
222 * @dataProvider invalidQueryStringsDataProvider
223 * @test
224 */
225 public function withQueryRaisesExceptionForInvalidQueryStrings($query)
226 {
227 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
228 $this->setExpectedException('InvalidArgumentException', 'Query string');
229 $new = $uri->withQuery($query);
230 }
231
232 /**
233 * @test
234 */
235 public function withFragmentReturnsNewInstanceWithProvidedFragment()
236 {
237 $uri = new Uri('https://user:pass@local.example.com:3001/foo?bar=baz#quz');
238 $new = $uri->withFragment('qat');
239 $this->assertNotSame($uri, $new);
240 $this->assertEquals('qat', $new->getFragment());
241 $this->assertEquals('https://user:pass@local.example.com:3001/foo?bar=baz#qat', (string) $new);
242 }
243
244 /**
245 * @return array
246 */
247 public function authorityInfoDataProvider()
248 {
249 return [
250 'host-only' => ['http://foo.com/bar', 'foo.com'],
251 'host-port' => ['http://foo.com:3000/bar', 'foo.com:3000'],
252 'user-host' => ['http://me@foo.com/bar', 'me@foo.com'],
253 'user-host-port' => ['http://me@foo.com:3000/bar', 'me@foo.com:3000'],
254 ];
255 }
256
257 /**
258 * @dataProvider authorityInfoDataProvider
259 * @test
260 */
261 public function getAuthorityReturnsExpectedValues($url, $expected)
262 {
263 $uri = new Uri($url);
264 $this->assertEquals($expected, $uri->getAuthority());
265 }
266
267 /**
268 * @test
269 */
270 public function canEmitOriginFormUrl()
271 {
272 $url = '/foo/bar?baz=bat';
273 $uri = new Uri($url);
274 $this->assertEquals($url, (string) $uri);
275 }
276
277 /**
278 * @test
279 */
280 public function settingEmptyPathOnAbsoluteUriReturnsAnEmptyPath()
281 {
282 $uri = new Uri('http://example.com/foo');
283 $new = $uri->withPath('');
284 $this->assertEquals('', $new->getPath());
285 }
286
287 /**
288 * @test
289 */
290 public function stringRepresentationOfAbsoluteUriWithNoPathSetsAnEmptyPath()
291 {
292 $uri = new Uri('http://example.com');
293 $this->assertEquals('http://example.com', (string) $uri);
294 }
295
296 /**
297 * @test
298 */
299 public function getPathOnOriginFormRemainsAnEmptyPath()
300 {
301 $uri = new Uri('?foo=bar');
302 $this->assertEquals('', $uri->getPath());
303 }
304
305 /**
306 * @test
307 */
308 public function stringRepresentationOfOriginFormWithNoPathRetainsEmptyPath()
309 {
310 $uri = new Uri('?foo=bar');
311 $this->assertEquals('?foo=bar', (string) $uri);
312 }
313
314 /**
315 * @return array
316 */
317 public function invalidConstructorUrisDataProvider()
318 {
319 return [
320 'null' => [null],
321 'true' => [true],
322 'false' => [false],
323 'int' => [1],
324 'float' => [1.1],
325 'array' => [['http://example.com/']],
326 'object' => [(object) ['uri' => 'http://example.com/']],
327 ];
328 }
329
330 /**
331 * @dataProvider invalidConstructorUrisDataProvider
332 */
333 public function constructorRaisesExceptionForNonStringURI($uri)
334 {
335 $this->setExpectedException('InvalidArgumentException');
336 new Uri($uri);
337 }
338
339 /**
340 * @test
341 */
342 public function constructorRaisesExceptionForSeriouslyMalformedURI()
343 {
344 $this->setExpectedException('InvalidArgumentException');
345 new Uri('http:///www.php-fig.org/');
346 }
347
348 /**
349 * @test
350 */
351 public function withSchemeStripsOffDelimiter()
352 {
353 $uri = new Uri('http://example.com');
354 $new = $uri->withScheme('https://');
355 $this->assertEquals('https', $new->getScheme());
356 }
357
358 /**
359 * @return array
360 */
361 public function invalidSchemesDataProvider()
362 {
363 return [
364 'mailto' => ['mailto'],
365 'ftp' => ['ftp'],
366 'telnet' => ['telnet'],
367 'ssh' => ['ssh'],
368 'git' => ['git'],
369 ];
370 }
371
372 /**
373 * @dataProvider invalidSchemesDataProvider
374 * @test
375 */
376 public function constructWithUnsupportedSchemeRaisesAnException($scheme)
377 {
378 $this->setExpectedException('InvalidArgumentException', 'Unsupported scheme');
379 $uri = new Uri($scheme . '://example.com');
380 }
381
382 /**
383 * @dataProvider invalidSchemesDataProvider
384 * @test
385 */
386 public function withSchemeUsingUnsupportedSchemeRaisesAnException($scheme)
387 {
388 $uri = new Uri('http://example.com');
389 $this->setExpectedException('InvalidArgumentException', 'Unsupported scheme');
390 $uri->withScheme($scheme);
391 }
392
393 /**
394 * @test
395 */
396 public function withPathIsNotPrefixedWithSlashIfSetWithoutOne()
397 {
398 $uri = new Uri('http://example.com');
399 $new = $uri->withPath('foo/bar');
400 $this->assertEquals('foo/bar', $new->getPath());
401 }
402
403 /**
404 * @test
405 */
406 public function withPathNotSlashPrefixedIsEmittedWithSlashDelimiterWhenUriIsCastToString()
407 {
408 $uri = new Uri('http://example.com');
409 $new = $uri->withPath('foo/bar');
410 $this->assertEquals('http://example.com/foo/bar', $new->__toString());
411 }
412
413 /**
414 * @test
415 */
416 public function withQueryStripsQueryPrefixIfPresent()
417 {
418 $uri = new Uri('http://example.com');
419 $new = $uri->withQuery('?foo=bar');
420 $this->assertEquals('foo=bar', $new->getQuery());
421 }
422
423 /**
424 * @test
425 */
426 public function withFragmentStripsFragmentPrefixIfPresent()
427 {
428 $uri = new Uri('http://example.com');
429 $new = $uri->withFragment('#/foo/bar');
430 $this->assertEquals('/foo/bar', $new->getFragment());
431 }
432
433 /**
434 * @return array
435 */
436 public function standardSchemePortCombinationsDataProvider()
437 {
438 return [
439 'http' => ['http', 80],
440 'https' => ['https', 443],
441 ];
442 }
443
444 /**
445 * @dataProvider standardSchemePortCombinationsDataProvider
446 * @test
447 */
448 public function getAuthorityOmitsPortForStandardSchemePortCombinations($scheme, $port)
449 {
450 $uri = (new Uri())
451 ->withHost('example.com')
452 ->withScheme($scheme)
453 ->withPort($port);
454 $this->assertEquals('example.com', $uri->getAuthority());
455 }
456
457 /**
458 * @test
459 */
460 public function getPathIsProperlyEncoded()
461 {
462 $uri = (new Uri())->withPath('/foo^bar');
463 $expected = '/foo%5Ebar';
464 $this->assertEquals($expected, $uri->getPath());
465 }
466
467 /**
468 * @test
469 */
470 public function getPathDoesNotBecomeDoubleEncoded()
471 {
472 $uri = (new Uri())->withPath('/foo%5Ebar');
473 $expected = '/foo%5Ebar';
474 $this->assertEquals($expected, $uri->getPath());
475 }
476
477 /**
478 * @return array
479 */
480 public function queryStringsForEncodingDataProvider()
481 {
482 return [
483 'key-only' => ['k^ey', 'k%5Eey'],
484 'key-value' => ['k^ey=valu`', 'k%5Eey=valu%60'],
485 'array-key-only' => ['key[]', 'key%5B%5D'],
486 'array-key-value' => ['key[]=valu`', 'key%5B%5D=valu%60'],
487 'complex' => ['k^ey&key[]=valu`&f<>=`bar', 'k%5Eey&key%5B%5D=valu%60&f%3C%3E=%60bar'],
488 ];
489 }
490
491 /**
492 * @dataProvider queryStringsForEncodingDataProvider
493 * @test
494 */
495 public function getQueryIsProperlyEncoded($query, $expected)
496 {
497 $uri = (new Uri())->withQuery($query);
498 $this->assertEquals($expected, $uri->getQuery());
499 }
500
501 /**
502 * @dataProvider queryStringsForEncodingDataProvider
503 * @test
504 */
505 public function getQueryIsNotDoubleEncoded($query, $expected)
506 {
507 $uri = (new Uri())->withQuery($expected);
508 $this->assertEquals($expected, $uri->getQuery());
509 }
510
511 /**
512 * @test
513 */
514 public function getFragmentIsProperlyEncoded()
515 {
516 $uri = (new Uri())->withFragment('/p^th?key^=`bar#b@z');
517 $expected = '/p%5Eth?key%5E=%60bar%23b@z';
518 $this->assertEquals($expected, $uri->getFragment());
519 }
520
521 /**
522 * @test
523 */
524 public function getFragmentIsNotDoubleEncoded()
525 {
526 $expected = '/p%5Eth?key%5E=%60bar%23b@z';
527 $uri = (new Uri())->withFragment($expected);
528 $this->assertEquals($expected, $uri->getFragment());
529 }
530 }