2 declare(strict_types
= 1);
3 namespace TYPO3\CMS\Redirects\Tests\Unit\Service
;
6 * This file is part of the TYPO3 CMS project.
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
15 * The TYPO3 project - inspiring people to share!
18 use Prophecy\Argument
;
19 use Prophecy\Prophecy\ObjectProphecy
;
20 use Psr\Log\LoggerInterface
;
21 use TYPO3\CMS\Core\Http\Uri
;
22 use TYPO3\CMS\Core\LinkHandling\LinkService
;
23 use TYPO3\CMS\Core\Resource\Exception\InvalidPathException
;
24 use TYPO3\CMS\Core\Resource\File
;
25 use TYPO3\CMS\Core\Resource\Folder
;
26 use TYPO3\CMS\Core\Site\Entity\Site
;
27 use TYPO3\CMS\Redirects\Service\RedirectCacheService
;
28 use TYPO3\CMS\Redirects\Service\RedirectService
;
29 use TYPO3\TestingFramework\Core\Unit\UnitTestCase
;
31 class RedirectServiceTest
extends UnitTestCase
34 * @var bool Reset singletons created by subject
36 protected $resetSingletonInstances = true
;
39 * @var RedirectCacheService|ObjectProphecy
41 protected $redirectCacheServiceProphecy;
44 * @var LinkService|ObjectProphecy
46 protected $linkServiceProphecy;
49 * @var RedirectService
51 protected $redirectService;
53 protected function setUp(): void
56 $loggerProphecy = $this->prophesize(LoggerInterface
::class);
57 $this->redirectCacheServiceProphecy
= $this->prophesize(RedirectCacheService
::class);
58 $this->linkServiceProphecy
= $this->prophesize(LinkService
::class);
60 $this->redirectService
= new RedirectService($this->redirectCacheServiceProphecy
->reveal(), $this->linkServiceProphecy
->reveal());
61 $this->redirectService
->setLogger($loggerProphecy->reveal());
63 $GLOBALS['SIM_ACCESS_TIME'] = 42;
69 public function matchRedirectReturnsNullIfNoRedirectsExist()
71 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn([]);
73 $result = $this->redirectService
->matchRedirect('example.com', 'foo');
75 self
::assertNull($result);
81 public function matchRedirectReturnsRedirectOnFlatMatch()
84 'target' => 'https://example.com',
86 'keep_query_parameters' => '0',
87 'target_statuscode' => '307',
92 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
104 $result = $this->redirectService
->matchRedirect('example.com', 'foo');
106 self
::assertSame($row, $result);
112 public function matchRedirectReturnsRedirectOnRespectQueryParametersMatch()
115 'target' => 'https://example.com',
116 'force_https' => '0',
117 'keep_query_parameters' => '0',
118 'respect_query_parameters' => '1',
119 'target_statuscode' => '307',
124 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
127 'respect_query_parameters' => [
128 'index.php?id=123' => [
136 $result = $this->redirectService
->matchRedirect('example.com', 'index.php', 'id=123');
138 self
::assertSame($row, $result);
144 public function matchRedirectReturnsRedirectOnRespectQueryParametersMatchWithSlash()
147 'target' => 'https://example.com',
148 'force_https' => '0',
149 'keep_query_parameters' => '0',
150 'respect_query_parameters' => '1',
151 'target_statuscode' => '307',
156 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
159 'respect_query_parameters' => [
160 'index.php/?id=123' => [
168 $result = $this->redirectService
->matchRedirect('example.com', 'index.php', 'id=123');
170 self
::assertSame($row, $result);
176 public function matchRedirectReturnsRedirectOnFullRespectQueryParametersMatch()
179 'target' => 'https://example.com/target',
180 'force_https' => '0',
181 'keep_query_parameters' => '0',
182 'respect_query_parameters' => '1',
183 'target_statuscode' => '307',
188 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
191 'respect_query_parameters' => [
192 'index.php?id=123&a=b' => [
200 $result = $this->redirectService
->matchRedirect('example.com', 'index.php', 'id=123&a=b');
202 self
::assertSame($row, $result);
208 public function matchRedirectReturnsNullOnPartialRespectQueryParametersMatch()
211 'target' => 'https://example.com/target',
212 'force_https' => '0',
213 'keep_query_parameters' => '0',
214 'respect_query_parameters' => '1',
215 'target_statuscode' => '307',
220 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
223 'respect_query_parameters' => [
224 'index.php?id=123&a=b' => [
232 $result = $this->redirectService
->matchRedirect('example.com', 'index.php', 'id=123&a=a');
234 self
::assertSame(null
, $result);
240 public function matchRedirectReturnsMatchingRedirectWithMatchingQueryParametersOverMatchingPath()
243 'target' => 'https://example.com/no-promotion',
244 'force_https' => '0',
245 'keep_query_parameters' => '0',
246 'respect_query_parameters' => '0',
247 'target_statuscode' => '307',
253 'target' => 'https://example.com/promotion',
254 'force_https' => '0',
255 'keep_query_parameters' => '0',
256 'respect_query_parameters' => '1',
257 'target_statuscode' => '307',
262 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
271 'respect_query_parameters' => [
272 'special/page?key=998877' => [
280 $result = $this->redirectService
->matchRedirect('example.com', 'special/page', 'key=998877');
282 self
::assertSame($row2, $result);
288 public function matchRedirectReturnsRedirectSpecificToDomainOnFlatMatchIfSpecificAndNonSpecificExist()
291 'target' => 'https://example.com',
292 'force_https' => '0',
293 'keep_query_parameters' => '0',
294 'target_statuscode' => '307',
300 'target' => 'https://example.net',
301 'force_https' => '0',
302 'keep_query_parameters' => '0',
303 'target_statuscode' => '307',
308 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
327 $result = $this->redirectService
->matchRedirect('example.com', 'foo');
329 self
::assertSame($row1, $result);
335 public function matchRedirectReturnsRedirectOnRegexMatch()
338 'target' => 'https://example.com',
339 'force_https' => '0',
340 'keep_query_parameters' => '0',
341 'target_statuscode' => '307',
346 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
358 $result = $this->redirectService
->matchRedirect('example.com', 'foo');
360 self
::assertSame($row, $result);
366 public function matchRedirectReturnsOnlyActiveRedirects()
369 'target' => 'https://example.com',
370 'force_https' => '0',
371 'keep_query_parameters' => '0',
372 'target_statuscode' => '307',
378 'target' => 'https://example.net',
379 'force_https' => '0',
380 'keep_query_parameters' => '0',
381 'target_statuscode' => '307',
386 $this->redirectCacheServiceProphecy
->getRedirects()->willReturn(
399 $result = $this->redirectService
->matchRedirect('example.com', 'foo');
401 self
::assertSame($row2, $result);
407 public function getTargetUrlReturnsNullIfUrlCouldNotBeResolved()
409 $this->linkServiceProphecy
->resolve(Argument
::any())->willThrow(new InvalidPathException('', 1516531195));
411 $result = $this->redirectService
->getTargetUrl(['target' => 'invalid'], [], new Site('dummy', 13, []));
413 self
::assertNull($result);
419 public function getTargetUrlReturnsUrlForTypeUrl()
421 $redirectTargetMatch = [
422 'target' => 'https://example.com',
423 'force_https' => '0',
424 'keep_query_parameters' => '0'
427 'type' => LinkService
::TYPE_URL
,
428 'url' => 'https://example.com/'
430 $this->linkServiceProphecy
->resolve($redirectTargetMatch['target'])->willReturn($linkDetails);
432 $result = $this->redirectService
->getTargetUrl($redirectTargetMatch, [], new Site('dummy', 13, []));
434 $uri = new Uri('https://example.com/');
435 self
::assertEquals($uri, $result);
441 public function getTargetUrlReturnsUrlForTypeFile()
443 $fileProphecy = $this->prophesize(File
::class);
444 $fileProphecy->getPublicUrl()->willReturn('https://example.com/file.txt');
445 $redirectTargetMatch = [
446 'target' => 'https://example.com',
447 'force_https' => '0',
448 'keep_query_parameters' => '0',
451 'type' => LinkService
::TYPE_FILE
,
452 'file' => $fileProphecy->reveal()
454 $this->linkServiceProphecy
->resolve($redirectTargetMatch['target'])->willReturn($linkDetails);
456 $result = $this->redirectService
->getTargetUrl($redirectTargetMatch, [], new Site('dummy', 13, []));
458 $uri = new Uri('https://example.com/file.txt');
459 self
::assertEquals($uri, $result);
465 public function getTargetUrlReturnsUrlForTypeFolder()
467 $folderProphecy = $this->prophesize(Folder
::class);
468 $folderProphecy->getPublicUrl()->willReturn('https://example.com/folder/');
469 $redirectTargetMatch = [
470 'target' => 'https://example.com',
471 'force_https' => '0',
472 'keep_query_parameters' => '0',
474 $folder = $folderProphecy->reveal();
476 'type' => LinkService
::TYPE_FOLDER
,
479 $this->linkServiceProphecy
->resolve($redirectTargetMatch['target'])->willReturn($linkDetails);
481 $result = $this->redirectService
->getTargetUrl($redirectTargetMatch, [], new Site('dummy', 13, []));
483 $uri = new Uri('https://example.com/folder/');
484 self
::assertEquals($uri, $result);
490 public function getTargetUrlRespectsForceHttps()
492 $redirectTargetMatch = [
493 'target' => 'https://example.com',
494 'keep_query_parameters' => '0',
495 'force_https' => '1',
498 'type' => LinkService
::TYPE_URL
,
499 'url' => 'http://example.com'
501 $this->linkServiceProphecy
->resolve($redirectTargetMatch['target'])->willReturn($linkDetails);
503 $result = $this->redirectService
->getTargetUrl($redirectTargetMatch, [], new Site('dummy', 13, []));
505 $uri = new Uri('https://example.com');
506 self
::assertEquals($uri, $result);
512 public function getTargetUrlAddsExistingQueryParams()
514 $redirectTargetMatch = [
515 'target' => 'https://example.com',
516 'force_https' => '0',
517 'keep_query_parameters' => '1'
520 'type' => LinkService
::TYPE_URL
,
521 'url' => 'https://example.com/?foo=1&bar=2'
523 $this->linkServiceProphecy
->resolve($redirectTargetMatch['target'])->willReturn($linkDetails);
525 $result = $this->redirectService
->getTargetUrl($redirectTargetMatch, ['bar' => 3, 'baz' => 4], new Site('dummy', 13, []));
527 $uri = new Uri('https://example.com/?bar=2&baz=4&foo=1');
528 self
::assertEquals($uri, $result);