‪TYPO3CMS  11.5
ExtensionManagementUtilityTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use PHPUnit\Framework\MockObject\MockObject;
21 use Prophecy\Argument;
22 use Prophecy\PhpUnit\ProphecyTrait;
23 use Psr\EventDispatcher\EventDispatcherInterface;
31 use TYPO3\CMS\Core\Package\PackageManager;
36 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
37 
41 class ExtensionManagementUtilityTest extends UnitTestCase
42 {
43  use ProphecyTrait;
44 
48  protected $resetSingletonInstances = true;
49 
50  protected ?PackageManager $backUpPackageManager;
51 
55  protected function setUp(): void
56  {
57  parent::setUp();
59  }
60 
64  protected function tearDown(): void
65  {
68  parent::tearDown();
69  }
70 
76  protected function createMockPackageManagerWithMockPackage(string $packageKey, array $packageMethods = ['getPackagePath', 'getPackageKey'])
77  {
78  $packagePath = ‪Environment::getVarPath() . '/tests/' . $packageKey . '/';
79  ‪GeneralUtility::mkdir_deep($packagePath);
80  $this->testFilesToDelete[] = $packagePath;
81  $package = $this->getMockBuilder(Package::class)
82  ->disableOriginalConstructor()
83  ->onlyMethods($packageMethods)
84  ->getMock();
85  $packageManager = $this->getMockBuilder(PackageManager::class)
86  ->onlyMethods(['isPackageActive', 'getPackage', 'getActivePackages'])
87  ->disableOriginalConstructor()
88  ->getMock();
89  $package
90  ->method('getPackagePath')
91  ->willReturn($packagePath);
92  $package
93  ->method('getPackageKey')
94  ->willReturn($packageKey);
95  $packageManager
96  ->method('isPackageActive')
97  ->willReturnMap([
98  [null, false],
99  [$packageKey, true],
100  ]);
101  $packageManager
102  ->method('getPackage')
103  ->with(self::equalTo($packageKey))
104  ->willReturn($package);
105  $packageManager
106  ->method('getActivePackages')
107  ->willReturn([$packageKey => $package]);
108  return $packageManager;
109  }
110 
112  // Tests concerning isLoaded
114 
117  public function isLoadedReturnsFalseIfExtensionIsNotLoaded(): void
118  {
120  }
121 
123  // Tests concerning extPath
125 
128  public function extPathThrowsExceptionIfExtensionIsNotLoaded(): void
129  {
130  $this->expectException(\BadFunctionCallException::class);
131  $this->expectExceptionCode(1365429656);
132 
133  $packageName = ‪StringUtility::getUniqueId('foo');
134  $packageManager = $this->getMockBuilder(PackageManager::class)
135  ->onlyMethods(['isPackageActive'])
136  ->disableOriginalConstructor()
137  ->getMock();
138  $packageManager->expects(self::once())
139  ->method('isPackageActive')
140  ->with(self::equalTo($packageName))
141  ->willReturn(false);
144  }
145 
149  public function extPathAppendsScriptNameToPath(): void
150  {
151  $package = $this->getMockBuilder(Package::class)
152  ->disableOriginalConstructor()
153  ->onlyMethods(['getPackagePath'])
154  ->getMock();
155  $packageManager = $this->getMockBuilder(PackageManager::class)
156  ->onlyMethods(['isPackageActive', 'getPackage'])
157  ->disableOriginalConstructor()
158  ->getMock();
159  $package->expects(self::once())
160  ->method('getPackagePath')
161  ->willReturn(‪Environment::getPublicPath() . '/foo/');
162  $packageManager->expects(self::once())
163  ->method('isPackageActive')
164  ->with(self::equalTo('foo'))
165  ->willReturn(true);
166  $packageManager->expects(self::once())
167  ->method('getPackage')
168  ->with('foo')
169  ->willReturn($package);
171  self::assertSame(‪Environment::getPublicPath() . '/foo/bar.txt', ‪ExtensionManagementUtility::extPath('foo', 'bar.txt'));
172  }
173 
175  // Utility functions
177 
183  private function generateTCAForTable($table): array
184  {
185  ‪$tca = [];
186  ‪$tca[$table] = [];
187  ‪$tca[$table]['columns'] = [
188  'fieldA' => [],
189  'fieldC' => [],
190  ];
191  ‪$tca[$table]['types'] = [
192  'typeA' => ['showitem' => 'fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1'],
193  'typeB' => ['showitem' => 'fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1'],
194  'typeC' => ['showitem' => 'fieldC;;paletteD'],
195  ];
196  ‪$tca[$table]['palettes'] = [
197  'paletteA' => ['showitem' => 'fieldX, fieldX1, fieldY'],
198  'paletteB' => ['showitem' => 'fieldX, fieldX1, fieldY'],
199  'paletteC' => ['showitem' => 'fieldX, fieldX1, fieldY'],
200  'paletteD' => ['showitem' => 'fieldX, fieldX1, fieldY'],
201  ];
202  return ‪$tca;
203  }
204 
210  public function extensionKeyDataProvider(): array
211  {
212  return [
213  'Without underscores' => [
214  'testkey',
215  'tx_testkey',
216  ],
217  'With underscores' => [
218  'this_is_a_test_extension',
219  'tx_thisisatestextension',
220  ],
221  'With user prefix and without underscores' => [
222  'user_testkey',
223  'user_testkey',
224  ],
225  'With user prefix and with underscores' => [
226  'user_test_key',
227  'user_testkey',
228  ],
229  ];
230  }
231 
238  public function getClassNamePrefixForExtensionKey(string $extensionName, string $expectedPrefix): void
239  {
240  self::assertSame($expectedPrefix, ‪ExtensionManagementUtility::getCN($extensionName));
241  }
242 
244  // Tests concerning addToAllTCAtypes
246 
252  public function canAddFieldsToAllTCATypesBeforeExistingOnes(): void
253  {
254  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
255  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
256  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'before:fieldD');
257  // Checking typeA:
258  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, newA, newB, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
259  // Checking typeB:
260  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, newA, newB, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
261  }
262 
269  public function canAddFieldsToAllTCATypesAfterExistingOnes(): void
270  {
271  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
272  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
273  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'after:fieldC');
274  // Checking typeA:
275  self::assertEquals('fieldA, fieldB, fieldC;labelC, newA, newB, --palette--;;paletteC, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
276  // Checking typeB:
277  self::assertEquals('fieldA, fieldB, fieldC;labelC, newA, newB, --palette--;;paletteC, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
278  }
279 
286  public function canAddFieldsToAllTCATypesRespectsPalettes(): void
287  {
288  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
289  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
290  ‪$GLOBALS['TCA'][$table]['types']['typeD'] = ['showitem' => 'fieldY, --palette--;;standard, fieldZ'];
291  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'after:--palette--;;standard');
292  // Checking typeD:
293  self::assertEquals('fieldY, --palette--;;standard, newA, newB, fieldA, fieldZ', ‪$GLOBALS['TCA'][$table]['types']['typeD']['showitem']);
294  }
295 
302  public function canAddFieldsToAllTCATypesRespectsPositionFieldInPalette(): void
303  {
304  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
305  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
306  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', '', 'after:fieldX1');
307  // Checking typeA:
308  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, newA, newB, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
309  }
310 
317  public function canAddFieldsToTCATypeBeforeExistingOnes(): void
318  {
319  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
320  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
321  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', 'typeA', 'before:fieldD');
322  // Checking typeA:
323  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, newA, newB, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
324  // Checking typeB:
325  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
326  }
327 
334  public function canAddFieldsToTCATypeAfterExistingOnes(): void
335  {
336  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
337  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
338  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'newA, newA, newB, fieldA', 'typeA', 'after:fieldC');
339  // Checking typeA:
340  self::assertEquals('fieldA, fieldB, fieldC;labelC, newA, newB, --palette--;;paletteC, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
341  // Checking typeB:
342  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
343  }
344 
348  public function canAddFieldWithPartOfAlreadyExistingFieldname(): void
349  {
350  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
351  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
352  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'field', 'typeA', 'after:fieldD1');
353 
354  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1, field', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
355  }
356 
363  public function canAddFieldsToTCATypeAndReplaceExistingOnes(): void
364  {
365  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
366  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
367  $typesBefore = ‪$GLOBALS['TCA'][$table]['types'];
368  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'fieldZ', '', 'replace:fieldX');
369  self::assertEquals($typesBefore, ‪$GLOBALS['TCA'][$table]['types'], 'It\'s wrong that the "types" array changes here - the replaced field is only on palettes');
370  // unchanged because the palette is not used
371  self::assertEquals('fieldX, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
372  self::assertEquals('fieldX, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteB']['showitem']);
373  // changed
374  self::assertEquals('fieldZ, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteC']['showitem']);
375  self::assertEquals('fieldZ, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteD']['showitem']);
376  }
377 
381  public function addToAllTCAtypesReplacesExistingOnes(): void
382  {
383  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
384  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
385  $typesBefore = ‪$GLOBALS['TCA'][$table]['types'];
386  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'fieldX, --palette--;;foo', '', 'replace:fieldX');
387  self::assertEquals($typesBefore, ‪$GLOBALS['TCA'][$table]['types'], 'It\'s wrong that the "types" array changes here - the replaced field is only on palettes');
388  // unchanged because the palette is not used
389  self::assertEquals('fieldX, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
390  self::assertEquals('fieldX, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteB']['showitem']);
391  // changed
392  self::assertEquals('fieldX, --palette--;;foo, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteC']['showitem']);
393  self::assertEquals('fieldX, --palette--;;foo, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteD']['showitem']);
394  }
395 
399  public function addToAllTCAtypesAddsToPaletteIdentifier(): void
400  {
401  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
402  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
403  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'fieldX, --palette--;;newpalette', '', 'after:palette:paletteC');
404  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldX, --palette--;;newpalette, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
405  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldX, --palette--;;newpalette, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeB']['showitem']);
406  }
407 
411  public function addToAllTCAtypesAddsBeforeDiv(): void
412  {
413  $showitemDiv = '--div--;LLL:EXT:my_ext/Resources/Private/Language/locallang.xlf:foobar';
414  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
415  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
416  ‪$GLOBALS['TCA'][$table]['types']['typeD']['showitem'] = $showitemDiv . ', ' . ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem'];
417 
418  ‪ExtensionManagementUtility::addToAllTCAtypes($table, 'fieldX', '', 'before:' . $showitemDiv);
419  self::assertEquals('fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1, fieldX', ‪$GLOBALS['TCA'][$table]['types']['typeA']['showitem']);
420  self::assertEquals('fieldX, ' . $showitemDiv . ', fieldA, fieldB, fieldC;labelC, --palette--;;paletteC, fieldC1, fieldD, fieldD1', ‪$GLOBALS['TCA'][$table]['types']['typeD']['showitem']);
421  }
422 
429  public function canAddFieldsToPaletteBeforeExistingOnes(): void
430  {
431  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
432  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
433  ‪ExtensionManagementUtility::addFieldsToPalette($table, 'paletteA', 'newA, newA, newB, fieldX', 'before:fieldY');
434  self::assertEquals('fieldX, fieldX1, newA, newB, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
435  }
436 
443  public function canAddFieldsToPaletteAfterExistingOnes(): void
444  {
445  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
446  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
447  ‪ExtensionManagementUtility::addFieldsToPalette($table, 'paletteA', 'newA, newA, newB, fieldX', 'after:fieldX');
448  self::assertEquals('fieldX, newA, newB, fieldX1, fieldY', ‪$GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
449  }
450 
457  public function canAddFieldsToPaletteAfterNotExistingOnes(): void
458  {
459  $table = ‪StringUtility::getUniqueId('tx_coretest_table');
460  ‪$GLOBALS['TCA'] = $this->generateTCAForTable($table);
461  ‪ExtensionManagementUtility::addFieldsToPalette($table, 'paletteA', 'newA, newA, newB, fieldX', 'after:' . ‪StringUtility::getUniqueId('notExisting'));
462  self::assertEquals('fieldX, fieldX1, fieldY, newA, newB', ‪$GLOBALS['TCA'][$table]['palettes']['paletteA']['showitem']);
463  }
464 
468  public function removeDuplicatesForInsertionRemovesDuplicatesDataProvider(): array
469  {
470  return [
471  'Simple' => [
472  'field_b, field_d, field_c',
473  'field_a, field_b, field_c',
474  'field_d',
475  ],
476  'with linebreaks' => [
477  'field_b, --linebreak--, field_d, --linebreak--, field_c',
478  'field_a, field_b, field_c',
479  '--linebreak--, field_d, --linebreak--',
480  ],
481  'with linebreaks in list and insertion list' => [
482  'field_b, --linebreak--, field_d, --linebreak--, field_c',
483  'field_a, field_b, --linebreak--, field_c',
484  '--linebreak--, field_d, --linebreak--',
485  ],
486  ];
487  }
488 
493  public function removeDuplicatesForInsertionRemovesDuplicates(string $insertionList, string $list, string $expected): void
494  {
496  self::assertSame($expected, $result);
497  }
498 
500  // Tests concerning addFieldsToAllPalettesOfField
502 
506  public function addFieldsToAllPalettesOfFieldDoesNotAddAnythingIfFieldIsNotRegisteredInColumns(): void
507  {
508  ‪$GLOBALS['TCA'] = [
509  'aTable' => [
510  'types' => [
511  'typeA' => [
512  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
513  ],
514  ],
515  'palettes' => [
516  'paletteA' => [
517  'showitem' => 'fieldX, fieldY',
518  ],
519  ],
520  ],
521  ];
522  $expected = ‪$GLOBALS['TCA'];
524  'aTable',
525  'fieldA',
526  'newA'
527  );
528  self::assertEquals($expected, ‪$GLOBALS['TCA']);
529  }
530 
534  public function addFieldsToAllPalettesOfFieldAddsFieldsToPaletteAndSuppressesDuplicates(): void
535  {
536  ‪$GLOBALS['TCA'] = [
537  'aTable' => [
538  'columns' => [
539  'fieldA' => [],
540  ],
541  'types' => [
542  'typeA' => [
543  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
544  ],
545  ],
546  'palettes' => [
547  'paletteA' => [
548  'showitem' => 'fieldX, fieldY',
549  ],
550  ],
551  ],
552  ];
553  $expected = [
554  'aTable' => [
555  'columns' => [
556  'fieldA' => [],
557  ],
558  'types' => [
559  'typeA' => [
560  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
561  ],
562  ],
563  'palettes' => [
564  'paletteA' => [
565  'showitem' => 'fieldX, fieldY, dupeA',
566  ],
567  ],
568  ],
569  ];
571  'aTable',
572  'fieldA',
573  'dupeA, dupeA' // Duplicate
574  );
575  self::assertEquals($expected, ‪$GLOBALS['TCA']);
576  }
577 
581  public function addFieldsToAllPalettesOfFieldDoesNotAddAFieldThatIsPartOfPaletteAlready(): void
582  {
583  ‪$GLOBALS['TCA'] = [
584  'aTable' => [
585  'columns' => [
586  'fieldA' => [],
587  ],
588  'types' => [
589  'typeA' => [
590  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
591  ],
592  ],
593  'palettes' => [
594  'paletteA' => [
595  'showitem' => 'existingA',
596  ],
597  ],
598  ],
599  ];
600  $expected = [
601  'aTable' => [
602  'columns' => [
603  'fieldA' => [],
604  ],
605  'types' => [
606  'typeA' => [
607  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
608  ],
609  ],
610  'palettes' => [
611  'paletteA' => [
612  'showitem' => 'existingA',
613  ],
614  ],
615  ],
616  ];
618  'aTable',
619  'fieldA',
620  'existingA'
621  );
622  self::assertEquals($expected, ‪$GLOBALS['TCA']);
623  }
624 
628  public function addFieldsToAllPalettesOfFieldAddsFieldsToMultiplePalettes(): void
629  {
630  ‪$GLOBALS['TCA'] = [
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',
646  ],
647  'palette2' => [
648  'showitem' => 'fieldY',
649  ],
650  ],
651  ],
652  ];
653  $expected = [
654  'aTable' => [
655  'columns' => [
656  'fieldA' => [],
657  ],
658  'types' => [
659  'typeA' => [
660  'showitem' => 'fieldA, --palette--;;palette1',
661  ],
662  'typeB' => [
663  'showitem' => 'fieldA;aLabel, --palette--;;palette2',
664  ],
665  ],
666  'palettes' => [
667  'palette1' => [
668  'showitem' => 'fieldX, newA',
669  ],
670  'palette2' => [
671  'showitem' => 'fieldY, newA',
672  ],
673  ],
674  ],
675  ];
677  'aTable',
678  'fieldA',
679  'newA'
680  );
681  self::assertEquals($expected, ‪$GLOBALS['TCA']);
682  }
683 
687  public function addFieldsToAllPalettesOfFieldAddsMultipleFields(): void
688  {
689  ‪$GLOBALS['TCA'] = [
690  'aTable' => [
691  'columns' => [
692  'fieldA' => [],
693  ],
694  'types' => [
695  'typeA' => [
696  'showitem' => 'fieldA, --palette--;;palette1',
697  ],
698  ],
699  'palettes' => [
700  'palette1' => [
701  'showitem' => 'fieldX',
702  ],
703  ],
704  ],
705  ];
706  $expected = [
707  'aTable' => [
708  'columns' => [
709  'fieldA' => [],
710  ],
711  'types' => [
712  'typeA' => [
713  'showitem' => 'fieldA, --palette--;;palette1',
714  ],
715  ],
716  'palettes' => [
717  'palette1' => [
718  'showitem' => 'fieldX, newA, newB',
719  ],
720  ],
721  ],
722  ];
724  'aTable',
725  'fieldA',
726  'newA, newB'
727  );
728  self::assertEquals($expected, ‪$GLOBALS['TCA']);
729  }
730 
734  public function addFieldsToAllPalettesOfFieldAddsBeforeExistingIfRequested(): void
735  {
736  ‪$GLOBALS['TCA'] = [
737  'aTable' => [
738  'columns' => [
739  'fieldA' => [],
740  ],
741  'types' => [
742  'typeA' => [
743  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
744  ],
745  ],
746  'palettes' => [
747  'paletteA' => [
748  'showitem' => 'existingA, existingB',
749  ],
750  ],
751  ],
752  ];
753  $expected = [
754  'aTable' => [
755  'columns' => [
756  'fieldA' => [],
757  ],
758  'types' => [
759  'typeA' => [
760  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
761  ],
762  ],
763  'palettes' => [
764  'paletteA' => [
765  'showitem' => 'existingA, newA, existingB',
766  ],
767  ],
768  ],
769  ];
771  'aTable',
772  'fieldA',
773  'newA',
774  'before:existingB'
775  );
776  self::assertEquals($expected, ‪$GLOBALS['TCA']);
777  }
778 
782  public function addFieldsToAllPalettesOfFieldAddsFieldsAtEndIfBeforeRequestedDoesNotExist(): void
783  {
784  ‪$GLOBALS['TCA'] = [
785  'aTable' => [
786  'columns' => [
787  'fieldA' => [],
788  ],
789  'types' => [
790  'typeA' => [
791  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
792  ],
793  ],
794  'palettes' => [
795  'paletteA' => [
796  'showitem' => 'fieldX, fieldY',
797  ],
798  ],
799  ],
800  ];
801  $expected = [
802  'aTable' => [
803  'columns' => [
804  'fieldA' => [],
805  ],
806  'types' => [
807  'typeA' => [
808  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
809  ],
810  ],
811  'palettes' => [
812  'paletteA' => [
813  'showitem' => 'fieldX, fieldY, newA, newB',
814  ],
815  ],
816  ],
817  ];
819  'aTable',
820  'fieldA',
821  'newA, newB',
822  'before:notExisting'
823  );
824  self::assertEquals($expected, ‪$GLOBALS['TCA']);
825  }
826 
830  public function addFieldsToAllPalettesOfFieldAddsAfterExistingIfRequested(): void
831  {
832  ‪$GLOBALS['TCA'] = [
833  'aTable' => [
834  'columns' => [
835  'fieldA' => [],
836  ],
837  'types' => [
838  'typeA' => [
839  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
840  ],
841  ],
842  'palettes' => [
843  'paletteA' => [
844  'showitem' => 'existingA, existingB',
845  ],
846  ],
847  ],
848  ];
849  $expected = [
850  'aTable' => [
851  'columns' => [
852  'fieldA' => [],
853  ],
854  'types' => [
855  'typeA' => [
856  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
857  ],
858  ],
859  'palettes' => [
860  'paletteA' => [
861  'showitem' => 'existingA, newA, existingB',
862  ],
863  ],
864  ],
865  ];
867  'aTable',
868  'fieldA',
869  'newA',
870  'after:existingA'
871  );
872  self::assertEquals($expected, ‪$GLOBALS['TCA']);
873  }
874 
878  public function addFieldsToAllPalettesOfFieldAddsFieldsAtEndIfAfterRequestedDoesNotExist(): void
879  {
880  ‪$GLOBALS['TCA'] = [
881  'aTable' => [
882  'columns' => [
883  'fieldA' => [],
884  ],
885  'types' => [
886  'typeA' => [
887  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
888  ],
889  ],
890  'palettes' => [
891  'paletteA' => [
892  'showitem' => 'existingA, existingB',
893  ],
894  ],
895  ],
896  ];
897  $expected = [
898  'aTable' => [
899  'columns' => [
900  'fieldA' => [],
901  ],
902  'types' => [
903  'typeA' => [
904  'showitem' => 'fieldA;labelA, --palette--;;paletteA',
905  ],
906  ],
907  'palettes' => [
908  'paletteA' => [
909  'showitem' => 'existingA, existingB, newA, newB',
910  ],
911  ],
912  ],
913  ];
915  'aTable',
916  'fieldA',
917  'newA, newB',
918  'after:notExistingA'
919  );
920  self::assertEquals($expected, ‪$GLOBALS['TCA']);
921  }
922 
926  public function addFieldsToAllPalettesOfFieldAddsNewPaletteIfFieldHasNoPaletteYet(): void
927  {
928  ‪$GLOBALS['TCA'] = [
929  'aTable' => [
930  'columns' => [
931  'fieldA' => [],
932  ],
933  'types' => [
934  'typeA' => [
935  'showitem' => 'fieldA',
936  ],
937  ],
938  ],
939  ];
940  $expected = [
941  'aTable' => [
942  'columns' => [
943  'fieldA' => [],
944  ],
945  'types' => [
946  'typeA' => [
947  'showitem' => 'fieldA, --palette--;;generatedFor-fieldA',
948  ],
949  ],
950  'palettes' => [
951  'generatedFor-fieldA' => [
952  'showitem' => 'newA',
953  ],
954  ],
955  ],
956  ];
958  'aTable',
959  'fieldA',
960  'newA'
961  );
962  self::assertEquals($expected, ‪$GLOBALS['TCA']);
963  }
964 
968  public function addFieldsToAllPalettesOfFieldAddsNewPaletteIfFieldHasNoPaletteYetAndKeepsExistingLabel(): void
969  {
970  ‪$GLOBALS['TCA'] = [
971  'aTable' => [
972  'columns' => [
973  'fieldA' => [],
974  ],
975  'types' => [
976  'typeA' => [
977  'showitem' => 'fieldA;labelA',
978  ],
979  ],
980  ],
981  ];
982  $expected = [
983  'aTable' => [
984  'columns' => [
985  'fieldA' => [],
986  ],
987  'types' => [
988  'typeA' => [
989  'showitem' => 'fieldA;labelA, --palette--;;generatedFor-fieldA',
990  ],
991  ],
992  'palettes' => [
993  'generatedFor-fieldA' => [
994  'showitem' => 'newA',
995  ],
996  ],
997  ],
998  ];
1000  'aTable',
1001  'fieldA',
1002  'newA'
1003  );
1004  self::assertEquals($expected, ‪$GLOBALS['TCA']);
1005  }
1006 
1008  // Tests concerning executePositionedStringInsertion
1010 
1015  public function executePositionedStringInsertionTrimsCorrectCharactersDataProvider(): array
1016  {
1017  return [
1018  'normal characters' => [
1019  'tr0',
1020  'tr0',
1021  ],
1022  'newlines' => [
1023  "test\n",
1024  'test',
1025  ],
1026  'newlines with carriage return' => [
1027  "test\r\n",
1028  'test',
1029  ],
1030  'tabs' => [
1031  "test\t",
1032  'test',
1033  ],
1034  'commas' => [
1035  'test,',
1036  'test',
1037  ],
1038  'multiple commas with trailing spaces' => [
1039  "test,,\t, \r\n",
1040  'test',
1041  ],
1042  ];
1043  }
1044 
1049  public function executePositionedStringInsertionTrimsCorrectCharacters(string $string, string $expectedResult): void
1050  {
1051  $extensionManagementUtility = $this->getAccessibleMock(ExtensionManagementUtility::class, ['dummy']);
1052  $string = $extensionManagementUtility->_call('executePositionedStringInsertion', $string, '');
1053  self::assertEquals($expectedResult, $string);
1054  }
1055 
1057  // Tests concerning addTcaSelectItem
1059 
1062  public function addTcaSelectItemThrowsExceptionIfTableIsNotOfTypeString(): void
1063  {
1064  $this->expectException(\InvalidArgumentException::class);
1065  $this->expectExceptionCode(1303236963);
1066 
1068  }
1069 
1073  public function addTcaSelectItemThrowsExceptionIfFieldIsNotOfTypeString(): void
1074  {
1075  $this->expectException(\InvalidArgumentException::class);
1076  $this->expectExceptionCode(1303236964);
1077 
1079  }
1080 
1084  public function addTcaSelectItemThrowsExceptionIfRelativeToFieldIsNotOfTypeString(): void
1085  {
1086  $this->expectException(\InvalidArgumentException::class);
1087  $this->expectExceptionCode(1303236965);
1088 
1090  }
1091 
1095  public function addTcaSelectItemThrowsExceptionIfRelativePositionIsNotOfTypeString(): void
1096  {
1097  $this->expectException(\InvalidArgumentException::class);
1098  $this->expectExceptionCode(1303236966);
1099 
1100  ‪ExtensionManagementUtility::addTcaSelectItem('foo', 'bar', [], 'foo', []);
1101  }
1102 
1106  public function addTcaSelectItemThrowsExceptionIfRelativePositionIsNotOneOfValidKeywords(): void
1107  {
1108  $this->expectException(\InvalidArgumentException::class);
1109  $this->expectExceptionCode(1303236967);
1110 
1111  ‪ExtensionManagementUtility::addTcaSelectItem('foo', 'bar', [], 'foo', 'not allowed keyword');
1112  }
1113 
1117  public function addTcaSelectItemThrowsExceptionIfFieldIsNotFoundInTca(): void
1118  {
1119  $this->expectException(\RuntimeException::class);
1120  $this->expectExceptionCode(1303237468);
1121 
1122  ‪$GLOBALS['TCA'] = [];
1124  }
1125 
1129  public function addTcaSelectItemDataProvider(): array
1130  {
1131  // Every array splits into:
1132  // - relativeToField
1133  // - relativePosition
1134  // - expectedResultArray
1135  return [
1136  'add at end of array' => [
1137  '',
1138  '',
1139  [
1140  0 => ['firstElement'],
1141  1 => ['matchMe'],
1142  2 => ['thirdElement'],
1143  3 => ['insertedElement'],
1144  ],
1145  ],
1146  'replace element' => [
1147  'matchMe',
1148  'replace',
1149  [
1150  0 => ['firstElement'],
1151  1 => ['insertedElement'],
1152  2 => ['thirdElement'],
1153  ],
1154  ],
1155  'add element after' => [
1156  'matchMe',
1157  'after',
1158  [
1159  0 => ['firstElement'],
1160  1 => ['matchMe'],
1161  2 => ['insertedElement'],
1162  3 => ['thirdElement'],
1163  ],
1164  ],
1165  'add element before' => [
1166  'matchMe',
1167  'before',
1168  [
1169  0 => ['firstElement'],
1170  1 => ['insertedElement'],
1171  2 => ['matchMe'],
1172  3 => ['thirdElement'],
1173  ],
1174  ],
1175  'add at end if relative position was not found' => [
1176  'notExistingItem',
1177  'after',
1178  [
1179  0 => ['firstElement'],
1180  1 => ['matchMe'],
1181  2 => ['thirdElement'],
1182  3 => ['insertedElement'],
1183  ],
1184  ],
1185  ];
1186  }
1187 
1192  public function addTcaSelectItemInsertsItemAtSpecifiedPosition(string $relativeToField, string $relativePosition, array $expectedResultArray): void
1193  {
1194  ‪$GLOBALS['TCA'] = [
1195  'testTable' => [
1196  'columns' => [
1197  'testField' => [
1198  'config' => [
1199  'items' => [
1200  '0' => ['firstElement'],
1201  '1' => ['matchMe'],
1202  2 => ['thirdElement'],
1203  ],
1204  ],
1205  ],
1206  ],
1207  ],
1208  ];
1209  ‪ExtensionManagementUtility::addTcaSelectItem('testTable', 'testField', ['insertedElement'], $relativeToField, $relativePosition);
1210  self::assertEquals($expectedResultArray, ‪$GLOBALS['TCA']['testTable']['columns']['testField']['config']['items']);
1211  }
1212 
1214  // Tests concerning loadExtLocalconf
1216 
1219  public function loadExtLocalconfDoesNotReadFromCacheIfCachingIsDenied(): void
1220  {
1221  $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1222  ->onlyMethods(['getCache'])
1223  ->getMock();
1224  $mockCacheManager->expects(self::never())->method('getCache');
1226  $packageManager = $this->createMockPackageManagerWithMockPackage(‪StringUtility::getUniqueId());
1229  }
1230 
1234  public function loadExtLocalconfRequiresCacheFileIfExistsAndCachingIsAllowed(): void
1235  {
1236  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1237  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1238  ->disableOriginalConstructor()
1239  ->getMock();
1240 
1241  $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1242  ->onlyMethods(['getCache'])
1243  ->getMock();
1244  $mockCacheManager->method('getCache')->willReturn($mockCache);
1246  $mockCache->method('has')->willReturn(true);
1247  $mockCache->expects(self::once())->method('require');
1249  }
1250 
1252  // Tests concerning loadSingleExtLocalconfFiles
1254 
1257  public function loadSingleExtLocalconfFilesRequiresExtLocalconfFileRegisteredInGlobalTypo3LoadedExt(): void
1258  {
1259  $this->expectException(\RuntimeException::class);
1260  $this->expectExceptionCode(1340559079);
1261 
1262  $extensionName = ‪StringUtility::getUniqueId('foo');
1263  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1264  $extLocalconfLocation = $packageManager->getPackage($extensionName)->getPackagePath() . 'ext_localconf.php';
1265  file_put_contents($extLocalconfLocation, "<?php\n\nthrow new RuntimeException('', 1340559079);\n\n?>");
1268  }
1269 
1271  // Tests concerning addModule
1273 
1278  public function addModulePositionTestsDataProvider(): array
1279  {
1280  return [
1281  'can add new main module if none exists' => [
1282  'top',
1283  '',
1284  'newModule',
1285  ],
1286  'can add new sub module if no position specified' => [
1287  '',
1288  'some,modules',
1289  'some,modules,newModule',
1290  ],
1291  'can add new sub module to top of module' => [
1292  'top',
1293  'some,modules',
1294  'newModule,some,modules',
1295  ],
1296  'can add new sub module if bottom of module' => [
1297  'bottom',
1298  'some,modules',
1299  'some,modules,newModule',
1300  ],
1301  'can add new sub module before specified sub module' => [
1302  'before:modules',
1303  'some,modules',
1304  'some,newModule,modules',
1305  ],
1306  'can add new sub module after specified sub module' => [
1307  'after:some',
1308  'some,modules',
1309  'some,newModule,modules',
1310  ],
1311  'can add new sub module at the bottom if specified sub module to add before does not exist' => [
1312  'before:modules',
1313  'some,otherModules',
1314  'some,otherModules,newModule',
1315  ],
1316  'can add new sub module at the bottom if specified sub module to add after does not exist' => [
1317  'after:some',
1318  'someOther,modules',
1319  'someOther,modules,newModule',
1320  ],
1321  ];
1322  }
1323 
1328  public function addModuleCanAddModule(string $position, string $existing, string $expected): void
1329  {
1330  $mainModule = 'foobar';
1331  $subModule = 'newModule';
1332  if ($existing) {
1333  ‪$GLOBALS['TBE_MODULES'][$mainModule] = $existing;
1334  }
1335 
1336  ‪ExtensionManagementUtility::addModule($mainModule, $subModule, $position);
1337 
1338  self::assertTrue(isset(‪$GLOBALS['TBE_MODULES'][$mainModule]));
1339  self::assertEquals($expected, ‪$GLOBALS['TBE_MODULES'][$mainModule]);
1340  }
1341 
1346  public function addModuleCanAddMainModule(string $position, string $existing, string $expected): void
1347  {
1348  $mainModule = 'newModule';
1349  if ($existing) {
1350  foreach (explode(',', $existing) as $existingMainModule) {
1351  ‪$GLOBALS['TBE_MODULES'][$existingMainModule] = '';
1352  }
1353  }
1354 
1355  ‪ExtensionManagementUtility::addModule($mainModule, '', $position);
1356 
1357  self::assertTrue(isset(‪$GLOBALS['TBE_MODULES'][$mainModule]));
1358  unset(‪$GLOBALS['TBE_MODULES']['_configuration']);
1359  unset(‪$GLOBALS['TBE_MODULES']['_navigationComponents']);
1360  self::assertEquals($expected, implode(',', array_keys(‪$GLOBALS['TBE_MODULES'])));
1361  }
1362 
1364  // Tests concerning createExtLocalconfCacheEntry
1366 
1369  public function createExtLocalconfCacheEntryWritesCacheEntryWithContentOfLoadedExtensionExtLocalconf(): void
1370  {
1371  $extensionName = ‪StringUtility::getUniqueId('foo');
1372  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1373  $mockCache = $this->getMockBuilder(PhpFrontend::class)->disableOriginalConstructor()->getMock();
1374  $packageManager->setPackageCache(new PackageStatesPackageCache('vfs://Test/Configuration/PackageStates.php', $mockCache));
1375  $extLocalconfLocation = $packageManager->getPackage($extensionName)->getPackagePath() . 'ext_localconf.php';
1376  $uniqueStringInLocalconf = ‪StringUtility::getUniqueId('foo');
1377  file_put_contents($extLocalconfLocation, "<?php\n\n" . $uniqueStringInLocalconf . "\n\n?>");
1379  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1380  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1381  ->disableOriginalConstructor()
1382  ->getMock();
1383 
1384  $mockCache->expects(self::once())->method('set')->with(self::anything(), self::stringContains($uniqueStringInLocalconf), self::anything());
1386  }
1387 
1391  public function createExtLocalconfCacheEntryWritesCacheEntryWithExtensionContentOnlyIfExtLocalconfExists(): void
1392  {
1393  $extensionName = ‪StringUtility::getUniqueId('foo');
1394  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1395  $mockCache = $this->getMockBuilder(PhpFrontend::class)->disableOriginalConstructor()->getMock();
1396  $packageManager->setPackageCache(new PackageStatesPackageCache('vfs://Test/Configuration/PackageStates.php', $mockCache));
1398  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1399  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1400  ->disableOriginalConstructor()
1401  ->getMock();
1402 
1403  $mockCache->expects(self::once())
1404  ->method('set')
1405  ->with(self::anything(), self::logicalNot(self::stringContains($extensionName)), self::anything());
1407  }
1408 
1412  public function createExtLocalconfCacheEntryWritesCacheEntryWithNoTags(): void
1413  {
1414  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1415  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1416  ->disableOriginalConstructor()
1417  ->getMock();
1418  $mockCache->expects(self::once())->method('set')->with(self::anything(), self::anything(), self::equalTo([]));
1419  $packageManager = $this->createMockPackageManagerWithMockPackage(‪StringUtility::getUniqueId());
1420  $packageManager->setPackageCache(new PackageStatesPackageCache('vfs://Test/Configuration/PackageStates.php', $mockCache));
1423  }
1424 
1426  // Tests concerning getExtLocalconfCacheIdentifier
1428 
1431  public function getExtLocalconfCacheIdentifierCreatesSha1WithFourtyCharactersAndPrefix(): void
1432  {
1433  $prefix = 'ext_localconf_';
1435  self::assertStringStartsWith($prefix, $identifier);
1436  $sha1 = str_replace($prefix, '', $identifier);
1437  self::assertEquals(40, strlen($sha1));
1438  }
1439 
1441  // Tests concerning loadBaseTca
1443 
1447  public function loadBaseTcaDoesNotReadFromCacheIfCachingIsDenied(): void
1448  {
1449  $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1450  ->onlyMethods(['getCache'])
1451  ->getMock();
1452  $mockCacheManager->expects(self::never())->method('getCache');
1455  }
1456 
1460  public function loadBaseTcaRequiresCacheFileIfExistsAndCachingIsAllowed(): void
1461  {
1462  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1463  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1464  ->disableOriginalConstructor()
1465  ->getMock();
1466 
1467  $mockCache->expects(self::once())->method('require')->willReturn(['tca' => [], 'categoryRegistry' => \serialize(‪CategoryRegistry::getInstance())]);
1469  }
1470 
1474  public function loadBaseTcaCreatesCacheFileWithContentOfAnExtensionsConfigurationTcaPhpFile(): void
1475  {
1476  $extensionName = ‪StringUtility::getUniqueId('test_baseTca_');
1477  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1478  $mockCache = $this->getMockBuilder(PhpFrontend::class)->disableOriginalConstructor()->getMock();
1479  $packageManager->setPackageCache(new PackageStatesPackageCache('vfs://Test/Configuration/PackageStates.php', $mockCache));
1480  $packagePath = $packageManager->getPackage($extensionName)->getPackagePath();
1481  ‪GeneralUtility::mkdir($packagePath);
1482  ‪GeneralUtility::mkdir($packagePath . 'Configuration/');
1483  ‪GeneralUtility::mkdir($packagePath . 'Configuration/TCA/');
1485  $uniqueTableName = ‪StringUtility::getUniqueId('table_name_');
1486  $uniqueStringInTableConfiguration = ‪StringUtility::getUniqueId('table_configuration_');
1487  $tableConfiguration = '<?php return array(\'foo\' => \'' . $uniqueStringInTableConfiguration . '\'); ?>';
1488  file_put_contents($packagePath . 'Configuration/TCA/' . $uniqueTableName . '.php', $tableConfiguration);
1489  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1490  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1491  ->disableOriginalConstructor()
1492  ->getMock();
1493 
1494  $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1495  ->onlyMethods(['getCache'])
1496  ->getMock();
1497  $mockCacheManager->method('getCache')->willReturn($mockCache);
1498  ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1499  $mockCache->expects(self::once())->method('require')->willReturn(false);
1500  $mockCache->expects(self::once())->method('set')->with(self::anything(), self::stringContains($uniqueStringInTableConfiguration), self::anything());
1501 
1502  $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
1503  $eventDispatcher->dispatch(Argument::any())->shouldBeCalled()->willReturnArgument(0);
1504  ExtensionManagementUtility::setEventDispatcher($eventDispatcher->reveal());
1505 
1506  ExtensionManagementUtility::loadBaseTca(true);
1507  }
1508 
1512  public function loadBaseTcaWritesCacheEntryWithNoTags(): void
1513  {
1514  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1515  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1516  ->disableOriginalConstructor()
1517  ->getMock();
1518 
1519  $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1520  ->onlyMethods(['getCache'])
1521  ->getMock();
1522  $mockCacheManager->method('getCache')->willReturn($mockCache);
1523  ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1524  $mockCache->expects(self::once())->method('require')->willReturn(false);
1525  $mockCache->expects(self::once())->method('set')->with(self::anything(), self::anything(), self::equalTo([]));
1526  ExtensionManagementUtilityAccessibleProxy::loadBaseTca();
1527  }
1528 
1530  // Tests concerning getBaseTcaCacheIdentifier
1532 
1536  public function getBaseTcaCacheIdentifierCreatesSha1WithFourtyCharactersAndPrefix(): void
1537  {
1538  $prefix = 'tca_base_';
1539  $identifier = ExtensionManagementUtilityAccessibleProxy::getBaseTcaCacheIdentifier();
1540  self::assertStringStartsWith($prefix, $identifier);
1541  $sha1 = str_replace($prefix, '', $identifier);
1542  self::assertEquals(40, strlen($sha1));
1543  }
1544 
1546  // Tests concerning loadExtTables
1548 
1551  public function loadExtTablesDoesNotReadFromCacheIfCachingIsDenied(): void
1552  {
1553  $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1554  ->onlyMethods(['getCache'])
1555  ->getMock();
1556  $mockCacheManager->expects(self::never())->method('getCache');
1557  ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1558  $packageManager = $this->createMockPackageManagerWithMockPackage(StringUtility::getUniqueId());
1559  ExtensionManagementUtility::setPackageManager($packageManager);
1560  ExtensionManagementUtility::loadExtLocalconf(false);
1561  }
1562 
1566  public function loadExtTablesRequiresCacheFileIfExistsAndCachingIsAllowed(): void
1567  {
1568  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1569  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1570  ->disableOriginalConstructor()
1571  ->getMock();
1572 
1573  $mockCacheManager = $this->getMockBuilder(CacheManager::class)
1574  ->onlyMethods(['getCache'])
1575  ->getMock();
1576  $mockCacheManager->method('getCache')->willReturn($mockCache);
1577  ExtensionManagementUtilityAccessibleProxy::setCacheManager($mockCacheManager);
1578  $mockCache->method('has')->willReturn(true);
1579  $mockCache->expects(self::once())->method('require');
1580  // Reset the internal cache access tracking variable of extMgm
1581  // This method is only in the ProxyClass!
1582  ExtensionManagementUtilityAccessibleProxy::resetExtTablesWasReadFromCacheOnceBoolean();
1583  ExtensionManagementUtility::loadExtTables(true);
1584  }
1585 
1587  // Tests concerning createExtTablesCacheEntry
1589 
1592  public function createExtTablesCacheEntryWritesCacheEntryWithContentOfLoadedExtensionExtTables(): void
1593  {
1594  $extensionName = StringUtility::getUniqueId('foo');
1595  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1596  $extensionPath = $packageManager->getPackage($extensionName)->getPackagePath();
1597  $extTablesLocation = $extensionPath . 'ext_tables.php';
1598  $uniqueStringInTables = StringUtility::getUniqueId('foo');
1599  file_put_contents($extTablesLocation, "<?php\n\n$uniqueStringInTables\n\n?>");
1600  ExtensionManagementUtility::setPackageManager($packageManager);
1601  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1602  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1603  ->disableOriginalConstructor()
1604  ->getMock();
1605  $packageManager->setPackageCache(new PackageStatesPackageCache('vfs://Test/Configuration/PackageStates.php', $mockCache));
1606 
1607  $mockCache->expects(self::once())->method('set')->with(self::anything(), self::stringContains($uniqueStringInTables), self::anything());
1609  }
1610 
1614  public function createExtTablesCacheEntryWritesCacheEntryWithExtensionContentOnlyIfExtTablesExists(): void
1615  {
1616  $extensionName = ‪StringUtility::getUniqueId('foo');
1617  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionName);
1619  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1620  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1621  ->disableOriginalConstructor()
1622  ->getMock();
1623  $packageManager->setPackageCache(new PackageStatesPackageCache('vfs://Test/Configuration/PackageStates.php', $mockCache));
1624 
1625  $mockCache->expects(self::once())
1626  ->method('set')
1627  ->with(self::anything(), self::logicalNot(self::stringContains($extensionName)), self::anything());
1629  }
1630 
1634  public function createExtTablesCacheEntryWritesCacheEntryWithNoTags(): void
1635  {
1636  $mockCache = $this->getMockBuilder(PhpFrontend::class)
1637  ->onlyMethods(['getIdentifier', 'set', 'get', 'has', 'remove', 'flush', 'flushByTag', 'require'])
1638  ->disableOriginalConstructor()
1639  ->getMock();
1640 
1641  $mockCache->expects(self::once())->method('set')->with(self::anything(), self::anything(), self::equalTo([]));
1642  $packageManager = $this->createMockPackageManagerWithMockPackage(‪StringUtility::getUniqueId());
1643  $packageManager->setPackageCache(new PackageStatesPackageCache('vfs://Test/Configuration/PackageStates.php', $mockCache));
1646  }
1647 
1649  // Tests concerning getExtTablesCacheIdentifier
1651 
1654  public function getExtTablesCacheIdentifierCreatesSha1WithFourtyCharactersAndPrefix(): void
1655  {
1656  $prefix = 'ext_tables_';
1658  self::assertStringStartsWith($prefix, $identifier);
1659  $sha1 = str_replace($prefix, '', $identifier);
1660  self::assertEquals(40, strlen($sha1));
1661  }
1662 
1664  // Tests concerning getExtensionVersion
1666 
1671  public function getExtensionVersionFaultyDataProvider(): array
1672  {
1673  return [
1674  [''],
1675  [0],
1676  [new \stdClass()],
1677  [true],
1678  ];
1679  }
1680 
1687  public function getExtensionVersionForFaultyExtensionKeyThrowsException($key): void
1688  {
1689  $this->expectException(\InvalidArgumentException::class);
1690  $this->expectExceptionCode(1294586096);
1691 
1693  }
1694 
1698  public function getExtensionVersionForNotLoadedExtensionReturnsEmptyString(): void
1699  {
1700  $uniqueSuffix = ‪StringUtility::getUniqueId('test');
1701  $extensionKey = 'unloadedextension' . $uniqueSuffix;
1702  self::assertEquals('', ‪ExtensionManagementUtility::getExtensionVersion($extensionKey));
1703  }
1704 
1708  public function getExtensionVersionForLoadedExtensionReturnsExtensionVersion(): void
1709  {
1710  $uniqueSuffix = ‪StringUtility::getUniqueId('test');
1711  $extensionKey = 'unloadedextension' . $uniqueSuffix;
1712  $packageMetaData = $this->getMockBuilder(MetaData::class)
1713  ->onlyMethods(['getVersion'])
1714  ->setConstructorArgs([$extensionKey])
1715  ->getMock();
1716  $packageMetaData->method('getVersion')->willReturn('1.2.3');
1717  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionKey, ['getPackagePath', 'getPackageKey', 'getPackageMetaData']);
1719  $package = $packageManager->getPackage($extensionKey);
1720  $package
1721  ->method('getPackageMetaData')
1722  ->willReturn($packageMetaData);
1724  self::assertEquals('1.2.3', ‪ExtensionManagementUtility::getExtensionVersion($extensionKey));
1725  }
1726 
1728  // Tests concerning loadExtension
1730 
1733  public function loadExtensionThrowsExceptionIfExtensionIsLoaded(): void
1734  {
1735  $this->expectException(\RuntimeException::class);
1736  $this->expectExceptionCode(1342345486);
1737 
1738  $extensionKey = ‪StringUtility::getUniqueId('test');
1739  $packageManager = $this->createMockPackageManagerWithMockPackage($extensionKey);
1742  }
1743 
1745  // Tests concerning unloadExtension
1747 
1750  public function unloadExtensionThrowsExceptionIfExtensionIsNotLoaded(): void
1751  {
1752  $this->expectException(\RuntimeException::class);
1753  $this->expectExceptionCode(1342345487);
1754 
1755  $packageName = ‪StringUtility::getUniqueId('foo');
1756  $packageManager = $this->getMockBuilder(PackageManager::class)
1757  ->onlyMethods(['isPackageActive'])
1758  ->disableOriginalConstructor()
1759  ->getMock();
1760  $packageManager->expects(self::once())
1761  ->method('isPackageActive')
1762  ->with(self::equalTo($packageName))
1763  ->willReturn(false);
1766  }
1767 
1771  public function unloadExtensionCallsPackageManagerToDeactivatePackage(): void
1772  {
1773  $packageName = ‪StringUtility::getUniqueId('foo');
1774  $packageManager = $this->getMockBuilder(PackageManager::class)
1775  ->onlyMethods(['isPackageActive', 'deactivatePackage'])
1776  ->disableOriginalConstructor()
1777  ->getMock();
1778  $packageManager
1779  ->method('isPackageActive')
1780  ->willReturn(true);
1781  $packageManager->expects(self::once())
1782  ->method('deactivatePackage')
1783  ->with($packageName);
1786  }
1787 
1789  // Tests concerning addPlugin
1791 
1795  public function addPluginSetsTcaCorrectlyForGivenExtKeyAsParameter(): void
1796  {
1797  $extKey = 'indexed_search';
1798  $expectedTCA = [
1799  [
1800  'label',
1801  $extKey,
1802  'EXT:' . $extKey . '/Resources/Public/Icons/Extension.png',
1803  'default',
1804  ],
1805  ];
1806  ‪$GLOBALS['TCA']['tt_content']['columns']['list_type']['config']['items'] = [];
1807  ‪ExtensionManagementUtility::addPlugin(['label', $extKey], 'list_type', $extKey);
1808  self::assertEquals($expectedTCA, ‪$GLOBALS['TCA']['tt_content']['columns']['list_type']['config']['items']);
1809  }
1810 
1814  public function addPluginThrowsExceptionForMissingExtkey(): void
1815  {
1816  $this->expectException(\InvalidArgumentException::class);
1817  $this->expectExceptionCode(1404068038);
1818 
1820  }
1821 
1825  public function addPluginAsContentTypeAddsIconAndDefaultItem(): void
1826  {
1827  $extKey = 'felogin';
1828  $expectedTCA = [
1829  [
1830  'label',
1831  'felogin',
1832  'content-form-login',
1833  'default',
1834  ],
1835  ];
1836  ‪$GLOBALS['TCA']['tt_content']['ctrl']['typeicon_classes'] = [];
1837  ‪$GLOBALS['TCA']['tt_content']['types']['header'] = ['showitem' => 'header,header_link'];
1838  ‪$GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'] = [];
1839  ‪ExtensionManagementUtility::addPlugin(['label', $extKey, 'content-form-login'], 'CType', $extKey);
1840  self::assertEquals($expectedTCA, ‪$GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items']);
1841  self::assertEquals([$extKey => 'content-form-login'], ‪$GLOBALS['TCA']['tt_content']['ctrl']['typeicon_classes']);
1842  self::assertEquals(‪$GLOBALS['TCA']['tt_content']['types']['header'], ‪$GLOBALS['TCA']['tt_content']['types']['felogin']);
1843  }
1844 
1845  public function addTcaSelectItemGroupAddsGroupDataProvider(): array
1846  {
1847  return [
1848  'add the first group' => [
1849  'my_group',
1850  'my_group_label',
1851  null,
1852  null,
1853  [
1854  'my_group' => 'my_group_label',
1855  ],
1856  ],
1857  'add a new group at the bottom' => [
1858  'my_group',
1859  'my_group_label',
1860  'bottom',
1861  [
1862  'default' => 'default_label',
1863  ],
1864  [
1865  'default' => 'default_label',
1866  'my_group' => 'my_group_label',
1867  ],
1868  ],
1869  'add a new group at the top' => [
1870  'my_group',
1871  'my_group_label',
1872  'top',
1873  [
1874  'default' => 'default_label',
1875  ],
1876  [
1877  'my_group' => 'my_group_label',
1878  'default' => 'default_label',
1879  ],
1880  ],
1881  'add a new group after an existing group' => [
1882  'my_group',
1883  'my_group_label',
1884  'after:default',
1885  [
1886  'default' => 'default_label',
1887  'special' => 'special_label',
1888  ],
1889  [
1890  'default' => 'default_label',
1891  'my_group' => 'my_group_label',
1892  'special' => 'special_label',
1893  ],
1894  ],
1895  'add a new group before an existing group' => [
1896  'my_group',
1897  'my_group_label',
1898  'before:default',
1899  [
1900  'default' => 'default_label',
1901  'special' => 'special_label',
1902  ],
1903  [
1904  'my_group' => 'my_group_label',
1905  'default' => 'default_label',
1906  'special' => 'special_label',
1907  ],
1908  ],
1909  'add a new group after a non-existing group moved to bottom' => [
1910  'my_group',
1911  'my_group_label',
1912  'after:default2',
1913  [
1914  'default' => 'default_label',
1915  'special' => 'special_label',
1916  ],
1917  [
1918  'default' => 'default_label',
1919  'special' => 'special_label',
1920  'my_group' => 'my_group_label',
1921  ],
1922  ],
1923  'add a new group which already exists does nothing' => [
1924  'my_group',
1925  'my_group_label',
1926  'does-not-matter',
1927  [
1928  'default' => 'default_label',
1929  'my_group' => 'existing_label',
1930  'special' => 'special_label',
1931  ],
1932  [
1933  'default' => 'default_label',
1934  'my_group' => 'existing_label',
1935  'special' => 'special_label',
1936  ],
1937  ],
1938  ];
1939  }
1940 
1950  public function addTcaSelectItemGroupAddsGroup(string $groupId, string $groupLabel, ?string $position, ?array $existingGroups, array $expectedGroups): void
1951  {
1952  ‪$GLOBALS['TCA']['tt_content']['columns']['CType']['config'] = [];
1953  if (is_array($existingGroups)) {
1954  ‪$GLOBALS['TCA']['tt_content']['columns']['CType']['config']['itemGroups'] = $existingGroups;
1955  }
1956  ‪ExtensionManagementUtility::addTcaSelectItemGroup('tt_content', 'CType', $groupId, $groupLabel, $position);
1957  self::assertEquals($expectedGroups, ‪$GLOBALS['TCA']['tt_content']['columns']['CType']['config']['itemGroups']);
1958  }
1959 
1963  public function addServiceDoesNotFailIfValueIsNotSet(): void
1964  {
1966  'myprovider',
1967  'auth',
1968  'myclass',
1969  [
1970  'title' => 'My authentication provider',
1971  'description' => 'Authentication with my provider',
1972  'subtype' => 'processLoginDataBE,getUserBE,authUserBE',
1973  'available' => true,
1974  'priority' => 80,
1975  'quality' => 100,
1976  ]
1977  );
1978  }
1979 }
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addModule
‪static addModule($main, $sub='', $position='', $path=null, $moduleConfiguration=[])
Definition: ExtensionManagementUtility.php:771
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:206
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\unloadExtension
‪static unloadExtension($extensionKey)
Definition: ExtensionManagementUtility.php:1861
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\setCacheManager
‪static setCacheManager(CacheManager $cacheManager=null)
Definition: ExtensionManagementUtilityAccessibleProxy.php:30
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\loadSingleExtLocalconfFiles
‪static loadSingleExtLocalconfFiles()
Definition: ExtensionManagementUtilityAccessibleProxy.php:45
‪TYPO3\CMS\Core\Package\Cache\PackageStatesPackageCache
Definition: PackageStatesPackageCache.php:30
‪TYPO3\CMS\Core\Cache\Frontend\PhpFrontend
Definition: PhpFrontend.php:25
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\loadExtension
‪static loadExtension($extensionKey)
Definition: ExtensionManagementUtility.php:1844
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addFieldsToPalette
‪static addFieldsToPalette($table, $palette, $addFields, $insertionPosition='')
Definition: ExtensionManagementUtility.php:405
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addTcaSelectItem
‪static addTcaSelectItem($table, $field, array $item, $relativeToField='', $relativePosition='')
Definition: ExtensionManagementUtility.php:449
‪TYPO3\CMS\Core\Tests\Unit\Utility
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addPlugin
‪static addPlugin($itemArray, $type='list_type', $extensionKey=null)
Definition: ExtensionManagementUtility.php:1201
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addToAllTCAtypes
‪static addToAllTCAtypes($table, $newFieldsString, $typeList='', $position='')
Definition: ExtensionManagementUtility.php:224
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addTcaSelectItemGroup
‪static addTcaSelectItemGroup(string $table, string $field, string $groupId, string $groupLabel, ?string $position='bottom')
Definition: ExtensionManagementUtility.php:508
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\removeDuplicatesForInsertion
‪static removeDuplicatesForInsertion($insertionList, $list='')
Definition: ExtensionManagementUtilityAccessibleProxy.php:82
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addFieldsToAllPalettesOfField
‪static addFieldsToAllPalettesOfField($table, $field, $addFields, $insertionPosition='')
Definition: ExtensionManagementUtility.php:352
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:43
‪TYPO3\CMS\Core\Category\CategoryRegistry\getInstance
‪static CategoryRegistry getInstance()
Definition: CategoryRegistry.php:53
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\getExtTablesCacheIdentifier
‪static getExtTablesCacheIdentifier()
Definition: ExtensionManagementUtilityAccessibleProxy.php:70
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\getExtLocalconfCacheIdentifier
‪static getExtLocalconfCacheIdentifier()
Definition: ExtensionManagementUtilityAccessibleProxy.php:40
‪TYPO3\CMS\Core\Category\CategoryRegistry
Definition: CategoryRegistry.php:30
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\setPackageManager
‪static setPackageManager(PackageManager $packageManager)
Definition: ExtensionManagementUtility.php:66
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep($directory)
Definition: GeneralUtility.php:1908
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\getExtensionVersion
‪static string getExtensionVersion($key)
Definition: ExtensionManagementUtility.php:172
‪TYPO3\CMS\Core\Package\Package
Definition: Package.php:28
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Core\Package\MetaData
Definition: PackageConstraint.php:16
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\getCN
‪static string getCN($key)
Definition: ExtensionManagementUtility.php:157
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\getPackageManager
‪static getPackageManager()
Definition: ExtensionManagementUtilityAccessibleProxy.php:35
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:128
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\createExtTablesCacheEntry
‪static createExtTablesCacheEntry(FrontendInterface $cache)
Definition: ExtensionManagementUtilityAccessibleProxy.php:65
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy\createExtLocalconfCacheEntry
‪static createExtLocalconfCacheEntry(FrontendInterface $cache)
Definition: ExtensionManagementUtilityAccessibleProxy.php:60
‪$tca
‪$tca
Definition: sys_file_metadata.php:5
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\extPath
‪static string extPath($key, $script='')
Definition: ExtensionManagementUtility.php:142
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\loadBaseTca
‪static loadBaseTca($allowCaching=true, FrontendInterface $codeCache=null)
Definition: ExtensionManagementUtility.php:1605
‪TYPO3\CMS\Core\Tests\Unit\Utility\AccessibleProxies\ExtensionManagementUtilityAccessibleProxy
Definition: ExtensionManagementUtilityAccessibleProxy.php:29
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\loadExtLocalconf
‪static loadExtLocalconf($allowCaching=true, FrontendInterface $codeCache=null)
Definition: ExtensionManagementUtility.php:1514
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir
‪static bool mkdir($newFolder)
Definition: GeneralUtility.php:1891
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\isLoaded
‪static bool isLoaded($key)
Definition: ExtensionManagementUtility.php:114
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\addService
‪static addService($extKey, $serviceType, $serviceKey, $info)
Definition: ExtensionManagementUtility.php:1031
‪TYPO3\CMS\Core\Core\Environment\getVarPath
‪static string getVarPath()
Definition: Environment.php:218