[TASK] Doctrine: Migrate ExtensionService
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Service / ExtensionServiceTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Tests\Unit\Service;
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 use TYPO3\CMS\Extbase\Exception;
17
18 use Doctrine\DBAL\Statement;
19 use Prophecy\Argument;
20 use Prophecy\Prophecy\ObjectProphecy;
21 use TYPO3\CMS\Core\Database\Connection;
22 use TYPO3\CMS\Core\Database\ConnectionPool;
23 use TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder;
24 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
25 use TYPO3\CMS\Core\Tests\Unit\Database\Mocks\MockPlatform;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27
28 /**
29 * Test case
30 */
31 class ExtensionServiceTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
32 {
33 /**
34 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
35 */
36 protected $mockConfigurationManager;
37
38 /**
39 * @var \TYPO3\CMS\Extbase\Service\ExtensionService
40 */
41 protected $extensionService;
42
43 protected function setUp()
44 {
45 $GLOBALS['TYPO3_DB'] = $this->getMock(\TYPO3\CMS\Core\Database\DatabaseConnection::class, array('fullQuoteStr', 'exec_SELECTgetRows'));
46 $GLOBALS['TSFE'] = new \stdClass();
47 $GLOBALS['TSFE']->gr_list = '';
48 $this->extensionService = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Service\ExtensionService::class, array('dummy'));
49 $this->mockConfigurationManager = $this->getMock(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::class);
50 $this->extensionService->_set('configurationManager', $this->mockConfigurationManager);
51 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions'] = array(
52 'ExtensionName' => array(
53 'plugins' => array(
54 'SomePlugin' => array(
55 'controllers' => array(
56 'ControllerName' => array(
57 'actions' => array('index', 'otherAction')
58 )
59 )
60 ),
61 'ThirdPlugin' => array(
62 'controllers' => array(
63 'ControllerName' => array(
64 'actions' => array('otherAction', 'thirdAction')
65 )
66 )
67 )
68 )
69 ),
70 'SomeOtherExtensionName' => array(
71 'plugins' => array(
72 'SecondPlugin' => array(
73 'controllers' => array(
74 'ControllerName' => array(
75 'actions' => array('index', 'otherAction')
76 ),
77 'SecondControllerName' => array(
78 'actions' => array('someAction', 'someOtherAction'),
79 'nonCacheableActions' => array('someOtherAction')
80 )
81 )
82 )
83 )
84 )
85 );
86 }
87
88 /**
89 * Setup and return a mocked database connection that allows
90 * the QueryBuilder to work.
91 *
92 * @return ObjectProphecy
93 */
94 protected function getMockDatabaseConnection(): ObjectProphecy
95 {
96 $connection = $this->prophesize(Connection::class);
97 $connection->getDatabasePlatform()->willReturn(new MockPlatform());
98 $connection->getExpressionBuilder()->willReturn(new ExpressionBuilder($connection->reveal()));
99 $connection->quoteIdentifier(Argument::cetera())->willReturnArgument(0);
100
101 $queryBuilder = new QueryBuilder(
102 $connection->reveal(),
103 null,
104 new \Doctrine\DBAL\Query\QueryBuilder($connection->reveal())
105 );
106
107 $connectionPool = $this->prophesize(ConnectionPool::class);
108 $connectionPool->getQueryBuilderForTable('tt_content')->willReturn($queryBuilder);
109 GeneralUtility::addInstance(ConnectionPool::class, $connectionPool->reveal());
110
111 return $connection;
112 }
113
114 /**
115 * DataProvider for getPluginNamespaceByPluginSignatureTests()
116 *
117 * @return array
118 */
119 public function getPluginNamespaceDataProvider()
120 {
121 return array(
122 array('SomeExtension', 'SomePlugin', 'tx_someextension_someplugin'),
123 array('NonExistingExtension', 'SomePlugin', 'tx_nonexistingextension_someplugin'),
124 array('Invalid', '', 'tx_invalid_')
125 );
126 }
127
128 /**
129 * @test
130 * @dataProvider getPluginNamespaceDataProvider
131 * @param string $extensionName
132 * @param string $pluginName
133 * @param mixed $expectedResult
134 */
135 public function getPluginNamespaceTests($extensionName, $pluginName, $expectedResult)
136 {
137 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->will($this->returnValue(array()));
138 $actualResult = $this->extensionService->getPluginNamespace($extensionName, $pluginName);
139 $this->assertEquals($expectedResult, $actualResult, 'Failing for extension: "' . $extensionName . '", plugin: "' . $pluginName . '"');
140 }
141
142 /**
143 * @test
144 */
145 public function pluginNamespaceCanBeOverridden()
146 {
147 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->with(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, 'SomeExtension', 'SomePlugin')->will($this->returnValue(array('view' => array('pluginNamespace' => 'overridden_plugin_namespace'))));
148 $expectedResult = 'overridden_plugin_namespace';
149 $actualResult = $this->extensionService->getPluginNamespace('SomeExtension', 'SomePlugin');
150 $this->assertEquals($expectedResult, $actualResult);
151 }
152
153 /**
154 * DataProvider for getPluginNameByActionTests()
155 *
156 * @return array
157 */
158 public function getPluginNameByActionDataProvider()
159 {
160 return array(
161 array('ExtensionName', 'ControllerName', 'someNonExistingAction', null),
162 array('ExtensionName', 'ControllerName', 'index', 'SomePlugin'),
163 array('ExtensionName', 'ControllerName', 'thirdAction', 'ThirdPlugin'),
164 array('eXtEnSiOnNaMe', 'cOnTrOlLeRnAmE', 'thirdAction', null),
165 array('eXtEnSiOnNaMe', 'cOnTrOlLeRnAmE', 'ThIrDaCtIoN', null),
166 array('SomeOtherExtensionName', 'ControllerName', 'otherAction', 'SecondPlugin')
167 );
168 }
169
170 /**
171 * @test
172 * @dataProvider getPluginNameByActionDataProvider
173 * @param string $extensionName
174 * @param string $controllerName
175 * @param string $actionName
176 * @param mixed $expectedResult
177 */
178 public function getPluginNameByActionTests($extensionName, $controllerName, $actionName, $expectedResult)
179 {
180 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->with(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK)->will($this->returnValue(array('view' => array('pluginNamespace' => 'overridden_plugin_namespace'))));
181 $actualResult = $this->extensionService->getPluginNameByAction($extensionName, $controllerName, $actionName);
182 $this->assertEquals($expectedResult, $actualResult, 'Failing for $extensionName: "' . $extensionName . '", $controllerName: "' . $controllerName . '", $actionName: "' . $actionName . '" - ');
183 }
184
185 /**
186 * @test
187 */
188 public function getPluginNameByActionThrowsExceptionIfMoreThanOnePluginMatches()
189 {
190 $this->expectException(Exception::class);
191 $this->expectExceptionCode(1280825466);
192 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->with(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK)->will($this->returnValue(array('view' => array('pluginNamespace' => 'overridden_plugin_namespace'))));
193 $this->extensionService->getPluginNameByAction('ExtensionName', 'ControllerName', 'otherAction');
194 }
195
196 /**
197 * @test
198 */
199 public function getPluginNameByActionReturnsCurrentIfItCanHandleTheActionEvenIfMoreThanOnePluginMatches()
200 {
201 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->with(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK)->will($this->returnValue(array('extensionName' => 'CurrentExtension', 'pluginName' => 'CurrentPlugin', 'controllerConfiguration' => array('ControllerName' => array('actions' => array('otherAction'))))));
202 $actualResult = $this->extensionService->getPluginNameByAction('CurrentExtension', 'ControllerName', 'otherAction');
203 $expectedResult = 'CurrentPlugin';
204 $this->assertEquals($expectedResult, $actualResult);
205 }
206
207 /**
208 * @test
209 */
210 public function isActionCacheableReturnsTrueByDefault()
211 {
212 $mockConfiguration = array();
213 $this->mockConfigurationManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($mockConfiguration));
214 $actualResult = $this->extensionService->isActionCacheable('SomeExtension', 'SomePlugin', 'SomeController', 'someAction');
215 $this->assertTrue($actualResult);
216 }
217
218 /**
219 * @test
220 */
221 public function isActionCacheableReturnsFalseIfActionIsNotCacheable()
222 {
223 $mockConfiguration = array(
224 'controllerConfiguration' => array(
225 'SomeController' => array(
226 'nonCacheableActions' => array('someAction')
227 )
228 )
229 );
230 $this->mockConfigurationManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($mockConfiguration));
231 $actualResult = $this->extensionService->isActionCacheable('SomeExtension', 'SomePlugin', 'SomeController', 'someAction');
232 $this->assertFalse($actualResult);
233 }
234
235 /**
236 * @test
237 */
238 public function getTargetPidByPluginSignatureReturnsNullIfConfigurationManagerIsNotInitialized()
239 {
240 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->will($this->returnValue(null));
241 $this->assertNull($this->extensionService->getTargetPidByPlugin('ExtensionName', 'PluginName'));
242 }
243
244 /**
245 * @test
246 */
247 public function getTargetPidByPluginSignatureReturnsNullIfDefaultPidIsZero()
248 {
249 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->will($this->returnValue(array('view' => array('defaultPid' => 0))));
250 $this->assertNull($this->extensionService->getTargetPidByPlugin('ExtensionName', 'PluginName'));
251 }
252
253 /**
254 * @test
255 */
256 public function getTargetPidByPluginSignatureReturnsTheConfiguredDefaultPid()
257 {
258 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->will($this->returnValue(array('view' => array('defaultPid' => 123))));
259 $expectedResult = 123;
260 $actualResult = $this->extensionService->getTargetPidByPlugin('ExtensionName', 'SomePlugin');
261 $this->assertEquals($expectedResult, $actualResult);
262 }
263
264 /**
265 * @test
266 * @todo This should rather be a functional test since it needs a connection / querybuilder
267 */
268 public function getTargetPidByPluginSignatureDeterminesTheTargetPidIfDefaultPidIsAuto()
269 {
270 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->will(
271 $this->returnValue(['view' => ['defaultPid' => 'auto']])
272 );
273 $expectedResult = 321;
274
275 $statement = $this->prophesize(Statement::class);
276 $statement->fetchAll()->shouldBeCalled()->willReturn([['pid' => (string)$expectedResult]]);
277
278 $connection = $this->getMockDatabaseConnection();
279 $connection->executeQuery(
280 'SELECT pid FROM tt_content WHERE (list_type = :dcValue1) AND (CType = :dcValue2) AND (sys_language_uid = 0) LIMIT 2',
281 ['dcValue1' => 'extensionname_someplugin', 'dcValue2' => 'list'],
282 Argument::cetera()
283 )->shouldBeCalled()->willReturn($statement->reveal());
284
285 $actualResult = $this->extensionService->getTargetPidByPlugin('ExtensionName', 'SomePlugin');
286 $this->assertEquals($expectedResult, $actualResult);
287 }
288
289 /**
290 * @test
291 * @todo This should rather be a functional test since it needs a connection / querybuilder
292 */
293 public function getTargetPidByPluginSignatureReturnsNullIfTargetPidCouldNotBeDetermined()
294 {
295 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->will(
296 $this->returnValue(['view' => ['defaultPid' => 'auto']])
297 );
298
299 $statement = $this->prophesize(Statement::class);
300 $statement->fetchAll()->shouldBeCalled()->willReturn([]);
301
302 $connection = $this->getMockDatabaseConnection();
303 $connection->executeQuery(
304 'SELECT pid FROM tt_content WHERE (list_type = :dcValue1) AND (CType = :dcValue2) AND (sys_language_uid = 0) LIMIT 2',
305 ['dcValue1' => 'extensionname_someplugin', 'dcValue2' => 'list'],
306 Argument::cetera()
307 )->shouldBeCalled()->willReturn($statement->reveal());
308
309 $this->assertNull($this->extensionService->getTargetPidByPlugin('ExtensionName', 'SomePlugin'));
310 }
311
312 /**
313 * @test
314 * @todo This should rather be a functional test since it needs a connection / querybuilder
315 */
316 public function getTargetPidByPluginSignatureThrowsExceptionIfMoreThanOneTargetPidsWereFound()
317 {
318 $this->expectException(Exception::class);
319 $this->expectExceptionCode(1280773643);
320
321 $this->mockConfigurationManager->expects($this->once())->method('getConfiguration')->will(
322 $this->returnValue(['view' => ['defaultPid' => 'auto']])
323 );
324
325 $statement = $this->prophesize(Statement::class);
326 $statement->fetchAll()->shouldBeCalled()->willReturn([['pid' => 123], ['pid' => 124]]);
327
328 $connection = $this->getMockDatabaseConnection();
329 $connection->executeQuery(
330 'SELECT pid FROM tt_content WHERE (list_type = :dcValue1) AND (CType = :dcValue2) AND (sys_language_uid = 0) LIMIT 2',
331 ['dcValue1' => 'extensionname_someplugin', 'dcValue2' => 'list'],
332 Argument::cetera()
333 )->shouldBeCalled()->willReturn($statement->reveal());
334
335 $this->expectException(\TYPO3\CMS\Extbase\Exception::class);
336 $this->expectExceptionCode(1280773643);
337
338 $this->extensionService->getTargetPidByPlugin('ExtensionName', 'SomePlugin');
339 }
340
341 /**
342 * @test
343 */
344 public function getDefaultControllerNameByPluginReturnsNullIfGivenExtensionCantBeFound()
345 {
346 $this->assertNull($this->extensionService->getDefaultControllerNameByPlugin('NonExistingExtensionName', 'SomePlugin'));
347 }
348
349 /**
350 * @test
351 */
352 public function getDefaultControllerNameByPluginReturnsNullIfGivenPluginCantBeFound()
353 {
354 $this->assertNull($this->extensionService->getDefaultControllerNameByPlugin('ExtensionName', 'NonExistingPlugin'));
355 }
356
357 /**
358 * @test
359 */
360 public function getDefaultControllerNameByPluginReturnsFirstControllerNameOfGivenPlugin()
361 {
362 $expectedResult = 'ControllerName';
363 $actualResult = $this->extensionService->getDefaultControllerNameByPlugin('ExtensionName', 'SomePlugin');
364 $this->assertEquals($expectedResult, $actualResult);
365 }
366
367 /**
368 * @test
369 */
370 public function getDefaultActionNameByPluginAndControllerReturnsNullIfGivenExtensionCantBeFound()
371 {
372 $this->assertNull($this->extensionService->getDefaultActionNameByPluginAndController('NonExistingExtensionName', 'SomePlugin', 'ControllerName'));
373 }
374
375 /**
376 * @test
377 */
378 public function getDefaultActionNameByPluginAndControllerReturnsNullIfGivenPluginCantBeFound()
379 {
380 $this->assertNull($this->extensionService->getDefaultActionNameByPluginAndController('ExtensionName', 'NonExistingPlugin', 'ControllerName'));
381 }
382
383 /**
384 * @test
385 */
386 public function getDefaultActionNameByPluginAndControllerReturnsNullIfGivenControllerCantBeFound()
387 {
388 $this->assertNull($this->extensionService->getDefaultActionNameByPluginAndController('ExtensionName', 'SomePlugin', 'NonExistingControllerName'));
389 }
390
391 /**
392 * @test
393 */
394 public function getDefaultActionNameByPluginAndControllerReturnsFirstActionNameOfGivenController()
395 {
396 $expectedResult = 'someAction';
397 $actualResult = $this->extensionService->getDefaultActionNameByPluginAndController('SomeOtherExtensionName', 'SecondPlugin', 'SecondControllerName');
398 $this->assertEquals($expectedResult, $actualResult);
399 }
400 }