eb1e0f218d8e850b0cedcddea522e4196d6ccd89
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Tests / Unit / Typolink / AbstractTypolinkBuilderTest.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Tests\Unit\Typolink;
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 Psr\Log\LoggerInterface;
18 use TYPO3\CMS\Core\Log\LogManager;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
21 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
22 use TYPO3\CMS\Frontend\Typolink\AbstractTypolinkBuilder;
23 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
24
25 /**
26 * Test case
27 */
28 class AbstractTypolinkBuilderTest extends UnitTestCase
29 {
30 /**
31 * Subject is not notice free, disable E_NOTICES
32 */
33 protected static $suppressNotices = true;
34
35 /**
36 * @var bool Reset singletons created by subject
37 */
38 protected $resetSingletonInstances = true;
39
40 /**
41 * @var \PHPUnit_Framework_MockObject_MockObject|TypoScriptFrontendController|\TYPO3\TestingFramework\Core\AccessibleObjectInterface
42 */
43 protected $frontendControllerMock;
44
45 /**
46 * Set up
47 */
48 protected function setUp()
49 {
50 GeneralUtility::flushInternalRuntimeCaches();
51
52 $this->createMockedLoggerAndLogManager();
53
54 $this->frontendControllerMock = $this->getAccessibleMock(
55 TypoScriptFrontendController::class,
56 ['dummy'],
57 [],
58 '',
59 false
60 );
61 $GLOBALS['TSFE'] = $this->frontendControllerMock;
62 }
63
64 //////////////////////
65 // Utility functions
66 //////////////////////
67
68 /**
69 * Avoid logging to the file system (file writer is currently the only configured writer)
70 */
71 protected function createMockedLoggerAndLogManager()
72 {
73 $logManagerMock = $this->getMockBuilder(LogManager::class)->getMock();
74 $loggerMock = $this->getMockBuilder(LoggerInterface::class)->getMock();
75 $logManagerMock->expects($this->any())
76 ->method('getLogger')
77 ->willReturn($loggerMock);
78 GeneralUtility::setSingletonInstance(LogManager::class, $logManagerMock);
79 }
80
81 /**
82 * @return array The test data for forceAbsoluteUrlReturnsAbsoluteUrl
83 */
84 public function forceAbsoluteUrlReturnsCorrectAbsoluteUrlDataProvider()
85 {
86 return [
87 'Missing forceAbsoluteUrl leaves URL untouched' => [
88 'foo',
89 'foo',
90 []
91 ],
92 'Absolute URL stays unchanged' => [
93 'http://example.org/',
94 'http://example.org/',
95 [
96 'forceAbsoluteUrl' => '1'
97 ]
98 ],
99 'Absolute URL stays unchanged 2' => [
100 'http://example.org/resource.html',
101 'http://example.org/resource.html',
102 [
103 'forceAbsoluteUrl' => '1'
104 ]
105 ],
106 'Scheme and host w/o ending slash stays unchanged' => [
107 'http://example.org',
108 'http://example.org',
109 [
110 'forceAbsoluteUrl' => '1'
111 ]
112 ],
113 'Scheme can be forced' => [
114 'typo3://example.org',
115 'http://example.org',
116 [
117 'forceAbsoluteUrl' => '1',
118 'forceAbsoluteUrl.' => [
119 'scheme' => 'typo3'
120 ]
121 ]
122 ],
123 'Relative path old-style' => [
124 'http://localhost/fileadmin/dummy.txt',
125 '/fileadmin/dummy.txt',
126 [
127 'forceAbsoluteUrl' => '1',
128 ]
129 ],
130 'Relative path' => [
131 'http://localhost/fileadmin/dummy.txt',
132 'fileadmin/dummy.txt',
133 [
134 'forceAbsoluteUrl' => '1',
135 ]
136 ],
137 'Scheme can be forced with pseudo-relative path' => [
138 'typo3://localhost/fileadmin/dummy.txt',
139 '/fileadmin/dummy.txt',
140 [
141 'forceAbsoluteUrl' => '1',
142 'forceAbsoluteUrl.' => [
143 'scheme' => 'typo3'
144 ]
145 ]
146 ],
147 'Hostname only is not treated as valid absolute URL' => [
148 'http://localhost/example.org',
149 'example.org',
150 [
151 'forceAbsoluteUrl' => '1'
152 ]
153 ],
154 'Scheme and host is added to local file path' => [
155 'typo3://localhost/fileadmin/my.pdf',
156 'fileadmin/my.pdf',
157 [
158 'forceAbsoluteUrl' => '1',
159 'forceAbsoluteUrl.' => [
160 'scheme' => 'typo3'
161 ]
162 ]
163 ]
164 ];
165 }
166
167 /**
168 * @param string $expected The expected URL
169 * @param string $url The URL to parse and manipulate
170 * @param array $configuration The configuration array
171 * @test
172 * @dataProvider forceAbsoluteUrlReturnsCorrectAbsoluteUrlDataProvider
173 */
174 public function forceAbsoluteUrlReturnsCorrectAbsoluteUrl($expected, $url, array $configuration)
175 {
176 $contentObjectRendererProphecy = $this->prophesize(ContentObjectRenderer::class);
177 $subject = $this->getAccessibleMock(
178 AbstractTypolinkBuilder::class,
179 ['build'],
180 [$contentObjectRendererProphecy->reveal()],
181 '',
182 false
183 );
184 // Force hostname
185 $_SERVER['HTTP_HOST'] = 'localhost';
186 $_SERVER['SCRIPT_NAME'] = '/typo3/index.php';
187 $GLOBALS['TSFE']->absRefPrefix = '';
188
189 $this->assertEquals($expected, $subject->_call('forceAbsoluteUrl', $url, $configuration));
190 }
191
192 /**
193 * @test
194 */
195 public function forceAbsoluteUrlReturnsCorrectAbsoluteUrlWithSubfolder()
196 {
197 $contentObjectRendererProphecy = $this->prophesize(ContentObjectRenderer::class);
198 $subject = $this->getAccessibleMock(
199 AbstractTypolinkBuilder::class,
200 ['build'],
201 [$contentObjectRendererProphecy->reveal()],
202 '',
203 false
204 );
205 // Force hostname
206 $_SERVER['HTTP_HOST'] = 'localhost';
207 $_SERVER['SCRIPT_NAME'] = '/subfolder/typo3/index.php';
208
209 $expected = 'http://localhost/subfolder/fileadmin/my.pdf';
210 $url = 'fileadmin/my.pdf';
211 $configuration = [
212 'forceAbsoluteUrl' => '1'
213 ];
214
215 $this->assertEquals($expected, $subject->_call('forceAbsoluteUrl', $url, $configuration));
216 }
217
218 /**
219 * Data provider for resolveTargetAttribute
220 *
221 * @return array [[$expected, $conf, $name, $respectFrameSetOption, $fallbackTarget],]
222 */
223 public function resolveTargetAttributeDataProvider(): array
224 {
225 $targetName = $this->getUniqueId('name_');
226 $target = $this->getUniqueId('target_');
227 $fallback = $this->getUniqueId('fallback_');
228 return [
229 'Take target from $conf, if $conf[$targetName] is set.' =>
230 [
231 $target,
232 [$targetName => $target], // $targetName is set
233 $targetName,
234 true,
235 $fallback,
236 'other doctype'
237 ],
238 'Else from fallback, if not $respectFrameSetOption ...' =>
239 [
240 $fallback,
241 [],
242 $targetName,
243 false, // $respectFrameSetOption false
244 $fallback,
245 'other doctype'
246 ],
247 ' ... or no doctype ... ' =>
248 [
249 $fallback,
250 [],
251 $targetName,
252 true,
253 $fallback,
254 null // no $doctype
255 ],
256 ' ... or doctype xhtml_trans... ' =>
257 [
258 $fallback,
259 [],
260 $targetName,
261 true,
262 $fallback,
263 'xhtml_trans'
264 ],
265 ' ... or doctype xhtml_basic... ' =>
266 [
267 $fallback,
268 [],
269 $targetName,
270 true,
271 $fallback,
272 'xhtml_basic'
273 ],
274 ' ... or doctype html5... ' =>
275 [
276 $fallback,
277 [],
278 $targetName,
279 true,
280 $fallback,
281 'html5'
282 ],
283 ' If all hopes fail, an empty string is returned. ' =>
284 [
285 '',
286 [],
287 $targetName,
288 true,
289 $fallback,
290 'other doctype'
291 ],
292 'It finally applies stdWrap' =>
293 [
294 'wrap_target',
295 [$targetName . '.' =>
296 [ 'ifEmpty' => 'wrap_target' ]
297 ],
298 $targetName,
299 true,
300 $fallback,
301 'other doctype'
302 ],
303 ];
304 }
305
306 /**
307 * @test
308 * @dataProvider resolveTargetAttributeDataProvider
309 * @param string $expected
310 * @param array $conf
311 * @param string $name
312 * @param bool $respectFrameSetOption
313 * @param string $fallbackTarget
314 * @param string|null $doctype
315 */
316 public function canResolveTheTargetAttribute(
317 string $expected,
318 array $conf,
319 string $name,
320 bool $respectFrameSetOption,
321 string $fallbackTarget,
322 $doctype
323 ) {
324 $this->frontendControllerMock->config =
325 ['config' => [ 'doctype' => $doctype]];
326 $renderer = GeneralUtility::makeInstance(ContentObjectRenderer::class);
327 $subject = $this->getMockBuilder(AbstractTypolinkBuilder::class)
328 ->setConstructorArgs([$renderer])
329 ->setMethods(['build'])
330 ->getMock();
331 $actual = $this->callInaccessibleMethod(
332 $subject,
333 'resolveTargetAttribute',
334 $conf,
335 $name,
336 $respectFrameSetOption,
337 $fallbackTarget
338 );
339 $this->assertEquals($expected, $actual);
340 }
341 }