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