54d2296c1f8e2bd8ba9a06dcf7ad85428dcd56ed
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Utility / ExtensionManagementUtilityTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Utility;
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\Cache\CacheManager;
18 use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
19 use TYPO3\CMS\Core\Category\CategoryRegistry;
20 use TYPO3\CMS\Core\Compatibility\LoadedExtensionsArray;
21 use TYPO3\CMS\Core\Core\Environment;
22 use TYPO3\CMS\Core\Package\MetaData;
23 use TYPO3\CMS\Core\Package\Package;
24 use TYPO3\CMS\Core\Package\PackageManager;
25 use TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy;
26 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
29
30 /**
31 * Test case
32 */
33 class ExtensionManagementUtilityTest extends UnitTestCase
34 {
35 /**
36 * Subject is not notice free, disable E_NOTICES
37 */
38 protected static $suppressNotices = true;
39
40 /**
41 * @var bool Reset singletons created by subject
42 */
43 protected $resetSingletonInstances = true;
44
45 /**
46 * @var \TYPO3\CMS\Core\Package\PackageManager
47 */
48 protected $backUpPackageManager;
49
50 /**
51 * Set up
52 */
53 protected function setUp()
54 {
55 $this->backUpPackageManager = ExtensionManagementUtilityAccessibleProxy::getPackageManager();
56 }
57
58 /**
59 * Tear down
60 */
61 protected function tearDown()
62 {
63 ExtensionManagementUtility::clearExtensionKeyMap();
64 ExtensionManagementUtilityAccessibleProxy::setPackageManager($this->backUpPackageManager);
65 ExtensionManagementUtilityAccessibleProxy::setCacheManager(null);
66 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($this->backUpPackageManager);
67 parent::tearDown();
68 }
69
70 /**
71 * @param string $packageKey
72 * @param array $packageMethods
73 * @return PackageManager|\PHPUnit_Framework_MockObject_MockObject
74 */
75 protected function createMockPackageManagerWithMockPackage($packageKey, $packageMethods = ['getPackagePath', 'getPackageKey'])
76 {
77 $packagePath = Environment::getVarPath() . '/tests/' . $packageKey . '/';
78 GeneralUtility::mkdir_deep($packagePath);
79 $this->testFilesToDelete[] = $packagePath;
80 $package = $this->getMockBuilder(Package::class)
81 ->disableOriginalConstructor()
82 ->setMethods($packageMethods)
83 ->getMock();
84 $packageManager = $this->getMockBuilder(PackageManager::class)
85 ->setMethods(['isPackageActive', 'getPackage', 'getActivePackages'])
86 ->disableOriginalConstructor()
87 ->getMock();
88 $package->expects($this->any())
89 ->method('getPackagePath')
90 ->will($this->returnValue($packagePath));
91 $package->expects($this->any())
92 ->method('getPackageKey')
93 ->will($this->returnValue($packageKey));
94 $packageManager->expects($this->any())
95 ->method('isPackageActive')
96 ->will($this->returnValueMap([
97 [null, false],
98 [$packageKey, true]
99 ]));
100 $packageManager->expects($this->any())
101 ->method('getPackage')
102 ->with($this->equalTo($packageKey))
103 ->will($this->returnValue($package));
104 $packageManager->expects($this->any())
105 ->method('getActivePackages')
106 ->will($this->returnValue([$packageKey => $package]));
107 return $packageManager;
108 }
109
110 ///////////////////////////////
111 // Tests concerning isLoaded
112 ///////////////////////////////
113 /**
114 * @test
115 */
116 public function isLoadedReturnsFalseIfExtensionIsNotLoaded()
117 {
118 $this->assertFalse(ExtensionManagementUtility::isLoaded($this->getUniqueId('foobar')));
119 }
120
121 ///////////////////////////////
122 // Tests concerning extPath
123 ///////////////////////////////
124 /**
125 * @test
126 */
127 public function extPathThrowsExceptionIfExtensionIsNotLoaded()
128 {
129 $this->expectException(\BadFunctionCallException::class);
130 $this->expectExceptionCode(1365429656);
131
132 $packageName = $this->getUniqueId('foo');
133 /** @var PackageManager|\PHPUnit_Framework_MockObject_MockObject $packageManager */
134 $packageManager = $this->getMockBuilder(PackageManager::class)
135 ->setMethods(['isPackageActive'])
136 ->disableOriginalConstructor()
137 ->getMock();
138 $packageManager->expects($this->once())
139 ->method('isPackageActive')
140 ->with($this->equalTo($packageName))
141 ->will($this->returnValue(false));
142 ExtensionManagementUtility::setPackageManager($packageManager);
143 ExtensionManagementUtility::extPath($packageName);
144 }
145
146 /**
147 * @test
148 */
149 public function extPathAppendsScriptNameToPath()
150 {
151 $package = $this->getMockBuilder(Package::class)
152 ->disableOriginalConstructor()
153 ->setMethods(['getPackagePath'])
154 ->getMock();
155 /** @var PackageManager|\PHPUnit_Framework_MockObject_MockObject $packageManager */
156 $packageManager = $this->getMockBuilder(PackageManager::class)
157 ->setMethods(['isPackageActive', 'getPackage'])
158 ->disableOriginalConstructor()
159 ->getMock();
160 $package->expects($this->once())
161 ->method('getPackagePath')
162 ->will($this->returnValue(Environment::getPublicPath() . '/foo/'));
163 $packageManager->expects($this->once())
164 ->method('isPackageActive')
165 ->with($this->equalTo('foo'))
166 ->will($this->returnValue(true));
167 $packageManager->expects($this->once())
168 ->method('getPackage')
169 ->with('foo')
170 ->will($this->returnValue($package));
171 ExtensionManagementUtility::setPackageManager($packageManager);
172 $this->assertSame(Environment::getPublicPath() . '/foo/bar.txt', ExtensionManagementUtility::extPath('foo', 'bar.txt'));
173 }
174
175 //////////////////////
176 // Utility functions
177 //////////////////////
178 /**
179 * Generates a basic TCA for a given table.
180 *
181 * @param string $table name of the table, must not be empty
182 * @return array generated TCA for the given table, will not be empty
183 */
184 private function generateTCAForTable($table)
185 {
186 $tca = [];
187 $tca[$table] = [];
188 $tca[$table]['columns'] = [
189 'fieldA' => [],
190 'fieldC' => []
191 ];
192 $tca[$table]['types'] = [
193 'typeA' => ['showitem' => 'fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1'],
194 'typeB' => ['showitem' => 'fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1'],
195 'typeC' => ['showitem' => 'fieldC;;paletteD']
196 ];
197 $tca[$table]['palettes'] = [
198 'paletteA' => ['showitem' => 'fieldX, fieldX1, fieldY'],
199 'paletteB' => ['showitem' => 'fieldX, fieldX1, fieldY'],
200 'paletteC' => ['showitem' => 'fieldX, fieldX1, fieldY'],
201 'paletteD' => ['showitem' => 'fieldX, fieldX1, fieldY']
202 ];
203 return $tca;
204 }
205
206 /**
207 * Data provider for getClassNamePrefixForExtensionKey.
208 *
209 * @return array
210 */
211 public function extensionKeyDataProvider()
212 {
213 return [
214 'Without underscores' => [
215 'testkey',
216 'tx_testkey'
217 ],
218 'With underscores' => [
219 'this_is_a_test_extension',
220 'tx_thisisatestextension'
221 ],
222 'With user prefix and without underscores' => [
223 'user_testkey',
224 'user_testkey'
225 ],
226 'With user prefix and with underscores' => [
227 'user_test_key',
228 'user_testkey'
229 ],
230 ];
231 }
232
233 /**
234 * @test
235 * @param string $extensionName
236 * @param string $expectedPrefix
237 * @dataProvider extensionKeyDataProvider
238 */
239 public function getClassNamePrefixForExtensionKey($extensionName, $expectedPrefix)
240 {
241 $this->assertSame($expectedPrefix, ExtensionManagementUtility::getCN($extensionName));
242 }
243
244 //////////////////////////////////////
245 // Tests concerning addToAllTCAtypes
246 //////////////////////////////////////
247 /**
248 * Tests whether fields can be add to all TCA types and duplicate fields are considered.
249 *
250 * @test
251 * @see ExtensionManagementUtility::addToAllTCAtypes()
252 */
253 public function canAddFieldsToAllTCATypesBeforeExistingOnes()
254 {
255 $table = $this->getUniqueId('tx_coretest_table');
256 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
257 ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'before:fieldD');
258 // Checking typeA:
259 $this->assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, newA, newB, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
260 // Checking typeB:
261 $this->assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, newA, newB, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
262 }
263
264 /**
265 * Tests whether fields can be add to all TCA types and duplicate fields are considered.
266 *
267 * @test
268 * @see ExtensionManagementUtility::addToAllTCAtypes()
269 */
270 public function canAddFieldsToAllTCATypesAfterExistingOnes()
271 {
272 $table = $this->getUniqueId('tx_coretest_table');
273 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
274 ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'after:fieldC');
275 // Checking typeA:
276 $this->assertEquals('fieldA, fieldB, fieldC;labelC, newA, newB, --palette--;;paletteC, fieldC1, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
277 // Checking typeB:
278 $this->assertEquals('fieldA, fieldB, fieldC;labelC, newA, newB, --palette--;;paletteC, fieldC1, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
279 }
280
281 /**
282 * Tests whether fields can be add to all TCA types and duplicate fields are considered.
283 *
284 * @test
285 * @see ExtensionManagementUtility::addToAllTCAtypes()
286 */
287 public function canAddFieldsToAllTCATypesRespectsPalettes()
288 {
289 $table = $this->getUniqueId('tx_coretest_table');
290 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
291 $GLOBALS['TCA'][$table]['types']['typeD'] = ['showitem' => 'fieldY, --palette--;;standard, fieldZ'];
292 ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'after:--palette--;;standard');
293 // Checking typeD:
294 $this->assertEquals('fieldY, --palette--;;standard, newA, newB, fieldA, fieldZ', $GLOBALS['TCA'][$table]['types']['typeD']['showitem']);
295 }
296
297 /**
298 * Tests whether fields can be add to all TCA types and fields in pallets are respected.
299 *
300 * @test
301 * @see ExtensionManagementUtility::addToAllTCAtypes()
302 */
303 public function canAddFieldsToAllTCATypesRespectsPositionFieldInPalette()
304 {
305 $table = $this->getUniqueId('tx_coretest_table');
306 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
307 ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'after:fieldX1');
308 // Checking typeA:
309 $this->assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, newA, newB, fieldC1, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
310 }
311
312 /**
313 * Tests whether fields can be add to a TCA type before existing ones
314 *
315 * @test
316 * @see ExtensionManagementUtility::addToAllTCAtypes()
317 */
318 public function canAddFieldsToTCATypeBeforeExistingOnes()
319 {
320 $table = $this->getUniqueId('tx_coretest_table');
321 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
322 ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', 'typeA', 'before:fieldD');
323 // Checking typeA:
324 $this->assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, newA, newB, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
325 // Checking typeB:
326 $this->assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
327 }
328
329 /**
330 * Tests whether fields can be add to a TCA type after existing ones
331 *
332 * @test
333 * @see ExtensionManagementUtility::addToAllTCAtypes()
334 */
335 public function canAddFieldsToTCATypeAfterExistingOnes()
336 {
337 $table = $this->getUniqueId('tx_coretest_table');
338 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
339 ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', 'typeA', 'after:fieldC');
340 // Checking typeA:
341 $this->assertEquals('fieldA, fieldB, fieldC;labelC, newA, newB, --palette--;;paletteC, fieldC1, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
342 // Checking typeB:
343 $this->assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1', $GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
344 }
345
346 /**
347 * @test
348 */
349 public function canAddFieldWithPartOfAlreadyExistingFieldname()
350 {
351 $table = $this->getUniqueId('tx_coretest_table');
352 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
353 ExtensionManagementUtility::addToAllTCAtypes($table, 'field', 'typeA', 'after:fieldD1');
354
355 $this->assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1, field', $GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
356 }
357
358 /**
359 * Test wheter replacing other TCA fields works as promissed
360 *
361 * @test
362 * @see ExtensionManagementUtility::addFieldsToAllPalettesOfField()
363 */
364 public function canAddFieldsToTCATypeAndReplaceExistingOnes()
365 {
366 $table = $this->getUniqueId('tx_coretest_table');
367 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
368 $typesBefore = $GLOBALS['TCA'][$table]['types'];
369 ExtensionManagementUtility::addToAllTCAtypes($table, 'fieldZ', '', 'replace:fieldX');
370 $this->assertEquals($typesBefore, $GLOBALS['TCA'][$table]['types'], 'It\'s wrong that the "types" array changes here - the replaced field is only on palettes');
371 // unchanged because the palette is not used
372 $this->assertEquals('fieldX, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
373 $this->assertEquals('fieldX, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteB']['showitem']);
374 // changed
375 $this->assertEquals('fieldZ, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteC']['showitem']);
376 $this->assertEquals('fieldZ, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteD']['showitem']);
377 }
378
379 /**
380 * @test
381 */
382 public function addToAllTCAtypesReplacesExistingOnes()
383 {
384 $table = $this->getUniqueId('tx_coretest_table');
385 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
386 $typesBefore = $GLOBALS['TCA'][$table]['types'];
387 ExtensionManagementUtility::addToAllTCAtypes($table, 'fieldX, --palette--;;foo', '', 'replace:fieldX');
388 $this->assertEquals($typesBefore, $GLOBALS['TCA'][$table]['types'], 'It\'s wrong that the "types" array changes here - the replaced field is only on palettes');
389 // unchanged because the palette is not used
390 $this->assertEquals('fieldX, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
391 $this->assertEquals('fieldX, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteB']['showitem']);
392 // changed
393 $this->assertEquals('fieldX, --palette--;;foo, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteC']['showitem']);
394 $this->assertEquals('fieldX, --palette--;;foo, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteD']['showitem']);
395 }
396
397 /**
398 * Tests whether fields can be added to a palette before existing elements.
399 *
400 * @test
401 * @see ExtensionManagementUtility::addFieldsToPalette()
402 */
403 public function canAddFieldsToPaletteBeforeExistingOnes()
404 {
405 $table = $this->getUniqueId('tx_coretest_table');
406 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
407 ExtensionManagementUtility::addFieldsToPalette($table, 'paletteA', 'newA, newA, newB, fieldX', 'before:fieldY');
408 $this->assertEquals('fieldX, fieldX1, newA, newB, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
409 }
410
411 /**
412 * Tests whether fields can be added to a palette after existing elements.
413 *
414 * @test
415 * @see ExtensionManagementUtility::addFieldsToPalette()
416 */
417 public function canAddFieldsToPaletteAfterExistingOnes()
418 {
419 $table = $this->getUniqueId('tx_coretest_table');
420 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
421 ExtensionManagementUtility::addFieldsToPalette($table, 'paletteA', 'newA, newA, newB, fieldX', 'after:fieldX');
422 $this->assertEquals('fieldX, newA, newB, fieldX1, fieldY', $GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
423 }
424
425 /**
426 * Tests whether fields can be added to a palette after a not existing elements.
427 *
428 * @test
429 * @see ExtensionManagementUtility::addFieldsToPalette()
430 */
431 public function canAddFieldsToPaletteAfterNotExistingOnes()
432 {
433 $table = $this->getUniqueId('tx_coretest_table');
434 $GLOBALS['TCA'] = $this->generateTCAForTable($table);
435 ExtensionManagementUtility::addFieldsToPalette($table, 'paletteA', 'newA, newA, newB, fieldX', 'after:' . $this->getUniqueId('notExisting'));
436 $this->assertEquals('fieldX, fieldX1, fieldY, newA, newB', $GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
437 }
438
439 /**
440 * @return array
441 */
442 public function removeDuplicatesForInsertionRemovesDuplicatesDataProvider()
443 {
444 return [
445 'Simple' => [
446 'field_b, field_d, field_c',
447 'field_a, field_b, field_c',
448 'field_d'
449 ],
450 'with linebreaks' => [
451 'field_b, --linebreak--, field_d, --linebreak--, field_c',
452 'field_a, field_b, field_c',
453 '--linebreak--, field_d, --linebreak--'
454 ],
455 'with linebreaks in list and insertion list' => [
456 'field_b, --linebreak--, field_d, --linebreak--, field_c',
457 'field_a, field_b, --linebreak--, field_c',
458 '--linebreak--, field_d, --linebreak--'
459 ],
460 ];
461 }
462
463 /**
464 * @test
465 * @dataProvider removeDuplicatesForInsertionRemovesDuplicatesDataProvider
466 * @param $insertionList
467 * @param $list
468 * @param $expected
469 */
470 public function removeDuplicatesForInsertionRemovesDuplicates($insertionList, $list, $expected)
471 {
472 $result = ExtensionManagementUtilityAccessibleProxy::removeDuplicatesForInsertion($insertionList, $list);
473 $this->assertSame($expected, $result);
474 }
475
476 ///////////////////////////////////////////////////
477 // Tests concerning addFieldsToAllPalettesOfField
478 ///////////////////////////////////////////////////
479
480 /**
481 * @test
482 */
483 public function addFieldsToAllPalettesOfFieldDoesNotAddAnythingIfFieldIsNotRegisteredInColumns()
484 {
485 $GLOBALS['TCA'] = [
486 'aTable' => [
487 'types' => [
488 'typeA' => [
489 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
490 ],
491 ],
492 'palettes' => [
493 'paletteA' => [
494 'showitem' => 'fieldX, fieldY',
495 ],
496 ],
497 ],
498 ];
499 $expected = $GLOBALS['TCA'];
500 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
501 'aTable',
502 'fieldA',
503 'newA'
504 );
505 $this->assertEquals($expected, $GLOBALS['TCA']);
506 }
507
508 /**
509 * @test
510 */
511 public function addFieldsToAllPalettesOfFieldAddsFieldsToPaletteAndSuppressesDuplicates()
512 {
513 $GLOBALS['TCA'] = [
514 'aTable' => [
515 'columns' => [
516 'fieldA' => [],
517 ],
518 'types' => [
519 'typeA' => [
520 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
521 ],
522 ],
523 'palettes' => [
524 'paletteA' => [
525 'showitem' => 'fieldX, fieldY',
526 ],
527 ],
528 ],
529 ];
530 $expected = [
531 'aTable' => [
532 'columns' => [
533 'fieldA' => [],
534 ],
535 'types' => [
536 'typeA' => [
537 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
538 ],
539 ],
540 'palettes' => [
541 'paletteA' => [
542 'showitem' => 'fieldX, fieldY, dupeA',
543 ],
544 ],
545 ],
546 ];
547 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
548 'aTable',
549 'fieldA',
550 'dupeA, dupeA' // Duplicate
551 );
552 $this->assertEquals($expected, $GLOBALS['TCA']);
553 }
554
555 /**
556 * @test
557 */
558 public function addFieldsToAllPalettesOfFieldDoesNotAddAFieldThatIsPartOfPaletteAlready()
559 {
560 $GLOBALS['TCA'] = [
561 'aTable' => [
562 'columns' => [
563 'fieldA' => [],
564 ],
565 'types' => [
566 'typeA' => [
567 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
568 ],
569 ],
570 'palettes' => [
571 'paletteA' => [
572 'showitem' => 'existingA',
573 ],
574 ],
575 ],
576 ];
577 $expected = [
578 'aTable' => [
579 'columns' => [
580 'fieldA' => [],
581 ],
582 'types' => [
583 'typeA' => [
584 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
585 ],
586 ],
587 'palettes' => [
588 'paletteA' => [
589 'showitem' => 'existingA',
590 ],
591 ],
592 ],
593 ];
594 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
595 'aTable',
596 'fieldA',
597 'existingA'
598 );
599 $this->assertEquals($expected, $GLOBALS['TCA']);
600 }
601
602 /**
603 * @test
604 */
605 public function addFieldsToAllPalettesOfFieldAddsFieldsToMultiplePalettes()
606 {
607 $GLOBALS['TCA'] = [
608 'aTable' => [
609 'columns' => [
610 'fieldA' => [],
611 ],
612 'types' => [
613 'typeA' => [
614 'showitem' => 'fieldA, --palette--;;palette1',
615 ],
616 'typeB' => [
617 'showitem' => 'fieldA;aLabel, --palette--;;palette2',
618 ],
619 ],
620 'palettes' => [
621 'palette1' => [
622 'showitem' => 'fieldX',
623 ],
624 'palette2' => [
625 'showitem' => 'fieldY',
626 ],
627 ],
628 ],
629 ];
630 $expected = [
631 'aTable' => [
632 'columns' => [
633 'fieldA' => [],
634 ],
635 'types' => [
636 'typeA' => [
637 'showitem' => 'fieldA, --palette--;;palette1',
638 ],
639 'typeB' => [
640 'showitem' => 'fieldA;aLabel, --palette--;;palette2',
641 ],
642 ],
643 'palettes' => [
644 'palette1' => [
645 'showitem' => 'fieldX, newA',
646 ],
647 'palette2' => [
648 'showitem' => 'fieldY, newA',
649 ],
650 ],
651 ],
652 ];
653 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
654 'aTable',
655 'fieldA',
656 'newA'
657 );
658 $this->assertEquals($expected, $GLOBALS['TCA']);
659 }
660
661 /**
662 * @test
663 */
664 public function addFieldsToAllPalettesOfFieldAddsMultipleFields()
665 {
666 $GLOBALS['TCA'] = [
667 'aTable' => [
668 'columns' => [
669 'fieldA' => [],
670 ],
671 'types' => [
672 'typeA' => [
673 'showitem' => 'fieldA, --palette--;;palette1',
674 ],
675 ],
676 'palettes' => [
677 'palette1' => [
678 'showitem' => 'fieldX',
679 ],
680 ],
681 ],
682 ];
683 $expected = [
684 'aTable' => [
685 'columns' => [
686 'fieldA' => [],
687 ],
688 'types' => [
689 'typeA' => [
690 'showitem' => 'fieldA, --palette--;;palette1',
691 ],
692 ],
693 'palettes' => [
694 'palette1' => [
695 'showitem' => 'fieldX, newA, newB',
696 ],
697 ],
698 ],
699 ];
700 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
701 'aTable',
702 'fieldA',
703 'newA, newB'
704 );
705 $this->assertEquals($expected, $GLOBALS['TCA']);
706 }
707
708 /**
709 * @test
710 */
711 public function addFieldsToAllPalettesOfFieldAddsBeforeExistingIfRequested()
712 {
713 $GLOBALS['TCA'] = [
714 'aTable' => [
715 'columns' => [
716 'fieldA' => [],
717 ],
718 'types' => [
719 'typeA' => [
720 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
721 ],
722 ],
723 'palettes' => [
724 'paletteA' => [
725 'showitem' => 'existingA, existingB',
726 ],
727 ],
728 ],
729 ];
730 $expected = [
731 'aTable' => [
732 'columns' => [
733 'fieldA' => [],
734 ],
735 'types' => [
736 'typeA' => [
737 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
738 ],
739 ],
740 'palettes' => [
741 'paletteA' => [
742 'showitem' => 'existingA, newA, existingB',
743 ],
744 ],
745 ],
746 ];
747 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
748 'aTable',
749 'fieldA',
750 'newA',
751 'before:existingB'
752 );
753 $this->assertEquals($expected, $GLOBALS['TCA']);
754 }
755
756 /**
757 * @test
758 */
759 public function addFieldsToAllPalettesOfFieldAddsFieldsAtEndIfBeforeRequestedDoesNotExist()
760 {
761 $GLOBALS['TCA'] = [
762 'aTable' => [
763 'columns' => [
764 'fieldA' => [],
765 ],
766 'types' => [
767 'typeA' => [
768 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
769 ],
770 ],
771 'palettes' => [
772 'paletteA' => [
773 'showitem' => 'fieldX, fieldY',
774 ],
775 ],
776 ],
777 ];
778 $expected = [
779 'aTable' => [
780 'columns' => [
781 'fieldA' => [],
782 ],
783 'types' => [
784 'typeA' => [
785 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
786 ],
787 ],
788 'palettes' => [
789 'paletteA' => [
790 'showitem' => 'fieldX, fieldY, newA, newB',
791 ],
792 ],
793 ],
794 ];
795 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
796 'aTable',
797 'fieldA',
798 'newA, newB',
799 'before:notExisting'
800 );
801 $this->assertEquals($expected, $GLOBALS['TCA']);
802 }
803
804 /**
805 * @test
806 */
807 public function addFieldsToAllPalettesOfFieldAddsAfterExistingIfRequested()
808 {
809 $GLOBALS['TCA'] = [
810 'aTable' => [
811 'columns' => [
812 'fieldA' => [],
813 ],
814 'types' => [
815 'typeA' => [
816 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
817 ],
818 ],
819 'palettes' => [
820 'paletteA' => [
821 'showitem' => 'existingA, existingB',
822 ],
823 ],
824 ],
825 ];
826 $expected = [
827 'aTable' => [
828 'columns' => [
829 'fieldA' => [],
830 ],
831 'types' => [
832 'typeA' => [
833 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
834 ],
835 ],
836 'palettes' => [
837 'paletteA' => [
838 'showitem' => 'existingA, newA, existingB',
839 ],
840 ],
841 ],
842 ];
843 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
844 'aTable',
845 'fieldA',
846 'newA',
847 'after:existingA'
848 );
849 $this->assertEquals($expected, $GLOBALS['TCA']);
850 }
851
852 /**
853 * @test
854 */
855 public function addFieldsToAllPalettesOfFieldAddsFieldsAtEndIfAfterRequestedDoesNotExist()
856 {
857 $GLOBALS['TCA'] = [
858 'aTable' => [
859 'columns' => [
860 'fieldA' => [],
861 ],
862 'types' => [
863 'typeA' => [
864 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
865 ],
866 ],
867 'palettes' => [
868 'paletteA' => [
869 'showitem' => 'existingA, existingB',
870 ],
871 ],
872 ],
873 ];
874 $expected = [
875 'aTable' => [
876 'columns' => [
877 'fieldA' => [],
878 ],
879 'types' => [
880 'typeA' => [
881 'showitem' => 'fieldA;labelA, --palette--;;paletteA',
882 ],
883 ],
884 'palettes' => [
885 'paletteA' => [
886 'showitem' => 'existingA, existingB, newA, newB',
887 ],
888 ],
889 ],
890 ];
891 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
892 'aTable',
893 'fieldA',
894 'newA, newB',
895 'after:notExistingA'
896 );
897 $this->assertEquals($expected, $GLOBALS['TCA']);
898 }
899
900 /**
901 * @test
902 */
903 public function addFieldsToAllPalettesOfFieldAddsNewPaletteIfFieldHasNoPaletteYet()
904 {
905 $GLOBALS['TCA'] = [
906 'aTable' => [
907 'columns' => [
908 'fieldA' => [],
909 ],
910 'types' => [
911 'typeA' => [
912 'showitem' => 'fieldA',
913 ],
914 ],
915 ],
916 ];
917 $expected = [
918 'aTable' => [
919 'columns' => [
920 'fieldA' => [],
921 ],
922 'types' => [
923 'typeA' => [
924 'showitem' => 'fieldA, --palette--;;generatedFor-fieldA',
925 ],
926 ],
927 'palettes' => [
928 'generatedFor-fieldA' => [
929 'showitem' => 'newA',
930 ],
931 ],
932 ],
933 ];
934 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
935 'aTable',
936 'fieldA',
937 'newA'
938 );
939 $this->assertEquals($expected, $GLOBALS['TCA']);
940 }
941
942 /**
943 * @test
944 */
945 public function addFieldsToAllPalettesOfFieldAddsNewPaletteIfFieldHasNoPaletteYetAndKeepsExistingLabel()
946 {
947 $GLOBALS['TCA'] = [
948 'aTable' => [
949 'columns' => [
950 'fieldA' => [],
951 ],
952 'types' => [
953 'typeA' => [
954 'showitem' => 'fieldA;labelA',
955 ],
956 ],
957 ],
958 ];
959 $expected = [
960 'aTable' => [
961 'columns' => [
962 'fieldA' => [],
963 ],
964 'types' => [
965 'typeA' => [
966 'showitem' => 'fieldA;labelA, --palette--;;generatedFor-fieldA',
967 ],
968 ],
969 'palettes' => [
970 'generatedFor-fieldA' => [
971 'showitem' => 'newA',
972 ],
973 ],
974 ],
975 ];
976 ExtensionManagementUtility::addFieldsToAllPalettesOfField(
977 'aTable',
978 'fieldA',
979 'newA'
980 );
981 $this->assertEquals($expected, $GLOBALS['TCA']);
982 }
983
984 ///////////////////////////////////////////////////
985 // Tests concerning executePositionedStringInsertion
986 ///////////////////////////////////////////////////
987
988 /**
989 * Data provider for executePositionedStringInsertionTrimsCorrectCharacters
990 * @return array
991 */
992 public function executePositionedStringInsertionTrimsCorrectCharactersDataProvider()
993 {
994 return [
995 'normal characters' => [
996 'tr0',
997 'tr0',
998 ],
999 'newlines' => [
1000 "test\n",
1001 'test',
1002 ],
1003 'newlines with carriage return' => [
1004 "test\r\n",
1005 'test',
1006 ],
1007 'tabs' => [
1008 "test\t",
1009 'test',
1010 ],
1011 'commas' => [
1012 'test,',
1013 'test',
1014 ],
1015 'multiple commas with trailing spaces' => [
1016 "test,,\t, \r\n",
1017 'test',
1018 ],
1019 ];
1020 }
1021
1022 /**
1023 * @test
1024 * @dataProvider executePositionedStringInsertionTrimsCorrectCharactersDataProvider
1025 * @param $string
1026 * @param $expectedResult
1027 */
1028 public function executePositionedStringInsertionTrimsCorrectCharacters($string, $expectedResult)
1029 {
1030 $extensionManagementUtility = $this->getAccessibleMock(ExtensionManagementUtility::class, ['dummy']);
1031 $string = $extensionManagementUtility->_call('executePositionedStringInsertion', $string, '');
1032 $this->assertEquals($expectedResult, $string);
1033 }
1034
1035 /////////////////////////////////////////
1036 // Tests concerning addTcaSelectItem
1037 /////////////////////////////////////////
1038 /**
1039 * @test
1040 */
1041 public function addTcaSelectItemThrowsExceptionIfTableIsNotOfTypeString()
1042 {
1043 $this->expectException(\InvalidArgumentException::class);
1044 $this->expectExceptionCode(1303236963);
1045
1046 ExtensionManagementUtility::addTcaSelectItem([], 'foo', []);
1047 }
1048
1049 /**
1050 * @test
1051 */
1052 public function addTcaSelectItemThrowsExceptionIfFieldIsNotOfTypeString()
1053 {
1054 $this->expectException(\InvalidArgumentException::class);
1055 $this->expectExceptionCode(1303236964);
1056
1057 ExtensionManagementUtility::addTcaSelectItem('foo', [], []);
1058 }
1059
1060 /**
1061 * @test
1062 */
1063 public function addTcaSelectItemThrowsExceptionIfRelativeToFieldIsNotOfTypeString()
1064 {
1065 $this->expectException(\InvalidArgumentException::class);
1066 $this->expectExceptionCode(1303236965);
1067
1068 ExtensionManagementUtility::addTcaSelectItem('foo', 'bar', [], []);
1069 }
1070
1071 /**
1072 * @test
1073 */
1074 public function addTcaSelectItemThrowsExceptionIfRelativePositionIsNotOfTypeString()
1075 {
1076 $this->expectException(\InvalidArgumentException::class);
1077 $this->expectExceptionCode(1303236966);
1078
1079 ExtensionManagementUtility::addTcaSelectItem('foo', 'bar', [], 'foo', []);
1080 }
1081
1082 /**
1083 * @test
1084 */
1085 public function addTcaSelectItemThrowsExceptionIfRelativePositionIsNotOneOfValidKeywords()
1086 {
1087 $this->expectException(\InvalidArgumentException::class);
1088 $this->expectExceptionCode(1303236967);
1089
1090 ExtensionManagementUtility::addTcaSelectItem('foo', 'bar', [], 'foo', 'not allowed keyword');
1091 }
1092
1093 /**
1094 * @test
1095 */
1096 public function addTcaSelectItemThrowsExceptionIfFieldIsNotFoundInTca()
1097 {
1098 $this->expectException(\RuntimeException::class);
1099 $this->expectExceptionCode(1303237468);
1100
1101 $GLOBALS['TCA'] = [];
1102 ExtensionManagementUtility::addTcaSelectItem('foo', 'bar', []);
1103 }
1104
1105 /**
1106 * Data provider for addTcaSelectItemInsertsItemAtSpecifiedPosition
1107 */
1108 public function addTcaSelectItemDataProvider()
1109 {
1110 // Every array splits into:
1111 // - relativeToField
1112 // - relativePosition
1113 // - expectedResultArray
1114 return [
1115 'add at end of array' => [
1116 '',
1117 '',
1118 [
1119 0 => ['firstElement'],
1120 1 => ['matchMe'],
1121 2 => ['thirdElement'],
1122 3 => ['insertedElement']
1123 ]
1124 ],
1125 'replace element' => [
1126 'matchMe',
1127 'replace',
1128 [
1129 0 => ['firstElement'],
1130 1 => ['insertedElement'],
1131 2 => ['thirdElement']
1132 ]
1133 ],
1134 'add element after' => [
1135 'matchMe',
1136 'after',
1137 [
1138 0 => ['firstElement'],
1139 1 => ['matchMe'],
1140 2 => ['insertedElement'],
1141 3 => ['thirdElement']
1142 ]
1143 ],
1144 'add element before' => [
1145 'matchMe',
1146 'before',
1147 [
1148 0 => ['firstElement'],
1149 1 => ['insertedElement'],
1150 2 => ['matchMe'],
1151 3 => ['thirdElement']
1152 ]
1153 ],
1154 'add at end if relative position was not found' => [
1155 'notExistingItem',
1156 'after',
1157 [
1158 0 => ['firstElement'],
1159 1 => ['matchMe'],
1160 2 => ['thirdElement'],
1161 3 => ['insertedElement']
1162 ]
1163 ]
1164 ];
1165 }
1166
1167 /**
1168 * @test
1169 * @dataProvider addTcaSelectItemDataProvider
1170 * @param $relativeToField
1171 * @param $relativePosition
1172 * @param $expectedResultArray
1173 */
1174 public function addTcaSelectItemInsertsItemAtSpecifiedPosition($relativeToField, $relativePosition, $expectedResultArray)
1175 {
1176 $GLOBALS['TCA'] = [
1177 'testTable' => [
1178 'columns' => [
1179 'testField' => [
1180 'config' => [
1181 'items' => [
1182 '0' => ['firstElement'],
1183 '1' => ['matchMe'],
1184 2 => ['thirdElement']
1185 ]
1186 ]
1187 ]
1188 ]
1189 ]
1190 ];
1191 ExtensionManagementUtility::addTcaSelectItem('testTable', 'testField', ['insertedElement'], $relativeToField, $relativePosition);
1192 $this->assertEquals($expectedResultArray, $GLOBALS['TCA']['testTable']['columns']['testField']['config']['items']);
1193 }
1194
1195 /////////////////////////////////////////
1196 // Tests concerning loadExtLocalconf
1197 /////////////////////////////////////////
1198 /**
1199 * @test
1200 */
1201 public function loadExtLocalconfDoesNotReadFromCacheIfCachingIsDenied()
1202 {
1203 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1204 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1205 ->setMethods(['getCache'])
1206 ->getMock();
1207 $mockCacheManager->expects($this->never())->method('getCache');
1208 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1209 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($this->createMockPackageManagerWithMockPackage($this->getUniqueId()));
1210 ExtensionManagementUtility::loadExtLocalconf(false);
1211 }
1212
1213 /**
1214 * @test
1215 */
1216 public function loadExtLocalconfRequiresCacheFileIfExistsAndCachingIsAllowed()
1217 {
1218 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1219 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1220 ->disableOriginalConstructor()
1221 ->getMock();
1222
1223 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1224 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1225 ->setMethods(['getCache'])
1226 ->getMock();
1227 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1228 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1229 $mockCache->expects($this->any())->method('has')->will($this->returnValue(true));
1230 $mockCache->expects($this->once())->method('requireOnce');
1231 ExtensionManagementUtility::loadExtLocalconf(true);
1232 }
1233
1234 /////////////////////////////////////////
1235 // Tests concerning loadSingleExtLocalconfFiles
1236 /////////////////////////////////////////
1237 /**
1238 * @test
1239 */
1240 public function loadSingleExtLocalconfFilesRequiresExtLocalconfFileRegisteredInGlobalTypo3LoadedExt()
1241 {
1242 $this->expectException(\RuntimeException::class);
1243 $this->expectExceptionCode(1340559079);
1244
1245 $extensionName = $this->getUniqueId('foo');
1246 $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1247 $extLocalconfLocation = $packageManager->getPackage($extensionName)->getPackagePath() . 'ext_localconf.php';
1248 file_put_contents($extLocalconfLocation, "<?php\n\nthrow new RuntimeException('', 1340559079);\n\n?>");
1249 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($packageManager);
1250 ExtensionManagementUtilityAccessibleProxy::loadSingleExtLocalconfFiles();
1251 }
1252
1253 /////////////////////////////////////////
1254 // Tests concerning addModule
1255 /////////////////////////////////////////
1256
1257 /**
1258 * Data provider for addModule tests
1259 * @return array
1260 */
1261 public function addModulePositionTestsDataProvider()
1262 {
1263 return [
1264 'can add new main module if none exists' => [
1265 'top',
1266 '',
1267 'newModule'
1268 ],
1269 'can add new sub module if no position specified' => [
1270 '',
1271 'some,modules',
1272 'some,modules,newModule'
1273 ],
1274 'can add new sub module to top of module' => [
1275 'top',
1276 'some,modules',
1277 'newModule,some,modules'
1278 ],
1279 'can add new sub module if bottom of module' => [
1280 'bottom',
1281 'some,modules',
1282 'some,modules,newModule'
1283 ],
1284 'can add new sub module before specified sub module' => [
1285 'before:modules',
1286 'some,modules',
1287 'some,newModule,modules'
1288 ],
1289 'can add new sub module after specified sub module' => [
1290 'after:some',
1291 'some,modules',
1292 'some,newModule,modules'
1293 ],
1294 'can add new sub module at the bottom if specified sub module to add before does not exist' => [
1295 'before:modules',
1296 'some,otherModules',
1297 'some,otherModules,newModule'
1298 ],
1299 'can add new sub module at the bottom if specified sub module to add after does not exist' => [
1300 'after:some',
1301 'someOther,modules',
1302 'someOther,modules,newModule'
1303 ],
1304 ];
1305 }
1306
1307 /**
1308 * @test
1309 * @dataProvider addModulePositionTestsDataProvider
1310 * @param $position
1311 * @param $existing
1312 * @param $expected
1313 */
1314 public function addModuleCanAddModule($position, $existing, $expected)
1315 {
1316 $mainModule = 'foobar';
1317 $subModule = 'newModule';
1318 if ($existing) {
1319 $GLOBALS['TBE_MODULES'][$mainModule] = $existing;
1320 }
1321
1322 ExtensionManagementUtility::addModule($mainModule, $subModule, $position);
1323
1324 $this->assertTrue(isset($GLOBALS['TBE_MODULES'][$mainModule]));
1325 $this->assertEquals($expected, $GLOBALS['TBE_MODULES'][$mainModule]);
1326 }
1327
1328 /////////////////////////////////////////
1329 // Tests concerning createExtLocalconfCacheEntry
1330 /////////////////////////////////////////
1331 /**
1332 * @test
1333 */
1334 public function createExtLocalconfCacheEntryWritesCacheEntryWithContentOfLoadedExtensionExtLocalconf()
1335 {
1336 $extensionName = $this->getUniqueId('foo');
1337 $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1338 $extLocalconfLocation = $packageManager->getPackage($extensionName)->getPackagePath() . 'ext_localconf.php';
1339 $uniqueStringInLocalconf = $this->getUniqueId('foo');
1340 file_put_contents($extLocalconfLocation, "<?php\n\n" . $uniqueStringInLocalconf . "\n\n?>");
1341 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($packageManager);
1342 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1343 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1344 ->disableOriginalConstructor()
1345 ->getMock();
1346
1347 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1348 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1349 ->setMethods(['getCache'])
1350 ->getMock();
1351 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1352 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1353 $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains($uniqueStringInLocalconf), $this->anything());
1354 ExtensionManagementUtilityAccessibleProxy::createExtLocalconfCacheEntry();
1355 }
1356
1357 /**
1358 * @test
1359 */
1360 public function createExtLocalconfCacheEntryWritesCacheEntryWithExtensionContentOnlyIfExtLocalconfExists()
1361 {
1362 $extensionName = $this->getUniqueId('foo');
1363 $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1364 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($packageManager);
1365 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1366 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1367 ->disableOriginalConstructor()
1368 ->getMock();
1369
1370 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1371 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1372 ->setMethods(['getCache'])
1373 ->getMock();
1374 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1375 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1376 $mockCache->expects($this->once())
1377 ->method('set')
1378 ->with($this->anything(), $this->logicalNot($this->stringContains($extensionName)), $this->anything());
1379 ExtensionManagementUtilityAccessibleProxy::createExtLocalconfCacheEntry();
1380 }
1381
1382 /**
1383 * @test
1384 */
1385 public function createExtLocalconfCacheEntryWritesCacheEntryWithNoTags()
1386 {
1387 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1388 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1389 ->disableOriginalConstructor()
1390 ->getMock();
1391
1392 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1393 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1394 ->setMethods(['getCache'])
1395 ->getMock();
1396 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1397 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1398 $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->anything(), $this->equalTo([]));
1399 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($this->createMockPackageManagerWithMockPackage($this->getUniqueId()));
1400 ExtensionManagementUtilityAccessibleProxy::createExtLocalconfCacheEntry();
1401 }
1402
1403 /////////////////////////////////////////
1404 // Tests concerning getExtLocalconfCacheIdentifier
1405 /////////////////////////////////////////
1406 /**
1407 * @test
1408 */
1409 public function getExtLocalconfCacheIdentifierCreatesSha1WithFourtyCharactersAndPrefix()
1410 {
1411 $prefix = 'ext_localconf_';
1412 $identifier = ExtensionManagementUtilityAccessibleProxy::getExtLocalconfCacheIdentifier();
1413 $this->assertStringStartsWith($prefix, $identifier);
1414 $sha1 = str_replace($prefix, '', $identifier);
1415 $this->assertEquals(40, strlen($sha1));
1416 }
1417
1418 /////////////////////////////////////////
1419 // Tests concerning loadBaseTca
1420 /////////////////////////////////////////
1421
1422 /**
1423 * @test
1424 */
1425 public function loadBaseTcaDoesNotReadFromCacheIfCachingIsDenied()
1426 {
1427 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1428 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1429 ->setMethods(['getCache'])
1430 ->getMock();
1431 $mockCacheManager->expects($this->never())->method('getCache');
1432 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1433 ExtensionManagementUtilityAccessibleProxy::loadBaseTca(false);
1434 }
1435
1436 /**
1437 * @test
1438 */
1439 public function loadBaseTcaRequiresCacheFileIfExistsAndCachingIsAllowed()
1440 {
1441 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1442 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1443 ->disableOriginalConstructor()
1444 ->getMock();
1445
1446 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1447 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1448 ->setMethods(['getCache'])
1449 ->getMock();
1450 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1451 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1452 $mockCache->expects($this->once())->method('requireOnce')->willReturn(['tca' => [], 'categoryRegistry' => \serialize(CategoryRegistry::getInstance())]);
1453 ExtensionManagementUtilityAccessibleProxy::loadBaseTca(true);
1454 }
1455
1456 /**
1457 * @test
1458 */
1459 public function loadBaseTcaCreatesCacheFileWithContentOfAnExtensionsConfigurationTcaPhpFile()
1460 {
1461 $extensionName = $this->getUniqueId('test_baseTca_');
1462 $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1463 $packagePath = $packageManager->getPackage($extensionName)->getPackagePath();
1464 GeneralUtility::mkdir($packagePath);
1465 GeneralUtility::mkdir($packagePath . 'Configuration/');
1466 GeneralUtility::mkdir($packagePath . 'Configuration/TCA/');
1467 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($packageManager);
1468 ExtensionManagementUtility::setPackageManager($packageManager);
1469 $uniqueTableName = $this->getUniqueId('table_name_');
1470 $uniqueStringInTableConfiguration = $this->getUniqueId('table_configuration_');
1471 $tableConfiguration = '<?php return array(\'foo\' => \'' . $uniqueStringInTableConfiguration . '\'); ?>';
1472 file_put_contents($packagePath . 'Configuration/TCA/' . $uniqueTableName . '.php', $tableConfiguration);
1473 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1474 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1475 ->disableOriginalConstructor()
1476 ->getMock();
1477
1478 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1479 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1480 ->setMethods(['getCache'])
1481 ->getMock();
1482 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1483 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1484 $mockCache->expects($this->once())->method('requireOnce')->will($this->returnValue(false));
1485 $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains($uniqueStringInTableConfiguration), $this->anything());
1486 ExtensionManagementUtility::loadBaseTca(true);
1487 }
1488
1489 /**
1490 * @test
1491 */
1492 public function loadBaseTcaWritesCacheEntryWithNoTags()
1493 {
1494 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1495 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1496 ->disableOriginalConstructor()
1497 ->getMock();
1498
1499 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1500 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1501 ->setMethods(['getCache'])
1502 ->getMock();
1503 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1504 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1505 $mockCache->expects($this->once())->method('requireOnce')->will($this->returnValue(false));
1506 $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->anything(), $this->equalTo([]));
1507 ExtensionManagementUtilityAccessibleProxy::loadBaseTca();
1508 }
1509
1510 /////////////////////////////////////////
1511 // Tests concerning getBaseTcaCacheIdentifier
1512 /////////////////////////////////////////
1513
1514 /**
1515 * @test
1516 */
1517 public function getBaseTcaCacheIdentifierCreatesSha1WithFourtyCharactersAndPrefix()
1518 {
1519 $prefix = 'tca_base_';
1520 $identifier = ExtensionManagementUtilityAccessibleProxy::getBaseTcaCacheIdentifier();
1521 $this->assertStringStartsWith($prefix, $identifier);
1522 $sha1 = str_replace($prefix, '', $identifier);
1523 $this->assertEquals(40, strlen($sha1));
1524 }
1525
1526 /////////////////////////////////////////
1527 // Tests concerning loadExtTables
1528 /////////////////////////////////////////
1529 /**
1530 * @test
1531 */
1532 public function loadExtTablesDoesNotReadFromCacheIfCachingIsDenied()
1533 {
1534 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1535 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1536 ->setMethods(['getCache'])
1537 ->getMock();
1538 $mockCacheManager->expects($this->never())->method('getCache');
1539 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1540 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($this->createMockPackageManagerWithMockPackage($this->getUniqueId()));
1541 ExtensionManagementUtility::loadExtLocalconf(false);
1542 }
1543
1544 /**
1545 * @test
1546 */
1547 public function loadExtTablesRequiresCacheFileIfExistsAndCachingIsAllowed()
1548 {
1549 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1550 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1551 ->disableOriginalConstructor()
1552 ->getMock();
1553
1554 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1555 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1556 ->setMethods(['getCache'])
1557 ->getMock();
1558 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1559 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1560 $mockCache->expects($this->any())->method('has')->will($this->returnValue(true));
1561 $mockCache->expects($this->once())->method('requireOnce');
1562 // Reset the internal cache access tracking variable of extMgm
1563 // This method is only in the ProxyClass!
1564 ExtensionManagementUtilityAccessibleProxy::resetExtTablesWasReadFromCacheOnceBoolean();
1565 ExtensionManagementUtility::loadExtTables(true);
1566 }
1567
1568 /////////////////////////////////////////
1569 // Tests concerning createExtTablesCacheEntry
1570 /////////////////////////////////////////
1571 /**
1572 * @test
1573 */
1574 public function createExtTablesCacheEntryWritesCacheEntryWithContentOfLoadedExtensionExtTables()
1575 {
1576 $extensionName = $this->getUniqueId('foo');
1577 $extTablesLocation = Environment::getVarPath() . '/tests/' . $this->getUniqueId('test_ext_tables') . '.php';
1578 $this->testFilesToDelete[] = $extTablesLocation;
1579 $uniqueStringInTables = $this->getUniqueId('foo');
1580 file_put_contents($extTablesLocation, "<?php\n\n$uniqueStringInTables\n\n?>");
1581 $GLOBALS['TYPO3_LOADED_EXT'] = [
1582 $extensionName => [
1583 'ext_tables.php' => $extTablesLocation
1584 ]
1585 ];
1586 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1587 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1588 ->disableOriginalConstructor()
1589 ->getMock();
1590
1591 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1592 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1593 ->setMethods(['getCache'])
1594 ->getMock();
1595 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1596 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1597 $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->stringContains($uniqueStringInTables), $this->anything());
1598 ExtensionManagementUtilityAccessibleProxy::createExtTablesCacheEntry();
1599 }
1600
1601 /**
1602 * @test
1603 */
1604 public function createExtTablesCacheEntryWritesCacheEntryWithExtensionContentOnlyIfExtTablesExists()
1605 {
1606 $extensionName = $this->getUniqueId('foo');
1607 $GLOBALS['TYPO3_LOADED_EXT'] = [
1608 $extensionName => [],
1609 ];
1610 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1611 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1612 ->disableOriginalConstructor()
1613 ->getMock();
1614
1615 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1616 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1617 ->setMethods(['getCache'])
1618 ->getMock();
1619 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1620 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1621 $mockCache->expects($this->once())
1622 ->method('set')
1623 ->with($this->anything(), $this->logicalNot($this->stringContains($extensionName)), $this->anything());
1624 ExtensionManagementUtilityAccessibleProxy::createExtTablesCacheEntry();
1625 }
1626
1627 /**
1628 * @test
1629 */
1630 public function createExtTablesCacheEntryWritesCacheEntryWithNoTags()
1631 {
1632 $mockCache = $this->getMockBuilder(PhpFrontend::class)
1633 ->setMethods(['getIdentifier', 'set', 'get', 'getByTag', 'has', 'remove', 'flush', 'flushByTag', 'requireOnce'])
1634 ->disableOriginalConstructor()
1635 ->getMock();
1636
1637 /** @var CacheManager|\PHPUnit_Framework_MockObject_MockObject $mockCacheManager */
1638 $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1639 ->setMethods(['getCache'])
1640 ->getMock();
1641 $mockCacheManager->expects($this->any())->method('getCache')->will($this->returnValue($mockCache));
1642 ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1643 $mockCache->expects($this->once())->method('set')->with($this->anything(), $this->anything(), $this->equalTo([]));
1644 $GLOBALS['TYPO3_LOADED_EXT'] = new LoadedExtensionsArray($this->createMockPackageManagerWithMockPackage($this->getUniqueId()));
1645 ExtensionManagementUtilityAccessibleProxy::createExtTablesCacheEntry();
1646 }
1647
1648 /////////////////////////////////////////
1649 // Tests concerning getExtTablesCacheIdentifier
1650 /////////////////////////////////////////
1651 /**
1652 * @test
1653 */
1654 public function getExtTablesCacheIdentifierCreatesSha1WithFourtyCharactersAndPrefix()
1655 {
1656 $prefix = 'ext_tables_';
1657 $identifier = ExtensionManagementUtilityAccessibleProxy::getExtTablesCacheIdentifier();
1658 $this->assertStringStartsWith($prefix, $identifier);
1659 $sha1 = str_replace($prefix, '', $identifier);
1660 $this->assertEquals(40, strlen($sha1));
1661 }
1662
1663 /////////////////////////////////////////
1664 // Tests concerning getExtensionVersion
1665 /////////////////////////////////////////
1666 /**
1667 * Data provider for negative getExtensionVersion() tests.
1668 *
1669 * @return array
1670 */
1671 public function getExtensionVersionFaultyDataProvider()
1672 {
1673 return [
1674 [''],
1675 [0],
1676 [new \stdClass()],
1677 [true]
1678 ];
1679 }
1680
1681 /**
1682 * @test
1683 * @dataProvider getExtensionVersionFaultyDataProvider
1684 * @param $key
1685 * @throws \TYPO3\CMS\Core\Package\Exception
1686 */
1687 public function getExtensionVersionForFaultyExtensionKeyThrowsException($key)
1688 {
1689 $this->expectException(\InvalidArgumentException::class);
1690 $this->expectExceptionCode(1294586096);
1691
1692 ExtensionManagementUtility::getExtensionVersion($key);
1693 }
1694
1695 /**
1696 * @test
1697 */
1698 public function getExtensionVersionForNotLoadedExtensionReturnsEmptyString()
1699 {
1700 ExtensionManagementUtility::clearExtensionKeyMap();
1701 $uniqueSuffix = $this->getUniqueId('test');
1702 $extensionKey = 'unloadedextension' . $uniqueSuffix;
1703 $this->assertEquals('', ExtensionManagementUtility::getExtensionVersion($extensionKey));
1704 }
1705
1706 /**
1707 * @test
1708 */
1709 public function getExtensionVersionForLoadedExtensionReturnsExtensionVersion()
1710 {
1711 ExtensionManagementUtility::clearExtensionKeyMap();
1712 $uniqueSuffix = $this->getUniqueId('test');
1713 $extensionKey = 'unloadedextension' . $uniqueSuffix;
1714 $packageMetaData = $this->getMockBuilder(MetaData::class)
1715 ->setMethods(['getVersion'])
1716 ->setConstructorArgs([$extensionKey])
1717 ->getMock();
1718 $packageMetaData->expects($this->any())->method('getVersion')->will($this->returnValue('1.2.3'));
1719 $packageManager = $this->createMockPackageManagerWithMockPackage($extensionKey, ['getPackagePath', 'getPackageKey', 'getPackageMetaData']);
1720 /** @var \PHPUnit_Framework_MockObject_MockObject $package */
1721 $package = $packageManager->getPackage($extensionKey);
1722 $package->expects($this->any())
1723 ->method('getPackageMetaData')
1724 ->will($this->returnValue($packageMetaData));
1725 ExtensionManagementUtility::setPackageManager($packageManager);
1726 $this->assertEquals('1.2.3', ExtensionManagementUtility::getExtensionVersion($extensionKey));
1727 }
1728
1729 /////////////////////////////////////////
1730 // Tests concerning loadExtension
1731 /////////////////////////////////////////
1732 /**
1733 * @test
1734 */
1735 public function loadExtensionThrowsExceptionIfExtensionIsLoaded()
1736 {
1737 $this->expectException(\RuntimeException::class);
1738 $this->expectExceptionCode(1342345486);
1739
1740 $extensionKey = $this->getUniqueId('test');
1741 $packageManager = $this->createMockPackageManagerWithMockPackage($extensionKey);
1742 ExtensionManagementUtility::setPackageManager($packageManager);
1743 ExtensionManagementUtility::loadExtension($extensionKey);
1744 }
1745
1746 /////////////////////////////////////////
1747 // Tests concerning unloadExtension
1748 /////////////////////////////////////////
1749 /**
1750 * @test
1751 */
1752 public function unloadExtensionThrowsExceptionIfExtensionIsNotLoaded()
1753 {
1754 $this->expectException(\RuntimeException::class);
1755 $this->expectExceptionCode(1342345487);
1756
1757 $packageName = $this->getUniqueId('foo');
1758 /** @var PackageManager|\PHPUnit_Framework_MockObject_MockObject $packageManager */
1759 $packageManager = $this->getMockBuilder(PackageManager::class)
1760 ->setMethods(['isPackageActive'])
1761 ->disableOriginalConstructor()
1762 ->getMock();
1763 $packageManager->expects($this->once())
1764 ->method('isPackageActive')
1765 ->with($this->equalTo($packageName))
1766 ->will($this->returnValue(false));
1767 ExtensionManagementUtility::setPackageManager($packageManager);
1768 ExtensionManagementUtility::unloadExtension($packageName);
1769 }
1770
1771 /**
1772 * @test
1773 */
1774 public function unloadExtensionCallsPackageManagerToDeactivatePackage()
1775 {
1776 $packageName = $this->getUniqueId('foo');
1777 /** @var PackageManager|\PHPUnit_Framework_MockObject_MockObject $packageManager */
1778 $packageManager = $this->getMockBuilder(PackageManager::class)
1779 ->setMethods(['isPackageActive', 'deactivatePackage'])
1780 ->disableOriginalConstructor()
1781 ->getMock();
1782 $packageManager->expects($this->any())
1783 ->method('isPackageActive')
1784 ->will($this->returnValue(true));
1785 $packageManager->expects($this->once())
1786 ->method('deactivatePackage')
1787 ->with($packageName);
1788 ExtensionManagementUtility::setPackageManager($packageManager);
1789 ExtensionManagementUtility::unloadExtension($packageName);
1790 }
1791
1792 /////////////////////////////////////////
1793 // Tests concerning makeCategorizable
1794 /////////////////////////////////////////
1795 /**
1796 * @test
1797 */
1798 public function doesMakeCategorizableCallsTheCategoryRegistryWithDefaultFieldName()
1799 {
1800 $extensionKey = $this->getUniqueId('extension');
1801 $tableName = $this->getUniqueId('table');
1802
1803 /** @var CategoryRegistry|\PHPUnit_Framework_MockObject_MockObject $registryMock */
1804 $registryMock = $this->getMockBuilder(CategoryRegistry::class)->getMock();
1805 $registryMock->expects($this->once())->method('add')->with($extensionKey, $tableName, 'categories', []);
1806 GeneralUtility::setSingletonInstance(CategoryRegistry::class, $registryMock);
1807 ExtensionManagementUtility::makeCategorizable($extensionKey, $tableName);
1808 }
1809
1810 /**
1811 * @test
1812 */
1813 public function doesMakeCategorizableCallsTheCategoryRegistryWithFieldName()
1814 {
1815 $extensionKey = $this->getUniqueId('extension');
1816 $tableName = $this->getUniqueId('table');
1817 $fieldName = $this->getUniqueId('field');
1818
1819 /** @var CategoryRegistry|\PHPUnit_Framework_MockObject_MockObject $registryMock */
1820 $registryMock = $this->getMockBuilder(CategoryRegistry::class)->getMock();
1821 $registryMock->expects($this->once())->method('add')->with($extensionKey, $tableName, $fieldName, []);
1822 GeneralUtility::setSingletonInstance(CategoryRegistry::class, $registryMock);
1823 ExtensionManagementUtility::makeCategorizable($extensionKey, $tableName, $fieldName);
1824 }
1825
1826 ///////////////////////////////
1827 // Tests concerning addPlugin
1828 ///////////////////////////////
1829
1830 /**
1831 * @test
1832 */
1833 public function addPluginSetsTcaCorrectlyForGivenExtKeyAsParameter()
1834 {
1835 $extKey = 'indexed_search';
1836 $GLOBALS['TYPO3_LOADED_EXT'] = [];
1837 $GLOBALS['TYPO3_LOADED_EXT'][$extKey]['ext_icon'] = 'foo.gif';
1838 $expectedTCA = [
1839 [
1840 'label',
1841 $extKey,
1842 'EXT:' . $extKey . '/foo.gif'
1843 ]
1844 ];
1845 $GLOBALS['TCA']['tt_content']['columns']['list_type']['config']['items'] = [];
1846 ExtensionManagementUtility::addPlugin(['label', $extKey], 'list_type', $extKey);
1847 $this->assertEquals($expectedTCA, $GLOBALS['TCA']['tt_content']['columns']['list_type']['config']['items']);
1848 }
1849
1850 /**
1851 * @test
1852 */
1853 public function addPluginThrowsExceptionForMissingExtkey()
1854 {
1855 $this->expectException(\InvalidArgumentException::class);
1856 $this->expectExceptionCode(1404068038);
1857
1858 ExtensionManagementUtility::addPlugin('test');
1859 }
1860 }