[BUGFIX] Add missing namespace parts
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Imaging / IconFactoryTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Imaging;
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 Prophecy\Argument;
18 use TYPO3\CMS\Core\Imaging\Icon;
19 use TYPO3\CMS\Core\Imaging\IconFactory;
20 use TYPO3\CMS\Core\Imaging\IconProvider\FontawesomeIconProvider;
21 use TYPO3\CMS\Core\Resource\File;
22
23 /**
24 * TestCase for \TYPO3\CMS\Core\Imaging\IconFactory
25 */
26 class IconFactoryTest extends \TYPO3\Components\TestingFramework\Core\Unit\UnitTestCase
27 {
28 /**
29 * @var \TYPO3\CMS\Core\Imaging\IconFactory
30 */
31 protected $subject = null;
32
33 /**
34 * @var string
35 */
36 protected $notRegisteredIconIdentifier = 'my-super-unregistered-identifier';
37
38 /**
39 * @var string
40 */
41 protected $registeredIconIdentifier = 'actions-document-close';
42
43 /**
44 * @var string
45 */
46 protected $registeredSpinningIconIdentifier = 'spinning-icon';
47
48 /**
49 * @var \TYPO3\CMS\Core\Imaging\IconRegistry
50 */
51 protected $iconRegistryMock;
52
53 /**
54 * @var array Simulate a tt_content record
55 */
56 protected $mockRecord = [
57 'header' => 'dummy content header',
58 'uid' => '1',
59 'pid' => '1',
60 'image' => '',
61 'hidden' => '0',
62 'starttime' => '0',
63 'endtime' => '0',
64 'fe_group' => '',
65 'CType' => 'text',
66 't3ver_id' => '0',
67 't3ver_state' => '0',
68 't3ver_wsid' => '0',
69 'sys_language_uid' => '0',
70 'l18n_parent' => '0',
71 'subheader' => '',
72 'bodytext' => '',
73 ];
74
75 /**
76 * Set up
77 *
78 * @return void
79 */
80 protected function setUp()
81 {
82 $this->iconRegistryMock = $this->prophesize(\TYPO3\CMS\Core\Imaging\IconRegistry::class);
83 $this->subject = new IconFactory($this->iconRegistryMock->reveal());
84
85 $this->iconRegistryMock->isRegistered('tcarecords--default')->willReturn(false);
86 $this->iconRegistryMock->isRegistered(Argument::any())->willReturn(true);
87 $this->iconRegistryMock->isDeprecated(Argument::any())->willReturn(false);
88 $this->iconRegistryMock->getDefaultIconIdentifier(Argument::any())->willReturn('default-not-found');
89 $this->iconRegistryMock->getIconIdentifierForMimeType('application/pdf')->willReturn('mimetypes-pdf');
90 $this->iconRegistryMock->getIconIdentifierForMimeType('image/*')->willReturn('mimetypes-media-image');
91 $this->iconRegistryMock->getIconIdentifierForMimeType(Argument::any())->willReturn(null);
92 $this->iconRegistryMock->getIconIdentifierForFileExtension(Argument::any())->willReturn('mimetypes-other-other');
93 $this->iconRegistryMock->getIconIdentifierForFileExtension('foo')->willReturn('mimetypes-other-other');
94 $this->iconRegistryMock->getIconIdentifierForFileExtension('pdf')->willReturn('mimetypes-pdf');
95 $this->iconRegistryMock->getIconIdentifierForFileExtension('png')->willReturn('mimetypes-media-image');
96 $this->iconRegistryMock->getIconConfigurationByIdentifier(Argument::any())->willReturn([
97 'provider' => FontawesomeIconProvider::class,
98 'options' => [
99 'name' => 'times',
100 'additionalClasses' => 'fa-fw'
101 ]
102 ]);
103 }
104
105 /**
106 * DataProvider for icon sizes
107 *
108 * @return array
109 */
110 public function differentSizesDataProvider()
111 {
112 return [
113 ['size ' . Icon::SIZE_SMALL => ['input' => Icon::SIZE_SMALL, 'expected' => Icon::SIZE_SMALL]],
114 ['size ' . Icon::SIZE_DEFAULT => ['input' => Icon::SIZE_DEFAULT, 'expected' => Icon::SIZE_DEFAULT]],
115 ['size ' . Icon::SIZE_LARGE => ['input' => Icon::SIZE_LARGE, 'expected' => Icon::SIZE_LARGE]]
116 ];
117 }
118
119 /**
120 * @test
121 */
122 public function getIconReturnsIconWithCorrectMarkupWrapperIfRegisteredIconIdentifierIsUsed()
123 {
124 $this->assertContains('<span class="icon-markup">',
125 $this->subject->getIcon($this->registeredIconIdentifier)->render());
126 }
127
128 /**
129 * @test
130 */
131 public function getIconByIdentifierReturnsIconWithCorrectMarkupIfRegisteredIconIdentifierIsUsed()
132 {
133 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-actions-document-close" data-identifier="actions-document-close">',
134 $this->subject->getIcon($this->registeredIconIdentifier)->render());
135 }
136
137 /**
138 * @test
139 * @dataProvider differentSizesDataProvider
140 */
141 public function getIconByIdentifierAndSizeReturnsIconWithCorrectMarkupIfRegisteredIconIdentifierIsUsed($size)
142 {
143 $this->assertContains('<span class="t3js-icon icon icon-size-' . $size['expected'] . ' icon-state-default icon-actions-document-close" data-identifier="actions-document-close">',
144 $this->subject->getIcon($this->registeredIconIdentifier, $size['input'])->render());
145 }
146
147 /**
148 * @test
149 * @dataProvider differentSizesDataProvider
150 */
151 public function getIconByIdentifierAndSizeAndWithOverlayReturnsIconWithCorrectOverlayMarkupIfRegisteredIconIdentifierIsUsed($size)
152 {
153 $this->assertContains('<span class="icon-overlay icon-overlay-readonly">',
154 $this->subject->getIcon($this->registeredIconIdentifier, $size['input'], 'overlay-readonly')->render());
155 }
156
157 /**
158 * @test
159 */
160 public function getIconReturnsNotFoundIconWithCorrectMarkupIfUnregisteredIdentifierIsUsed()
161 {
162 $this->iconRegistryMock->isRegistered(Argument::any())->willReturn(false);
163 $this->iconRegistryMock->getDefaultIconIdentifier(Argument::any())->willReturn('default-not-found');
164 $this->iconRegistryMock->getIconConfigurationByIdentifier('default-not-found')->willReturn([
165 'provider' => FontawesomeIconProvider::class,
166 'options' => [
167 'name' => 'times-circle',
168 'additionalClasses' => 'fa-fw'
169 ]
170 ]);
171 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-default-not-found" data-identifier="default-not-found">',
172 $this->subject->getIcon($this->notRegisteredIconIdentifier)->render());
173 }
174
175 /**
176 * @test
177 * @dataProvider differentSizesDataProvider
178 */
179 public function getIconByIdentifierAndSizeReturnsNotFoundIconWithCorrectMarkupIfUnregisteredIdentifierIsUsed($size)
180 {
181 $this->iconRegistryMock->isRegistered(Argument::any())->willReturn(false);
182 $this->iconRegistryMock->getDefaultIconIdentifier(Argument::any())->willReturn('default-not-found');
183 $this->iconRegistryMock->getIconConfigurationByIdentifier('default-not-found')->willReturn([
184 'provider' => FontawesomeIconProvider::class,
185 'options' => [
186 'name' => 'times-circle',
187 'additionalClasses' => 'fa-fw'
188 ]
189 ]);
190 $this->assertContains('<span class="t3js-icon icon icon-size-' . $size['expected'] . ' icon-state-default icon-default-not-found" data-identifier="default-not-found">',
191 $this->subject->getIcon($this->notRegisteredIconIdentifier, $size['input'])->render());
192 }
193
194 /**
195 * @test
196 */
197 public function getIconReturnsCorrectMarkupIfIconIsRegisteredAsSpinningIcon()
198 {
199 $this->iconRegistryMock->getIconConfigurationByIdentifier($this->registeredSpinningIconIdentifier)->willReturn([
200 'provider' => FontawesomeIconProvider::class,
201 'options' => [
202 'name' => 'times-circle',
203 'additionalClasses' => 'fa-fw',
204 'spinning' => true
205 ]
206 ]);
207 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-' . $this->registeredSpinningIconIdentifier . ' icon-spin" data-identifier="spinning-icon">',
208 $this->subject->getIcon($this->registeredSpinningIconIdentifier)->render());
209 }
210
211 /**
212 * @test
213 * @dataProvider differentSizesDataProvider
214 * @param string $size
215 */
216 public function getIconByIdentifierAndSizeAndOverlayReturnsNotFoundIconWithCorrectMarkupIfUnregisteredIdentifierIsUsed($size)
217 {
218 $this->assertContains('<span class="icon-overlay icon-overlay-readonly">',
219 $this->subject->getIcon($this->notRegisteredIconIdentifier, $size['input'], 'overlay-readonly')->render());
220 }
221
222 /**
223 * @test
224 */
225 public function getIconThrowsExceptionIfInvalidSizeIsGiven()
226 {
227 $this->expectException(\InvalidArgumentException::class);
228 $this->subject->getIcon($this->registeredIconIdentifier, 'foo')->render();
229 }
230
231 //
232 // Tests for getIconForFileExtension
233 //
234
235 /**
236 * Tests the return of an icon for a file without extension
237 *
238 * @test
239 */
240 public function getIconForFileWithNoFileTypeReturnsDefaultFileIcon()
241 {
242 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-other-other" data-identifier="mimetypes-other-other">',
243 $this->subject->getIconForFileExtension('')->render());
244 }
245
246 /**
247 * Tests the return of an icon for an unknown file type
248 *
249 * @test
250 */
251 public function getIconForFileWithUnknownFileTypeReturnsDefaultFileIcon()
252 {
253 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-other-other" data-identifier="mimetypes-other-other">',
254 $this->subject->getIconForFileExtension('foo')->render());
255 }
256
257 /**
258 * Tests the return of an icon for a file with extension pdf
259 *
260 * @test
261 */
262 public function getIconForFileWithFileTypePdfReturnsPdfIcon()
263 {
264 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-pdf" data-identifier="mimetypes-pdf">',
265 $this->subject->getIconForFileExtension('pdf')->render());
266 }
267
268 /**
269 * Tests the return of an icon for a file with extension png
270 *
271 * @test
272 */
273 public function getIconForFileWithFileTypePngReturnsPngIcon()
274 {
275 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-media-image" data-identifier="mimetypes-media-image">',
276 $this->subject->getIconForFileExtension('png')->render());
277 }
278
279 /**
280 * @test
281 */
282 public function getIconForResourceReturnsCorrectMarkupForFileResources()
283 {
284 $resourceProphecy = $this->prophesize(File::class);
285 $resourceProphecy->isMissing()->willReturn(false);
286 $resourceProphecy->getExtension()->willReturn('pdf');
287 $resourceProphecy->getMimeType()->willReturn('');
288
289 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-pdf" data-identifier="mimetypes-pdf">',
290 $this->subject->getIconForResource($resourceProphecy->reveal())->render());
291 }
292
293 //////////////////////////////////////////////
294 // Tests concerning getIconForResource
295 //////////////////////////////////////////////
296 /**
297 * Tests the returns of no file
298 *
299 * @test
300 */
301 public function getIconForResourceWithFileWithoutExtensionTypeReturnsOtherIcon()
302 {
303 $fileObject = $this->getTestSubjectFileObject('');
304 $result = $this->subject->getIconForResource($fileObject)->render();
305 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-other-other" data-identifier="mimetypes-other-other">', $result);
306 }
307
308 /**
309 * Tests the returns of unknown file
310 *
311 * @test
312 */
313 public function getIconForResourceWithUnknownFileTypeReturnsOtherIcon()
314 {
315 $fileObject = $this->getTestSubjectFileObject('foo');
316 $result = $this->subject->getIconForResource($fileObject)->render();
317 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-other-other" data-identifier="mimetypes-other-other">', $result);
318 }
319
320 /**
321 * Tests the returns of file pdf
322 *
323 * @test
324 */
325 public function getIconForResourceWithPdfReturnsPdfIcon()
326 {
327 $fileObject = $this->getTestSubjectFileObject('pdf');
328 $result = $this->subject->getIconForResource($fileObject)->render();
329 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-pdf" data-identifier="mimetypes-pdf">', $result);
330 }
331
332 /**
333 * Tests the returns of file pdf with known mime-type
334 *
335 * @test
336 */
337 public function getIconForResourceWithMimeTypeApplicationPdfReturnsPdfIcon()
338 {
339 $fileObject = $this->getTestSubjectFileObject('pdf', 'application/pdf');
340 $result = $this->subject->getIconForResource($fileObject)->render();
341 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-pdf" data-identifier="mimetypes-pdf">', $result);
342 }
343
344 /**
345 * Tests the returns of file with custom image mime-type
346 *
347 * @test
348 */
349 public function getIconForResourceWithCustomImageMimeTypeReturnsImageIcon()
350 {
351 $fileObject = $this->getTestSubjectFileObject('custom', 'image/my-custom-extension');
352 $result = $this->subject->getIconForResource($fileObject)->render();
353 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-media-image" data-identifier="mimetypes-media-image">', $result);
354 }
355
356 /**
357 * Tests the returns of file png
358 *
359 * @test
360 */
361 public function getIconForResourceWithPngFileReturnsIcon()
362 {
363 $fileObject = $this->getTestSubjectFileObject('png', 'image/png');
364 $result = $this->subject->getIconForResource($fileObject)->render();
365 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-media-image" data-identifier="mimetypes-media-image">', $result);
366 }
367
368 /**
369 * Tests the returns of normal folder
370 *
371 * @test
372 */
373 public function getIconForResourceWithFolderReturnsFolderIcon()
374 {
375 $folderObject = $this->getTestSubjectFolderObject('/test');
376 $result = $this->subject->getIconForResource($folderObject)->render();
377 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-apps-filetree-folder-default" data-identifier="apps-filetree-folder-default">', $result);
378 }
379
380 /**
381 * Tests the returns of open folder
382 *
383 * @test
384 */
385 public function getIconForResourceWithOpenFolderReturnsOpenFolderIcon()
386 {
387 $folderObject = $this->getTestSubjectFolderObject('/test');
388 $result = $this->subject->getIconForResource($folderObject, Icon::SIZE_DEFAULT, null, ['folder-open' => true])->render();
389 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-apps-filetree-folder-opened" data-identifier="apps-filetree-folder-opened">', $result);
390 }
391
392 /**
393 * Tests the returns of root folder
394 *
395 * @test
396 */
397 public function getIconForResourceWithRootFolderReturnsRootFolderIcon()
398 {
399 $folderObject = $this->getTestSubjectFolderObject('/');
400 $result = $this->subject->getIconForResource($folderObject)->render();
401 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-apps-filetree-root" data-identifier="apps-filetree-root">', $result);
402 }
403
404 /**
405 * Tests the returns of mount root
406 *
407 * @test
408 */
409 public function getIconForResourceWithMountRootReturnsMountFolderIcon()
410 {
411 $folderObject = $this->getTestSubjectFolderObject('/mount');
412 $result = $this->subject->getIconForResource($folderObject, Icon::SIZE_DEFAULT, null, ['mount-root' => true])->render();
413 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-apps-filetree-mount" data-identifier="apps-filetree-mount">', $result);
414 }
415
416 //
417 // Test for getIconForRecord
418 //
419
420 /**
421 * Tests the returns of NULL table + empty array
422 *
423 * @test
424 */
425 public function getIconForRecordWithNullTableReturnsMissingIcon()
426 {
427 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-default-not-found" data-identifier="default-not-found">',
428 $this->subject->getIconForRecord('', [])->render());
429 }
430
431 /**
432 * Tests the returns of tt_content + empty record
433 *
434 * @test
435 */
436 public function getIconForRecordWithEmptyRecordReturnsNormalIcon()
437 {
438 $GLOBALS['TCA'] = [
439 'tt_content' => [
440 'ctrl' => [
441 'typeicon_column' => 'CType',
442 'typeicon_classes' => [
443 'default' => 'mimetypes-x-content-text',
444 ],
445 ],
446 ],
447 ];
448 $result = $this->subject->getIconForRecord('tt_content', [])->render();
449 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-x-content-text" data-identifier="mimetypes-x-content-text">', $result);
450 }
451
452 /**
453 * Tests the returns of tt_content + mock record
454 *
455 * @test
456 */
457 public function getIconForRecordWithMockRecordReturnsNormalIcon()
458 {
459 $GLOBALS['TCA'] = [
460 'tt_content' => [
461 'ctrl' => [
462 'typeicon_column' => 'CType',
463 'typeicon_classes' => [
464 'text' => 'mimetypes-x-content-text',
465 ],
466 ],
467 ],
468 ];
469 $result = $this->subject->getIconForRecord('tt_content', $this->mockRecord)->render();
470 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-x-content-text" data-identifier="mimetypes-x-content-text">', $result);
471 }
472
473 /**
474 * Tests the returns of tt_content + mock record of type 'list' (aka plugin)
475 *
476 * @test
477 */
478 public function getIconForRecordWithMockRecordOfTypePluginReturnsPluginIcon()
479 {
480 $GLOBALS['TCA'] = [
481 'tt_content' => [
482 'ctrl' => [
483 'typeicon_column' => 'CType',
484 'typeicon_classes' => [
485 'list' => 'mimetypes-x-content-plugin',
486 ],
487 ],
488 ],
489 ];
490 $mockRecord = $this->mockRecord;
491 $mockRecord['CType'] = 'list';
492 $result = $this->subject->getIconForRecord('tt_content', $mockRecord)->render();
493 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-x-content-plugin" data-identifier="mimetypes-x-content-plugin">', $result);
494 }
495
496 /**
497 * Tests the returns of tt_content + mock record with hidden flag
498 *
499 * @test
500 */
501 public function getIconForRecordWithMockRecordWithHiddenFlagReturnsNormalIconAndOverlay()
502 {
503 $GLOBALS['TCA'] = [
504 'tt_content' => [
505 'ctrl' => [
506 'enablecolumns' => [
507 'disabled' => 'hidden',
508 ],
509 'typeicon_column' => 'CType',
510 'typeicon_classes' => [
511 'text' => 'mimetypes-x-content-text',
512 ],
513 ],
514 ],
515 ];
516 $mockRecord = $this->mockRecord;
517 $mockRecord['hidden'] = '1';
518 $result = $this->subject->getIconForRecord('tt_content', $mockRecord)->render();
519 $this->assertContains('<span class="t3js-icon icon icon-size-default icon-state-default icon-mimetypes-x-content-text" data-identifier="mimetypes-x-content-text">', $result);
520 $this->assertContains('<span class="icon-overlay icon-overlay-hidden">', $result);
521 }
522
523 /**
524 * Create file object to use as test subject
525 *
526 * @param string $extension
527 * @param string $mimeType
528 * @return \TYPO3\CMS\Core\Resource\File
529 */
530 protected function getTestSubjectFileObject($extension, $mimeType = '')
531 {
532 $mockedStorage = $this->createMock(\TYPO3\CMS\Core\Resource\ResourceStorage::class);
533 $mockedFile = $this->getMockBuilder(\TYPO3\CMS\Core\Resource\File::class)
534 ->setConstructorArgs([[], $mockedStorage])
535 ->getMock();
536 $mockedFile->expects($this->atMost(1))->method('getExtension')->will($this->returnValue($extension));
537 $mockedFile->expects($this->atLeastOnce())->method('getMimeType')->will($this->returnValue($mimeType));
538 return $mockedFile;
539 }
540
541 /**
542 * Create folder object to use as test subject
543 *
544 * @param string $identifier
545 * @return \TYPO3\CMS\Core\Resource\Folder
546 */
547 protected function getTestSubjectFolderObject($identifier)
548 {
549 $mockedStorage = $this->createMock(\TYPO3\CMS\Core\Resource\ResourceStorage::class);
550 $mockedStorage->expects($this->any())->method('getRootLevelFolder')->will($this->returnValue(
551 new \TYPO3\CMS\Core\Resource\Folder($mockedStorage, '/', '/')
552 ));
553 $mockedStorage->expects($this->any())->method('checkFolderActionPermission')->will($this->returnValue(true));
554 $mockedStorage->expects($this->any())->method('isBrowsable')->will($this->returnValue(true));
555 return new \TYPO3\CMS\Core\Resource\Folder($mockedStorage, $identifier, $identifier);
556 }
557 }