Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / locale / tests / src / Unit / LocaleLookupTest.php
1 <?php
2
3 namespace Drupal\Tests\locale\Unit;
4
5 use Drupal\Core\DependencyInjection\ContainerBuilder;
6 use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
7 use Drupal\locale\LocaleLookup;
8 use Drupal\Tests\UnitTestCase;
9 use Symfony\Component\HttpFoundation\Request;
10 use Symfony\Component\HttpFoundation\RequestStack;
11
12 /**
13  * @coversDefaultClass \Drupal\locale\LocaleLookup
14  * @group locale
15  */
16 class LocaleLookupTest extends UnitTestCase {
17
18   /**
19    * A mocked storage to use when instantiating LocaleTranslation objects.
20    *
21    * @var \Drupal\locale\StringStorageInterface|\PHPUnit_Framework_MockObject_MockObject
22    */
23   protected $storage;
24
25   /**
26    * A mocked cache object.
27    *
28    * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
29    */
30   protected $cache;
31
32   /**
33    * A mocked lock object.
34    *
35    * @var \Drupal\Core\Lock\LockBackendInterface|\PHPUnit_Framework_MockObject_MockObject
36    */
37   protected $lock;
38
39   /**
40    * A mocked user object built from AccountInterface.
41    *
42    * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
43    */
44   protected $user;
45
46   /**
47    * A mocked config factory built with UnitTestCase::getConfigFactoryStub().
48    *
49    * @var \Drupal\Core\Config\ConfigFactory|\PHPUnit_Framework_MockObject_MockBuilder
50    */
51   protected $configFactory;
52
53   /**
54    * A mocked language manager built from LanguageManagerInterface.
55    *
56    * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
57    */
58   protected $languageManager;
59
60   /**
61    * The request stack.
62    *
63    * @var \Symfony\Component\HttpFoundation\RequestStack
64    */
65   protected $requestStack;
66
67   /**
68    * {@inheritdoc}
69    */
70   protected function setUp() {
71     $this->storage = $this->getMock('Drupal\locale\StringStorageInterface');
72     $this->cache = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
73     $this->lock = $this->getMock('Drupal\Core\Lock\LockBackendInterface');
74     $this->lock->expects($this->never())
75       ->method($this->anything());
76
77     $this->user = $this->getMock('Drupal\Core\Session\AccountInterface');
78     $this->user->expects($this->any())
79       ->method('getRoles')
80       ->will($this->returnValue(['anonymous']));
81
82     $this->configFactory = $this->getConfigFactoryStub(['locale.settings' => ['cache_strings' => FALSE]]);
83
84     $this->languageManager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
85     $this->requestStack = new RequestStack();
86
87     $container = new ContainerBuilder();
88     $container->set('current_user', $this->user);
89     \Drupal::setContainer($container);
90   }
91
92   /**
93    * Tests locale lookups without fallback.
94    *
95    * @covers ::resolveCacheMiss
96    */
97   public function testResolveCacheMissWithoutFallback() {
98     $args = [
99       'language' => 'en',
100       'source' => 'test',
101       'context' => 'irrelevant',
102     ];
103
104     $result = (object) [
105       'translation' => 'test',
106     ];
107
108     $this->cache->expects($this->once())
109       ->method('get')
110       ->with('locale:en:irrelevant:anonymous', FALSE);
111
112     $this->storage->expects($this->once())
113       ->method('findTranslation')
114       ->with($this->equalTo($args))
115       ->will($this->returnValue($result));
116
117     $locale_lookup = $this->getMockBuilder('Drupal\locale\LocaleLookup')
118       ->setConstructorArgs(['en', 'irrelevant', $this->storage, $this->cache, $this->lock, $this->configFactory, $this->languageManager, $this->requestStack])
119       ->setMethods(['persist'])
120       ->getMock();
121     $locale_lookup->expects($this->never())
122       ->method('persist');
123     $this->assertSame('test', $locale_lookup->get('test'));
124   }
125
126   /**
127    * Tests locale lookups with fallback.
128    *
129    * Note that context is irrelevant here. It is not used but it is required.
130    *
131    * @covers ::resolveCacheMiss
132    *
133    * @dataProvider resolveCacheMissWithFallbackProvider
134    */
135   public function testResolveCacheMissWithFallback($langcode, $string, $context, $expected) {
136     // These are fake words!
137     $translations = [
138       'en' => [
139         'test' => 'test',
140         'fake' => 'fake',
141         'missing pl' => 'missing pl',
142         'missing cs' => 'missing cs',
143         'missing both' => 'missing both',
144       ],
145       'pl' => [
146         'test' => 'test po polsku',
147         'fake' => 'ściema',
148         'missing cs' => 'zaginiony czech',
149       ],
150       'cs' => [
151         'test' => 'test v české',
152         'fake' => 'falešný',
153         'missing pl' => 'chybějící pl',
154       ],
155     ];
156     $this->storage->expects($this->any())
157       ->method('findTranslation')
158       ->will($this->returnCallback(function ($argument) use ($translations) {
159         if (isset($translations[$argument['language']][$argument['source']])) {
160           return (object) ['translation' => $translations[$argument['language']][$argument['source']]];
161         }
162         return TRUE;
163       }));
164
165     $this->languageManager->expects($this->any())
166       ->method('getFallbackCandidates')
167       ->will($this->returnCallback(function (array $context = []) {
168         switch ($context['langcode']) {
169           case 'pl':
170             return ['cs', 'en'];
171
172           case 'cs':
173             return ['en'];
174
175           default:
176             return [];
177         }
178       }));
179
180     $this->cache->expects($this->once())
181       ->method('get')
182       ->with('locale:' . $langcode . ':' . $context . ':anonymous', FALSE);
183
184     $locale_lookup = new LocaleLookup($langcode, $context, $this->storage, $this->cache, $this->lock, $this->configFactory, $this->languageManager, $this->requestStack);
185     $this->assertSame($expected, $locale_lookup->get($string));
186   }
187
188   /**
189    * Provides test data for testResolveCacheMissWithFallback().
190    */
191   public function resolveCacheMissWithFallbackProvider() {
192     return [
193       ['cs', 'test', 'irrelevant', 'test v české'],
194       ['cs', 'fake', 'irrelevant', 'falešný'],
195       ['cs', 'missing pl', 'irrelevant', 'chybějící pl'],
196       ['cs', 'missing cs', 'irrelevant', 'missing cs'],
197       ['cs', 'missing both', 'irrelevant', 'missing both'],
198
199       // Testing PL with fallback to cs, en.
200       ['pl', 'test', 'irrelevant', 'test po polsku'],
201       ['pl', 'fake', 'irrelevant', 'ściema'],
202       ['pl', 'missing pl', 'irrelevant', 'chybějící pl'],
203       ['pl', 'missing cs', 'irrelevant', 'zaginiony czech'],
204       ['pl', 'missing both', 'irrelevant', 'missing both'],
205     ];
206   }
207
208   /**
209    * Tests locale lookups with persistent tracking.
210    *
211    * @covers ::resolveCacheMiss
212    */
213   public function testResolveCacheMissWithPersist() {
214     $args = [
215       'language' => 'en',
216       'source' => 'test',
217       'context' => 'irrelevant',
218     ];
219
220     $result = (object) [
221       'translation' => 'test',
222     ];
223
224     $this->storage->expects($this->once())
225       ->method('findTranslation')
226       ->with($this->equalTo($args))
227       ->will($this->returnValue($result));
228
229     $this->configFactory = $this->getConfigFactoryStub(['locale.settings' => ['cache_strings' => TRUE]]);
230     $locale_lookup = $this->getMockBuilder('Drupal\locale\LocaleLookup')
231       ->setConstructorArgs(['en', 'irrelevant', $this->storage, $this->cache, $this->lock, $this->configFactory, $this->languageManager, $this->requestStack])
232       ->setMethods(['persist'])
233       ->getMock();
234     $locale_lookup->expects($this->once())
235       ->method('persist');
236
237     $this->assertSame('test', $locale_lookup->get('test'));
238   }
239
240   /**
241    * Tests locale lookups without a found translation.
242    *
243    * @covers ::resolveCacheMiss
244    */
245   public function testResolveCacheMissNoTranslation() {
246     $string = $this->getMock('Drupal\locale\StringInterface');
247     $string->expects($this->once())
248       ->method('addLocation')
249       ->will($this->returnSelf());
250     $this->storage->expects($this->once())
251       ->method('findTranslation')
252       ->will($this->returnValue(NULL));
253     $this->storage->expects($this->once())
254       ->method('createString')
255       ->will($this->returnValue($string));
256
257     $request = Request::create('/test');
258     $this->requestStack->push($request);
259
260     $locale_lookup = $this->getMockBuilder('Drupal\locale\LocaleLookup')
261       ->setConstructorArgs(['en', 'irrelevant', $this->storage, $this->cache, $this->lock, $this->configFactory, $this->languageManager, $this->requestStack])
262       ->setMethods(['persist'])
263       ->getMock();
264     $locale_lookup->expects($this->never())
265       ->method('persist');
266
267     $this->assertTrue($locale_lookup->get('test'));
268   }
269
270   /**
271    * Tests locale lookups with old plural style of translations.
272    *
273    * @param array $translations
274    *   The source with translations.
275    * @param string $langcode
276    *   The language code of translation string.
277    * @param string $string
278    *   The string for translation.
279    * @param bool $is_fix
280    *   The flag about expected fix translation.
281    *
282    * @covers ::resolveCacheMiss
283    * @dataProvider providerFixOldPluralTranslationProvider
284    */
285   public function testFixOldPluralStyleTranslations($translations, $langcode, $string, $is_fix) {
286     $this->storage->expects($this->any())
287       ->method('findTranslation')
288       ->will($this->returnCallback(function ($argument) use ($translations) {
289         if (isset($translations[$argument['language']][$argument['source']])) {
290           return (object) ['translation' => $translations[$argument['language']][$argument['source']]];
291         }
292         return TRUE;
293       }));
294     $this->languageManager->expects($this->any())
295       ->method('getFallbackCandidates')
296       ->will($this->returnCallback(function (array $context = []) {
297         switch ($context['langcode']) {
298           case 'by':
299             return ['ru'];
300         }
301       }));
302     $this->cache->expects($this->once())
303       ->method('get')
304       ->with('locale:' . $langcode . '::anonymous', FALSE);
305
306     $locale_lookup = new LocaleLookup($langcode, '', $this->storage, $this->cache, $this->lock, $this->configFactory, $this->languageManager, $this->requestStack);
307     $this->assertSame($is_fix, strpos($locale_lookup->get($string), '@count[2]') === FALSE);
308   }
309
310   /**
311    * Provides test data for testResolveCacheMissWithFallback().
312    */
313   public function providerFixOldPluralTranslationProvider() {
314     $translations = [
315       'by' => [
316         'word1' => '@count[2] word-by',
317         'word2' => implode(PluralTranslatableMarkup::DELIMITER, ['word-by', '@count[2] word-by']),
318       ],
319       'ru' => [
320         'word3' => '@count[2] word-ru',
321         'word4' => implode(PluralTranslatableMarkup::DELIMITER, ['word-ru', '@count[2] word-ru']),
322       ],
323     ];
324     return [
325       'no-plural' => [$translations, 'by', 'word1', FALSE],
326       'no-plural from other language' => [$translations, 'by', 'word3', FALSE],
327       'plural' => [$translations, 'by', 'word2', TRUE],
328       'plural from other language' => [$translations, 'by', 'word4', TRUE],
329     ];
330   }
331
332 }