Backup of db before drupal security update
[yaffs-website] / web / core / modules / locale / tests / src / Kernel / LocaleConfigSubscriberTest.php
1 <?php
2
3 namespace Drupal\Tests\locale\Kernel;
4
5 use Drupal\language\Entity\ConfigurableLanguage;
6 use Drupal\locale\Locale;
7 use Drupal\locale\StringInterface;
8 use Drupal\locale\TranslationString;
9 use Drupal\KernelTests\KernelTestBase;
10
11 /**
12  * Tests that shipped configuration translations are updated correctly.
13  *
14  * @group locale
15  */
16 class LocaleConfigSubscriberTest extends KernelTestBase {
17
18   /**
19    * {@inheritdoc}
20    */
21   public static $modules = ['language', 'locale', 'system', 'locale_test'];
22
23   /**
24    * The configurable language manager used in this test.
25    *
26    * @var \Drupal\language\ConfigurableLanguageManagerInterface
27    */
28   protected $languageManager;
29
30   /**
31    * The configuration factory used in this test.
32    *
33    * @var \Drupal\Core\Config\ConfigFactoryInterface
34    */
35   protected $configFactory;
36
37   /**
38    * The string storage used in this test.
39    *
40    * @var \Drupal\locale\StringStorageInterface;
41    */
42   protected $stringStorage;
43
44   /**
45    * The locale configuration manager used in this test.
46    *
47    * @var \Drupal\locale\LocaleConfigManager
48    */
49   protected $localeConfigManager;
50
51   /**
52    * {@inheritdoc}
53    */
54   protected function setUp() {
55     parent::setUp();
56
57     $this->setUpDefaultLanguage();
58
59     $this->installSchema('locale', ['locales_source', 'locales_target', 'locales_location']);
60
61     $this->setupLanguages();
62
63     $this->installConfig(['locale_test']);
64     // Simulate this hook invoked which would happen if in a non-kernel test
65     // or normal environment.
66     // @see locale_modules_installed()
67     // @see locale_system_update()
68     locale_system_set_config_langcodes();
69     $langcodes = array_keys(\Drupal::languageManager()->getLanguages());
70     $names = Locale::config()->getComponentNames();
71     Locale::config()->updateConfigTranslations($names, $langcodes);
72
73     $this->configFactory = $this->container->get('config.factory');
74     $this->stringStorage = $this->container->get('locale.storage');
75     $this->localeConfigManager = $this->container->get('locale.config_manager');
76     $this->languageManager = $this->container->get('language_manager');
77
78     $this->setUpLocale();
79   }
80
81   /**
82    * Sets up default language for this test.
83    */
84   protected function setUpDefaultLanguage() {
85     // Keep the default English.
86   }
87
88   /**
89    * Sets up languages needed for this test.
90    */
91   protected function setUpLanguages() {
92     ConfigurableLanguage::createFromLangcode('de')->save();
93   }
94
95   /**
96    * Sets up the locale storage strings to be in line with configuration.
97    */
98   protected function setUpLocale() {
99     // Set up the locale database the same way we have in the config samples.
100     $this->setUpNoTranslation('locale_test.no_translation', 'test', 'Test', 'de');
101     $this->setUpTranslation('locale_test.translation', 'test', 'English test', 'German test', 'de');
102   }
103
104   /**
105    * Tests creating translations of shipped configuration.
106    */
107   public function testCreateTranslation() {
108     $config_name = 'locale_test.no_translation';
109
110     $this->saveLanguageOverride($config_name, 'test', 'Test (German)', 'de');
111     $this->assertTranslation($config_name, 'Test (German)', 'de');
112   }
113
114   /**
115    * Tests importing community translations of shipped configuration.
116    */
117   public function testLocaleCreateTranslation() {
118     $config_name = 'locale_test.no_translation';
119
120     $this->saveLocaleTranslationData($config_name, 'test', 'Test', 'Test (German)', 'de');
121     $this->assertTranslation($config_name, 'Test (German)', 'de', FALSE);
122   }
123
124   /**
125    * Tests updating translations of shipped configuration.
126    */
127   public function testUpdateTranslation() {
128     $config_name = 'locale_test.translation';
129
130     $this->saveLanguageOverride($config_name, 'test', 'Updated German test', 'de');
131     $this->assertTranslation($config_name, 'Updated German test', 'de');
132   }
133
134   /**
135    * Tests updating community translations of shipped configuration.
136    */
137   public function testLocaleUpdateTranslation() {
138     $config_name = 'locale_test.translation';
139
140     $this->saveLocaleTranslationData($config_name, 'test', 'English test', 'Updated German test', 'de');
141     $this->assertTranslation($config_name, 'Updated German test', 'de', FALSE);
142   }
143
144   /**
145    * Tests deleting translations of shipped configuration.
146    */
147   public function testDeleteTranslation() {
148     $config_name = 'locale_test.translation';
149
150     $this->deleteLanguageOverride($config_name, 'test', 'English test', 'de');
151     // Instead of deleting the translation, we need to keep a translation with
152     // the source value and mark it as customized to prevent the deletion being
153     // reverted by importing community translations.
154     $this->assertTranslation($config_name, 'English test', 'de');
155   }
156
157   /**
158    * Tests deleting community translations of shipped configuration.
159    */
160   public function testLocaleDeleteTranslation() {
161     $config_name = 'locale_test.translation';
162
163     $this->deleteLocaleTranslationData($config_name, 'test', 'English test', 'de');
164     $this->assertNoTranslation($config_name, 'de');
165   }
166
167   /**
168    * Sets up a configuration string without a translation.
169    *
170    * The actual configuration is already available by installing locale_test
171    * module, as it is done in LocaleConfigSubscriberTest::setUp(). This sets up
172    * the necessary source string and verifies that everything is as expected to
173    * avoid false positives.
174    *
175    * @param string $config_name
176    *   The configuration name.
177    * @param string $key
178    *   The configuration key.
179    * @param string $source
180    *   The source string.
181    * @param string $langcode
182    *   The language code.
183    */
184   protected function setUpNoTranslation($config_name, $key, $source, $langcode) {
185     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
186     $this->assertNoConfigOverride($config_name, $key, $source, $langcode);
187     $this->assertNoTranslation($config_name, $langcode);
188   }
189
190
191   /**
192    * Sets up a configuration string with a translation.
193    *
194    * The actual configuration is already available by installing locale_test
195    * module, as it is done in LocaleConfigSubscriberTest::setUp(). This sets up
196    * the necessary source and translation strings and verifies that everything
197    * is as expected to avoid false positives.
198    *
199    * @param string $config_name
200    *   The configuration name.
201    * @param string $key
202    *   The configuration key.
203    * @param string $source
204    *   The source string.
205    * @param string $translation
206    *   The translation string.
207    * @param string $langcode
208    *   The language code.
209    * @param bool $is_active
210    *   Whether the update will affect the active configuration.
211    */
212   protected function setUpTranslation($config_name, $key, $source, $translation, $langcode, $is_active = FALSE) {
213     // Create source and translation strings for the configuration value and add
214     // the configuration name as a location. This would be performed by
215     // locale_translate_batch_import() invoking
216     // LocaleConfigManager::updateConfigTranslations() normally.
217     $this->localeConfigManager->reset();
218     $this->localeConfigManager
219       ->getStringTranslation($config_name, $langcode, $source, '')
220       ->setString($translation)
221       ->setCustomized(FALSE)
222       ->save();
223     $this->configFactory->reset($config_name);
224     $this->localeConfigManager->reset();
225     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
226
227     if ($is_active) {
228       $this->assertActiveConfig($config_name, $key, $translation, $langcode);
229     }
230     else {
231       $this->assertConfigOverride($config_name, $key, $translation, $langcode);
232     }
233     $this->assertTranslation($config_name, $translation, $langcode, FALSE);
234   }
235
236   /**
237    * Saves a language override.
238    *
239    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
240    * make sure the configuration was persisted correctly, the configuration
241    * value is checked. Because LocaleConfigSubscriber temporarily disables the
242    * override state of the configuration factory we check that the correct value
243    * is restored afterwards.
244    *
245    * @param string $config_name
246    *   The configuration name.
247    * @param string $key
248    *   The configuration key.
249    * @param string $value
250    *   The configuration value to save.
251    * @param string $langcode
252    *   The language code.
253    */
254   protected function saveLanguageOverride($config_name, $key, $value, $langcode) {
255     $translation_override = $this->languageManager
256       ->getLanguageConfigOverride($langcode, $config_name);
257     $translation_override
258       ->set($key, $value)
259       ->save();
260     $this->configFactory->reset($config_name);
261
262     $this->assertConfigOverride($config_name, $key, $value, $langcode);
263   }
264
265   /**
266    * Saves translation data from locale module.
267    *
268    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
269    * make sure the configuration was persisted correctly, the configuration
270    * value is checked. Because LocaleConfigSubscriber temporarily disables the
271    * override state of the configuration factory we check that the correct value
272    * is restored afterwards.
273    *
274    * @param string $config_name
275    *   The configuration name.
276    * @param string $key
277    *   The configuration key.
278    * @param string $source
279    *   The source string.
280    * @param string $translation
281    *   The translation string to save.
282    * @param string $langcode
283    *   The language code.
284    * @param bool $is_active
285    *   Whether the update will affect the active configuration.
286    */
287   protected function saveLocaleTranslationData($config_name, $key, $source, $translation, $langcode, $is_active = FALSE) {
288     $this->localeConfigManager->reset();
289     $this->localeConfigManager
290       ->getStringTranslation($config_name, $langcode, $source, '')
291       ->setString($translation)
292       ->save();
293     $this->localeConfigManager->reset();
294     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
295     $this->configFactory->reset($config_name);
296
297     if ($is_active) {
298       $this->assertActiveConfig($config_name, $key, $translation, $langcode);
299     }
300     else {
301       $this->assertConfigOverride($config_name, $key, $translation, $langcode);
302     }
303   }
304
305   /**
306    * Deletes a language override.
307    *
308    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
309    * make sure the configuration was persisted correctly, the configuration
310    * value is checked. Because LocaleConfigSubscriber temporarily disables the
311    * override state of the configuration factory we check that the correct value
312    * is restored afterwards.
313    *
314    * @param string $config_name
315    *   The configuration name.
316    * @param string $key
317    *   The configuration key.
318    * @param string $source_value
319    *   The source configuration value to verify the correct value is returned
320    *   from the configuration factory after the deletion.
321    * @param string $langcode
322    *   The language code.
323    */
324   protected function deleteLanguageOverride($config_name, $key, $source_value, $langcode) {
325     $translation_override = $this->languageManager
326       ->getLanguageConfigOverride($langcode, $config_name);
327     $translation_override
328       ->clear($key)
329       ->save();
330     $this->configFactory->reset($config_name);
331
332     $this->assertNoConfigOverride($config_name, $key, $source_value, $langcode);
333   }
334
335   /**
336    * Deletes translation data from locale module.
337    *
338    * This will invoke LocaleConfigSubscriber through the event dispatcher. To
339    * make sure the configuration was persisted correctly, the configuration
340    * value is checked. Because LocaleConfigSubscriber temporarily disables the
341    * override state of the configuration factory we check that the correct value
342    * is restored afterwards.
343    *
344    * @param string $config_name
345    *   The configuration name.
346    * @param string $key
347    *   The configuration key.
348    * @param string $source_value
349    *   The source configuration value to verify the correct value is returned
350    *   from the configuration factory after the deletion.
351    * @param string $langcode
352    *   The language code.
353    */
354   protected function deleteLocaleTranslationData($config_name, $key, $source_value, $langcode) {
355     $this->localeConfigManager
356       ->getStringTranslation($config_name, $langcode, $source_value, '')
357       ->delete();
358     $this->localeConfigManager->reset();
359     $this->localeConfigManager->updateConfigTranslations([$config_name], [$langcode]);
360     $this->configFactory->reset($config_name);
361
362     $this->assertNoConfigOverride($config_name, $key, $source_value, $langcode);
363   }
364
365   /**
366    * Ensures configuration override is not present anymore.
367    *
368    * @param string $config_name
369    *   The configuration name.
370    * @param string $langcode
371    *   The language code.
372    *
373    * @return bool
374    *   TRUE if the assertion succeeded, FALSE otherwise.
375    */
376   protected function assertNoConfigOverride($config_name, $langcode) {
377     $config_langcode = $this->configFactory->getEditable($config_name)->get('langcode');
378     $override = $this->languageManager->getLanguageConfigOverride($langcode, $config_name);
379     return $this->assertNotEqual($config_langcode, $langcode) && $this->assertEqual($override->isNew(), TRUE);
380   }
381
382   /**
383    * Ensures configuration was saved correctly.
384    *
385    * @param string $config_name
386    *   The configuration name.
387    * @param string $key
388    *   The configuration key.
389    * @param string $value
390    *   The configuration value.
391    * @param string $langcode
392    *   The language code.
393    *
394    * @return bool
395    *   TRUE if the assertion succeeded, FALSE otherwise.
396    */
397   protected function assertConfigOverride($config_name, $key, $value, $langcode) {
398     $config_langcode = $this->configFactory->getEditable($config_name)->get('langcode');
399     $override = $this->languageManager->getLanguageConfigOverride($langcode, $config_name);
400     return $this->assertNotEqual($config_langcode, $langcode) && $this->assertEqual($override->get($key), $value);
401   }
402
403   /**
404    * Ensures configuration was saved correctly.
405    *
406    * @param string $config_name
407    *   The configuration name.
408    * @param string $key
409    *   The configuration key.
410    * @param string $value
411    *   The configuration value.
412    * @param string $langcode
413    *   The language code.
414    *
415    * @return bool
416    *   TRUE if the assertion succeeded, FALSE otherwise.
417    */
418   protected function assertActiveConfig($config_name, $key, $value, $langcode) {
419     $config = $this->configFactory->getEditable($config_name);
420     return
421       $this->assertEqual($config->get('langcode'), $langcode) &&
422       $this->assertIdentical($config->get($key), $value);
423   }
424
425   /**
426    * Ensures no translation exists.
427    *
428    * @param string $config_name
429    *   The configuration name.
430    * @param string $langcode
431    *   The language code.
432    *
433    * @return bool
434    *   TRUE if the assertion succeeded, FALSE otherwise.
435    */
436   protected function assertNoTranslation($config_name, $langcode) {
437     $strings = $this->stringStorage->getTranslations([
438       'type' => 'configuration',
439       'name' => $config_name,
440       'language' => $langcode,
441       'translated' => TRUE,
442     ]);
443     return $this->assertIdentical([], $strings);
444   }
445
446   /**
447    * Ensures a translation exists and is marked as customized.
448    *
449    * @param string $config_name
450    *   The configuration name.
451    * @param string $translation
452    *   The translation.
453    * @param string $langcode
454    *   The language code.
455    * @param bool $customized
456    *   Whether or not the string should be asserted to be customized or not
457    *   customized.
458    *
459    * @return bool
460    *   TRUE if the assertion succeeded, FALSE otherwise.
461    */
462   protected function assertTranslation($config_name, $translation, $langcode, $customized = TRUE) {
463     // Make sure a string exists.
464     $strings = $this->stringStorage->getTranslations([
465       'type' => 'configuration',
466       'name' => $config_name,
467       'language' => $langcode,
468       'translated' => TRUE,
469     ]);
470     $pass = $this->assertIdentical(1, count($strings));
471     $string = reset($strings);
472     if ($this->assertTrue($string instanceof StringInterface)) {
473       /** @var \Drupal\locale\StringInterface $string */
474       $pass = $pass && $this->assertIdentical($translation, $string->getString());
475       $pass = $pass && $this->assertTrue($string->isTranslation());
476       if ($this->assertTrue($string instanceof TranslationString)) {
477         /** @var \Drupal\locale\TranslationString $string */
478         // Make sure the string is marked as customized so that it does not get
479         // overridden when the string translations are updated.
480         return $pass && $this->assertEqual($customized, $string->customized);
481       }
482     }
483     return FALSE;
484   }
485
486 }