6fe092c2954c024dbc2a7f739997977fc429ce20
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Tests / Unit / FolderStructure / LinkNodeTest.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Install\Tests\Unit\FolderStructure;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
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.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Core\Messaging\FlashMessage;
19 use TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException;
20 use TYPO3\CMS\Install\FolderStructure\LinkNode;
21 use TYPO3\CMS\Install\FolderStructure\NodeInterface;
22 use TYPO3\CMS\Install\FolderStructure\RootNodeInterface;
23 use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
24 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
25
26 /**
27 * Test case
28 */
29 class LinkNodeTest extends UnitTestCase
30 {
31 /**
32 * @test
33 */
34 public function constructorThrowsExceptionIfParentIsNull()
35 {
36 $this->expectException(InvalidArgumentException::class);
37 $this->expectExceptionCode(1380485700);
38 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
39 $node = $this->getAccessibleMock(LinkNode::class, ['dummy'], [], '', false);
40 $node->__construct([], null);
41 }
42
43 /**
44 * @test
45 */
46 public function constructorThrowsExceptionIfNameContainsForwardSlash()
47 {
48 $this->expectException(InvalidArgumentException::class);
49 $this->expectExceptionCode(1380546061);
50 $parent = $this->createMock(NodeInterface::class);
51 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
52 $node = $this->getAccessibleMock(LinkNode::class, ['dummy'], [], '', false);
53 $structure = [
54 'name' => 'foo/bar',
55 ];
56 $node->__construct($structure, $parent);
57 }
58
59 /**
60 * @test
61 */
62 public function constructorSetsParent()
63 {
64 $parent = $this->createMock(NodeInterface::class);
65 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
66 $node = $this->getAccessibleMock(LinkNode::class, ['dummy'], [], '', false);
67 $structure = [
68 'name' => 'foo',
69 ];
70 $node->__construct($structure, $parent);
71 $this->assertSame($parent, $node->_call('getParent'));
72 }
73
74 /**
75 * @test
76 */
77 public function constructorSetsName()
78 {
79 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
80 $node = $this->getAccessibleMock(LinkNode::class, ['dummy'], [], '', false);
81 $parent = $this->createMock(RootNodeInterface::class);
82 $name = $this->getUniqueId('test_');
83 $node->__construct(['name' => $name], $parent);
84 $this->assertSame($name, $node->getName());
85 }
86
87 /**
88 * @test
89 */
90 public function constructorSetsNameAndTarget()
91 {
92 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
93 $node = $this->getAccessibleMock(LinkNode::class, ['dummy'], [], '', false);
94 $parent = $this->createMock(RootNodeInterface::class);
95 $name = $this->getUniqueId('test_');
96 $target = '../' . $this->getUniqueId('test_');
97 $node->__construct(['name' => $name, 'target' => $target], $parent);
98 $this->assertSame($target, $node->_call('getTarget'));
99 }
100
101 /**
102 * @test
103 */
104 public function getStatusReturnsArray()
105 {
106 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
107 $node = $this->getAccessibleMock(
108 LinkNode::class,
109 ['isWindowsOs', 'getAbsolutePath', 'exists'],
110 [],
111 '',
112 false
113 );
114 $path = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('dir_');
115 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
116 $this->assertInternalType('array', $node->getStatus());
117 }
118
119 /**
120 * @test
121 */
122 public function getStatusReturnsArrayWithInformationStatusIfRunningOnWindows()
123 {
124 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
125 $node = $this->getAccessibleMock(
126 LinkNode::class,
127 ['isWindowsOs', 'getAbsolutePath', 'exists'],
128 [],
129 '',
130 false
131 );
132 $path = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('dir_');
133 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
134 $node->expects($this->once())->method('isWindowsOs')->will($this->returnValue(true));
135 $statusArray = $node->getStatus();
136 $this->assertSame(FlashMessage::INFO, $statusArray[0]->getSeverity());
137 }
138
139 /**
140 * @test
141 */
142 public function getStatusReturnsArrayWithErrorStatusIfLinkNotExists()
143 {
144 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
145 $node = $this->getAccessibleMock(
146 LinkNode::class,
147 ['isWindowsOs', 'getAbsolutePath', 'exists'],
148 [],
149 '',
150 false
151 );
152 $path = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('dir_');
153 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
154 $node->expects($this->any())->method('isWindowsOs')->will($this->returnValue(false));
155 $node->expects($this->once())->method('exists')->will($this->returnValue(false));
156 $statusArray = $node->getStatus();
157 $this->assertSame(FlashMessage::ERROR, $statusArray[0]->getSeverity());
158 }
159
160 /**
161 * @test
162 */
163 public function getStatusReturnsArrayWithWarningStatusIfNodeIsNotALink()
164 {
165 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
166 $node = $this->getAccessibleMock(
167 LinkNode::class,
168 ['isWindowsOs', 'getAbsolutePath', 'exists', 'isLink', 'getRelativePathBelowSiteRoot'],
169 [],
170 '',
171 false
172 );
173 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue(''));
174 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
175 $node->expects($this->once())->method('isLink')->will($this->returnValue(false));
176 $statusArray = $node->getStatus();
177 $this->assertSame(FlashMessage::WARNING, $statusArray[0]->getSeverity());
178 }
179
180 /**
181 * @test
182 */
183 public function getStatusReturnsErrorStatusIfLinkTargetIsNotCorrect()
184 {
185 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
186 $node = $this->getAccessibleMock(
187 LinkNode::class,
188 ['isWindowsOs', 'getAbsolutePath', 'exists', 'isLink', 'isTargetCorrect', 'getCurrentTarget', 'getRelativePathBelowSiteRoot'],
189 [],
190 '',
191 false
192 );
193 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue(''));
194 $node->expects($this->any())->method('getCurrentTarget')->will($this->returnValue(''));
195 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
196 $node->expects($this->any())->method('isLink')->will($this->returnValue(true));
197 $node->expects($this->once())->method('isLink')->will($this->returnValue(false));
198 $statusArray = $node->getStatus();
199 $this->assertSame(FlashMessage::ERROR, $statusArray[0]->getSeverity());
200 }
201
202 /**
203 * @test
204 */
205 public function getStatusReturnsOkStatusIfLinkExistsAndTargetIsCorrect()
206 {
207 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
208 $node = $this->getAccessibleMock(
209 LinkNode::class,
210 ['isWindowsOs', 'getAbsolutePath', 'exists', 'isLink', 'isTargetCorrect', 'getRelativePathBelowSiteRoot'],
211 [],
212 '',
213 false
214 );
215 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue(''));
216 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
217 $node->expects($this->once())->method('isLink')->will($this->returnValue(true));
218 $node->expects($this->once())->method('isTargetCorrect')->will($this->returnValue(true));
219 $node->expects($this->once())->method('getRelativePathBelowSiteRoot')->will($this->returnValue(''));
220 $statusArray = $node->getStatus();
221 $this->assertSame(FlashMessage::OK, $statusArray[0]->getSeverity());
222 }
223
224 /**
225 * @test
226 */
227 public function fixReturnsEmptyArray()
228 {
229 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
230 $node = $this->getAccessibleMock(
231 LinkNode::class,
232 ['getRelativePathBelowSiteRoot'],
233 [],
234 '',
235 false
236 );
237 $statusArray = $node->fix();
238 $this->assertEmpty($statusArray);
239 }
240
241 /**
242 * @test
243 */
244 public function isLinkThrowsExceptionIfLinkNotExists()
245 {
246 $this->expectException(InvalidArgumentException::class);
247 $this->expectExceptionCode(1380556246);
248 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
249 $node = $this->getAccessibleMock(LinkNode::class, ['exists'], [], '', false);
250 $node->expects($this->once())->method('exists')->will($this->returnValue(false));
251 $this->assertFalse($node->_call('isLink'));
252 }
253
254 /**
255 * @test
256 */
257 public function isLinkReturnsTrueIfNameIsLink()
258 {
259 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
260 $node = $this->getAccessibleMock(LinkNode::class, ['exists', 'getAbsolutePath'], [], '', false);
261 $path = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('link_');
262 $target = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('linkTarget_');
263 touch($target);
264 symlink($target, $path);
265 $this->testFilesToDelete[] = $path;
266 $this->testFilesToDelete[] = $target;
267 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
268 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
269 $this->assertTrue($node->_call('isLink'));
270 }
271
272 /**
273 * @test
274 */
275 public function isFileReturnsFalseIfNameIsAFile()
276 {
277 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
278 $node = $this->getAccessibleMock(LinkNode::class, ['exists', 'getAbsolutePath'], [], '', false);
279 $path = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('file_');
280 touch($path);
281 $this->testFilesToDelete[] = $path;
282 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
283 $node->expects($this->any())->method('getAbsolutePath')->will($this->returnValue($path));
284 $this->assertFalse($node->_call('isLink'));
285 }
286
287 /**
288 * @test
289 */
290 public function isTargetCorrectThrowsExceptionIfLinkNotExists()
291 {
292 $this->expectException(InvalidArgumentException::class);
293 $this->expectExceptionCode(1380556245);
294 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
295 $node = $this->getAccessibleMock(LinkNode::class, ['exists'], [], '', false);
296 $node->expects($this->once())->method('exists')->will($this->returnValue(false));
297 $this->assertFalse($node->_call('isTargetCorrect'));
298 }
299
300 /**
301 * @test
302 */
303 public function isTargetCorrectThrowsExceptionIfNodeIsNotALink()
304 {
305 $this->expectException(InvalidArgumentException::class);
306 $this->expectExceptionCode(1380556247);
307 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
308 $node = $this->getAccessibleMock(LinkNode::class, ['exists', 'isLink', 'getTarget'], [], '', false);
309 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
310 $node->expects($this->once())->method('isLink')->will($this->returnValue(false));
311 $this->assertTrue($node->_call('isTargetCorrect'));
312 }
313
314 /**
315 * @test
316 */
317 public function isTargetCorrectReturnsTrueIfNoExpectedLinkTargetIsSpecified()
318 {
319 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
320 $node = $this->getAccessibleMock(LinkNode::class, ['exists', 'isLink', 'getTarget'], [], '', false);
321 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
322 $node->expects($this->any())->method('isLink')->will($this->returnValue(true));
323 $node->expects($this->once())->method('getTarget')->will($this->returnValue(''));
324 $this->assertTrue($node->_call('isTargetCorrect'));
325 }
326
327 /**
328 * @test
329 */
330 public function isTargetCorrectAcceptsATargetWithATrailingSlash()
331 {
332 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
333 $node = $this->getAccessibleMock(LinkNode::class, ['exists', 'isLink', 'getCurrentTarget', 'getTarget'], [], '', false);
334 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
335 $node->expects($this->any())->method('isLink')->will($this->returnValue(true));
336 $node->expects($this->once())->method('getCurrentTarget')->will($this->returnValue('someLinkTarget/'));
337 $node->expects($this->once())->method('getTarget')->will($this->returnValue('someLinkTarget'));
338 $this->assertTrue($node->_call('isTargetCorrect'));
339 }
340
341 /**
342 * @test
343 * @see https://github.com/mikey179/vfsStream/wiki/Known-Issues - symlink doesn't work with vfsStream
344 */
345 public function isTargetCorrectReturnsTrueIfActualTargetIsIdenticalToSpecifiedTarget()
346 {
347 $path = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('link_');
348 $target = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('linkTarget_');
349 touch($target);
350 symlink($target, $path);
351 $this->testFilesToDelete[] = $path;
352 $this->testFilesToDelete[] = $target;
353 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
354 $node = $this->getAccessibleMock(
355 LinkNode::class,
356 ['exists', 'isLink', 'getTarget', 'getAbsolutePath'],
357 [],
358 '',
359 false
360 );
361 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
362 $node->expects($this->any())->method('isLink')->will($this->returnValue(true));
363 $node->expects($this->once())->method('getTarget')->will($this->returnValue(str_replace('/', DIRECTORY_SEPARATOR, $target)));
364 $node->expects($this->once())->method('getAbsolutePath')->will($this->returnValue($path));
365 $this->assertTrue($node->_call('isTargetCorrect'));
366 }
367
368 /**
369 * @test
370 * @see https://github.com/mikey179/vfsStream/wiki/Known-Issues - symlink doesn't work with vfsStream
371 */
372 public function isTargetCorrectReturnsFalseIfActualTargetIsNotIdenticalToSpecifiedTarget()
373 {
374 $path = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('link_');
375 $target = PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('linkTarget_');
376 touch($target);
377 symlink($target, $path);
378 $this->testFilesToDelete[] = $path;
379 $this->testFilesToDelete[] = $target;
380 /** @var $node LinkNode|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject */
381 $node = $this->getAccessibleMock(
382 LinkNode::class,
383 ['exists', 'isLink', 'getTarget', 'getAbsolutePath'],
384 [],
385 '',
386 false
387 );
388 $node->expects($this->any())->method('exists')->will($this->returnValue(true));
389 $node->expects($this->any())->method('isLink')->will($this->returnValue(true));
390 $node->expects($this->once())->method('getTarget')->will($this->returnValue('foo'));
391 $node->expects($this->once())->method('getAbsolutePath')->will($this->returnValue($path));
392 $this->assertFalse($node->_call('isTargetCorrect'));
393 }
394 }