[BUGFIX] Unit tests call parent::tearDown()
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Tests / Unit / Utility / LocalizationUtilityTest.php
1 <?php
2 namespace TYPO3\CMS\Extbase\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\Extbase\Utility\LocalizationUtility;
18
19 /**
20 * Test case
21 */
22 class LocalizationUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
23 {
24 /**
25 * Subject is not notice free, disable E_NOTICES
26 */
27 protected static $suppressNotices = true;
28
29 /**
30 * Instance of configurationManager, injected to subject
31 *
32 * @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManager
33 */
34 protected $configurationManagerMock;
35
36 /**
37 * LOCAL_LANG array fixture
38 *
39 * @var array
40 */
41 protected $LOCAL_LANG = [];
42
43 /**
44 * File path of locallang for extension "core"
45 * @var string
46 */
47 protected $languageFilePath = '';
48
49 /**
50 * Prepare class mocking some dependencies
51 */
52 protected function setUp()
53 {
54 $this->languageFilePath = $this->getLanguageFilePath('core');
55 $this->LOCAL_LANG = [
56 $this->languageFilePath => [
57 'default' => [
58 'key1' => [
59 [
60 'source' => 'English label for key1',
61 'target' => 'English label for key1',
62 ]
63 ],
64 'key2' => [
65 [
66 'source' => 'English label for key2',
67 'target' => 'English label for key2',
68 ]
69 ],
70 'key3' => [
71 [
72 'source' => 'English label for key3',
73 'target' => 'English label for key3',
74 ]
75 ],
76 'key4' => [
77 [
78 'source' => 'English label for key4',
79 'target' => 'English label for key4',
80 ]
81 ],
82 'keyWithPlaceholder' => [
83 [
84 'source' => 'English label with number %d',
85 'target' => 'English label with number %d',
86 ]
87 ],
88 ],
89 'dk' => [
90 'key1' => [
91 [
92 'source' => 'English label for key1',
93 'target' => 'Dansk label for key1',
94 ]
95 ],
96 // not translated in dk => no target (llxml)
97 'key2' => [
98 [
99 'source' => 'English label for key2',
100 ]
101 ],
102 'key3' => [
103 [
104 'source' => 'English label for key3',
105 ]
106 ],
107 // not translated in dk => empty target (xliff)
108 'key4' => [
109 [
110 'source' => 'English label for key4',
111 'target' => '',
112 ]
113 ],
114 // not translated in dk => empty target (xliff)
115 'key5' => [
116 [
117 'source' => 'English label for key5',
118 'target' => '',
119 ]
120 ],
121 'keyWithPlaceholder' => [
122 [
123 'source' => 'English label with number %d',
124 ]
125 ],
126 ],
127 // fallback language for labels which are not translated in dk
128 'dk_alt' => [
129 'key1' => [
130 [
131 'source' => 'English label for key1',
132 ]
133 ],
134 'key2' => [
135 [
136 'source' => 'English label for key2',
137 'target' => 'Dansk alternative label for key2',
138 ]
139 ],
140 'key3' => [
141 [
142 'source' => 'English label for key3',
143 ]
144 ],
145 // not translated in dk_alt => empty target (xliff)
146 'key4' => [
147 [
148 'source' => 'English label for key4',
149 'target' => '',
150 ]
151 ],
152 'key5' => [
153 [
154 'source' => 'English label for key5',
155 'target' => 'Dansk alternative label for key5',
156 ]
157 ],
158 'keyWithPlaceholder' => [
159 [
160 'source' => 'English label with number %d',
161 ]
162 ],
163 ],
164
165 ],
166 ];
167
168 $reflectionClass = new \ReflectionClass(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::class);
169
170 $this->configurationManager = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Configuration\ConfigurationManager::class, ['getConfiguration']);
171 $property = $reflectionClass->getProperty('configurationManager');
172 $property->setAccessible(true);
173 $property->setValue($this->configurationManager);
174 }
175
176 /**
177 * Reset static properties
178 */
179 protected function tearDown()
180 {
181 $reflectionClass = new \ReflectionClass(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::class);
182
183 $property = $reflectionClass->getProperty('configurationManager');
184 $property->setAccessible(true);
185 $property->setValue(null);
186
187 $property = $reflectionClass->getProperty('LOCAL_LANG');
188 $property->setAccessible(true);
189 $property->setValue([]);
190
191 parent::tearDown();
192 }
193
194 /**
195 * @param string $extensionName
196 * @return string
197 */
198 protected function getLanguageFilePath(string $extensionName): string
199 {
200 return PATH_typo3 . 'sysext/' . $extensionName . '/Resources/Private/Language/locallang.xlf';
201 }
202
203 /**
204 * @test
205 */
206 public function implodeTypoScriptLabelArrayWorks()
207 {
208 $reflectionClass = new \ReflectionClass(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::class);
209 $method = $reflectionClass->getMethod('flattenTypoScriptLabelArray');
210 $method->setAccessible(true);
211
212 $expected = [
213 'key1' => 'value1',
214 'key2' => 'value2',
215 'key3' => 'value3',
216 'key3.subkey1' => 'subvalue1',
217 'key3.subkey2.subsubkey' => 'val'
218 ];
219 $input = [
220 'key1' => 'value1',
221 'key2' => 'value2',
222 'key3' => [
223 '_typoScriptNodeValue' => 'value3',
224 'subkey1' => 'subvalue1',
225 'subkey2' => [
226 'subsubkey' => 'val'
227 ]
228 ]
229 ];
230 $result = $method->invoke(null, $input);
231 $this->assertEquals($expected, $result);
232 }
233
234 /**
235 * @test
236 */
237 public function translateForEmptyStringKeyReturnsNull()
238 {
239 $this->assertNull(LocalizationUtility::translate('', 'extbase'));
240 }
241
242 /**
243 * @test
244 */
245 public function translateForEmptyStringKeyWithArgumentsReturnsNull()
246 {
247 $this->assertNull(LocalizationUtility::translate('', 'extbase', ['argument']));
248 }
249
250 /**
251 * @return array
252 */
253 public function translateDataProvider()
254 {
255 return [
256 'get translated key' =>
257 ['key1', 'dk', 'Dansk label for key1'],
258
259 'fallback to English when translation is missing for key' =>
260 ['key2', 'dk', 'English label for key2'],
261
262 'fallback to English for non existing language' =>
263 ['key2', 'xx', 'English label for key2'],
264
265 'replace placeholder with argument' =>
266 ['keyWithPlaceholder', 'default', 'English label with number 100', [], [100]],
267
268 'get translated key from primary language' =>
269 ['key1', 'dk', 'Dansk label for key1', ['dk_alt']],
270
271 'fallback to alternative language if translation is missing(llxml)' =>
272 ['key2', 'dk', 'Dansk alternative label for key2', ['dk_alt']],
273
274 'fallback to alternative language if translation is missing(xlif)' =>
275 ['key5', 'dk', 'Dansk alternative label for key5', ['dk_alt']],
276
277 'fallback to English for label not translated in dk and dk_alt(llxml)' =>
278 ['key3', 'dk', 'English label for key3', ['dk_alt']],
279
280 'fallback to English for label not translated in dk and dk_alt(xlif)' =>
281 ['key4', 'dk', 'English label for key4', ['dk_alt']],
282 ];
283 }
284
285 /**
286 * @param string $key
287 * @param string $languageKey
288 * @param string $expected
289 * @param array $altLanguageKeys
290 * @param array $arguments
291 * @dataProvider translateDataProvider
292 * @test
293 */
294 public function translateTestWithBackendUserLanguage($key, $languageKey, $expected, array $altLanguageKeys = [], array $arguments = null)
295 {
296 $reflectionClass = new \ReflectionClass(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::class);
297
298 $property = $reflectionClass->getProperty('LOCAL_LANG');
299 $property->setAccessible(true);
300 $property->setValue($this->LOCAL_LANG);
301
302 $oldBackendUserLanguage = $GLOBALS['BE_USER']->uc['lang'];
303 $GLOBALS['BE_USER']->uc['lang'] = $languageKey;
304 $this->assertEquals($expected, LocalizationUtility::translate($key, 'core', $arguments, null, $altLanguageKeys));
305 $GLOBALS['BE_USER']->uc['lang'] = $oldBackendUserLanguage;
306 }
307
308 /**
309 * @param string $key
310 * @param string $languageKey
311 * @param string $expected
312 * @param array $altLanguageKeys
313 * @param array $arguments
314 * @dataProvider translateDataProvider
315 * @test
316 */
317 public function translateTestWithExplicitLanguageParameters($key, $languageKey, $expected, array $altLanguageKeys = [], array $arguments = null)
318 {
319 $reflectionClass = new \ReflectionClass(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::class);
320
321 $property = $reflectionClass->getProperty('LOCAL_LANG');
322 $property->setAccessible(true);
323 $property->setValue($this->LOCAL_LANG);
324
325 $this->assertEquals($expected, LocalizationUtility::translate($key, 'core', $arguments, $languageKey, $altLanguageKeys));
326 }
327
328 /**
329 * @return array
330 */
331 public function loadTypoScriptLabelsProvider()
332 {
333 return [
334 'override labels with typoscript' => [
335 'LOCAL_LANG' => [
336 $this->getLanguageFilePath('core') => [
337 'dk' => [
338 'key1' => [
339 [
340 'source' => 'English label for key1',
341 'target' => 'Dansk label for key1 core',
342 ]
343 ],
344 'key2' => [
345 [
346 'source' => 'English label for key2',
347 ]
348 ],
349 'key3.subkey1' => [
350 [
351 'source' => 'English label for key3',
352 ]
353 ],
354 ],
355 ],
356 $this->getLanguageFilePath('backend') => [
357 'dk' => [
358 'key1' => [
359 [
360 'source' => 'English label for key1',
361 'target' => 'Dansk label for key1 backend',
362 ]
363 ],
364 'key2' => [
365 [
366 'source' => 'English label for key2',
367 ]
368 ],
369 'key3.subkey1' => [
370 [
371 'source' => 'English label for key3',
372 ]
373 ],
374 ],
375 ],
376 ],
377 'typoscript LOCAL_LANG' => [
378 '_LOCAL_LANG' => [
379 'dk' => [
380 'key1' => 'key1 value from TS core',
381 'key3' => [
382 'subkey1' => 'key3.subkey1 value from TS core',
383 // this key doesn't exist in xml files
384 'subkey2' => [
385 'subsubkey' => 'key3.subkey2.subsubkey value from TS core'
386 ]
387 ]
388 ]
389 ]
390 ],
391 'language key' => 'dk',
392 'expected' => [
393 'key1' => [
394 [
395 'source' => 'English label for key1',
396 'target' => 'key1 value from TS core',
397 ]
398 ],
399 'key2' => [
400 [
401 'source' => 'English label for key2',
402 ]
403 ],
404 'key3.subkey1' => [
405 [
406 'source' => 'English label for key3',
407 'target' => 'key3.subkey1 value from TS core',
408 ]
409 ],
410 'key3.subkey2.subsubkey' => [
411 [
412 'target' => 'key3.subkey2.subsubkey value from TS core',
413 ]
414 ],
415 ],
416 ]
417 ];
418 }
419
420 /**
421 * Tests whether labels from xml are overwritten by TypoScript labels
422 *
423 * @param array $LOCAL_LANG
424 * @param array $typoScriptLocalLang
425 * @param string $languageKey
426 * @param array $expected
427 * @dataProvider loadTypoScriptLabelsProvider
428 * @test
429 */
430 public function loadTypoScriptLabels(array $LOCAL_LANG, array $typoScriptLocalLang, $languageKey, array $expected)
431 {
432 $reflectionClass = new \ReflectionClass(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::class);
433
434 $property = $reflectionClass->getProperty('LOCAL_LANG');
435 $property->setAccessible(true);
436 $property->setValue($LOCAL_LANG);
437
438 $configurationType = \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK;
439 $this->configurationManager->expects($this->at(0))->method('getConfiguration')->with($configurationType, 'core', null)->will($this->returnValue($typoScriptLocalLang));
440
441 $method = $reflectionClass->getMethod('loadTypoScriptLabels');
442 $method->setAccessible(true);
443 $method->invoke(null, 'core', $this->languageFilePath);
444
445 $property = $reflectionClass->getProperty('LOCAL_LANG');
446 $property->setAccessible(true);
447 $result = $property->getValue();
448
449 $this->assertEquals($expected, $result[$this->languageFilePath][$languageKey]);
450 }
451
452 /**
453 * @test
454 */
455 public function clearLabelWithTypoScript()
456 {
457 $reflectionClass = new \ReflectionClass(\TYPO3\CMS\Extbase\Utility\LocalizationUtility::class);
458
459 $property = $reflectionClass->getProperty('LOCAL_LANG');
460 $property->setAccessible(true);
461 $property->setValue($this->LOCAL_LANG);
462
463 $typoScriptLocalLang = [
464 '_LOCAL_LANG' => [
465 'dk' => [
466 'key1' => '',
467 ]
468 ]
469 ];
470
471 $configurationType = \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK;
472 $this->configurationManager->expects($this->at(0))->method('getConfiguration')->with($configurationType, 'core', null)->will($this->returnValue($typoScriptLocalLang));
473
474 $method = $reflectionClass->getMethod('loadTypoScriptLabels');
475 $method->setAccessible(true);
476 $method->invoke(null, 'core', $this->languageFilePath);
477
478 $result = LocalizationUtility::translate('key1', 'core', null, 'dk');
479 $this->assertNotNull($result);
480 $this->assertEquals('', $result);
481 }
482
483 /**
484 * Tests whether method can be invoked without second parameter. Actual translation is not tested here.
485 *
486 * @test
487 */
488 public function translateWithFullyQualifiedKey()
489 {
490 $result = LocalizationUtility::translate('LLL:EXT:extbase/Resources/Private/Language/locallang_db.xlf:fe_users.tx_extbase_type');
491 $this->assertNotEmpty($result);
492 }
493
494 /**
495 * @test
496 */
497 public function translateThrowsExceptionWithEmptyExtensionNameIfKeyIsNotPrefixedWithLLL()
498 {
499 $this->expectException(\InvalidArgumentException::class);
500 $this->expectExceptionCode(1498144052);
501 LocalizationUtility::translate('foo/bar', '');
502 }
503 }