Skip to content

Commit 5cb5e09

Browse files
fix tests
1 parent aba5c4b commit 5cb5e09

File tree

1 file changed

+353
-0
lines changed

1 file changed

+353
-0
lines changed

Test/TranslatorTest.php

Lines changed: 353 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,353 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\Translation\Test;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Contracts\Translation\TranslatorInterface;
16+
use Symfony\Contracts\Translation\TranslatorTrait;
17+
18+
/**
19+
* Test should cover all languages mentioned on http://translate.sourceforge.net/wiki/l10n/pluralforms
20+
* and Plural forms mentioned on http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms.
21+
*
22+
* See also https://developer.mozilla.org/en/Localization_and_Plurals which mentions 15 rules having a maximum of 6 forms.
23+
* The mozilla code is also interesting to check for.
24+
*
25+
* As mentioned by chx http://drupal.org/node/1273968 we can cover all by testing number from 0 to 199
26+
*
27+
* The goal to cover all languages is to far fetched so this test case is smaller.
28+
*
29+
* @author Clemens Tolboom [email protected]
30+
*/
31+
class TranslatorTest extends TestCase
32+
{
33+
public function getTranslator()
34+
{
35+
return new class() implements TranslatorInterface {
36+
use TranslatorTrait;
37+
};
38+
}
39+
40+
/**
41+
* @dataProvider getTransTests
42+
*/
43+
public function testTrans($expected, $id, $parameters)
44+
{
45+
$translator = $this->getTranslator();
46+
47+
$this->assertEquals($expected, $translator->trans($id, $parameters));
48+
}
49+
50+
/**
51+
* @dataProvider getTransChoiceTests
52+
*/
53+
public function testTransChoiceWithExplicitLocale($expected, $id, $number)
54+
{
55+
$translator = $this->getTranslator();
56+
$translator->setLocale('en');
57+
58+
$this->assertEquals($expected, $translator->trans($id, ['%count%' => $number]));
59+
}
60+
61+
/**
62+
* @dataProvider getTransChoiceTests
63+
*/
64+
public function testTransChoiceWithDefaultLocale($expected, $id, $number)
65+
{
66+
\Locale::setDefault('en');
67+
68+
$translator = $this->getTranslator();
69+
70+
$this->assertEquals($expected, $translator->trans($id, ['%count%' => $number]));
71+
}
72+
73+
public function testGetSetLocale()
74+
{
75+
$translator = $this->getTranslator();
76+
$translator->setLocale('en');
77+
78+
$this->assertEquals('en', $translator->getLocale());
79+
}
80+
81+
/**
82+
* @requires extension intl
83+
*/
84+
public function testGetLocaleReturnsDefaultLocaleIfNotSet()
85+
{
86+
$translator = $this->getTranslator();
87+
88+
\Locale::setDefault('pt_BR');
89+
$this->assertEquals('pt_BR', $translator->getLocale());
90+
91+
\Locale::setDefault('en');
92+
$this->assertEquals('en', $translator->getLocale());
93+
}
94+
95+
public function getTransTests()
96+
{
97+
return [
98+
['Symfony is great!', 'Symfony is great!', []],
99+
['Symfony is awesome!', 'Symfony is %what%!', ['%what%' => 'awesome']],
100+
];
101+
}
102+
103+
public function getTransChoiceTests()
104+
{
105+
return [
106+
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
107+
['There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1],
108+
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
109+
['There are 0 apples', 'There is 1 apple|There are %count% apples', 0],
110+
['There is 1 apple', 'There is 1 apple|There are %count% apples', 1],
111+
['There are 10 apples', 'There is 1 apple|There are %count% apples', 10],
112+
// custom validation messages may be coded with a fixed value
113+
['There are 2 apples', 'There are 2 apples', 2],
114+
];
115+
}
116+
117+
/**
118+
* @dataProvider getInternal
119+
*/
120+
public function testInterval($expected, $number, $interval)
121+
{
122+
$translator = $this->getTranslator();
123+
124+
$this->assertEquals($expected, $translator->trans($interval.' foo|[1,Inf[ bar', ['%count%' => $number]));
125+
}
126+
127+
public function getInternal()
128+
{
129+
return [
130+
['foo', 3, '{1,2, 3 ,4}'],
131+
['bar', 10, '{1,2, 3 ,4}'],
132+
['bar', 3, '[1,2]'],
133+
['foo', 1, '[1,2]'],
134+
['foo', 2, '[1,2]'],
135+
['bar', 1, ']1,2['],
136+
['bar', 2, ']1,2['],
137+
['foo', log(0), '[-Inf,2['],
138+
['foo', -log(0), '[-2,+Inf]'],
139+
];
140+
}
141+
142+
/**
143+
* @dataProvider getChooseTests
144+
*/
145+
public function testChoose($expected, $id, $number)
146+
{
147+
$translator = $this->getTranslator();
148+
149+
$this->assertEquals($expected, $translator->trans($id, ['%count%' => $number]));
150+
}
151+
152+
public function testReturnMessageIfExactlyOneStandardRuleIsGiven()
153+
{
154+
$translator = $this->getTranslator();
155+
156+
$this->assertEquals('There are two apples', $translator->trans('There are two apples', ['%count%' => 2]));
157+
}
158+
159+
/**
160+
* @dataProvider getNonMatchingMessages
161+
* @expectedException \InvalidArgumentException
162+
*/
163+
public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number)
164+
{
165+
$translator = $this->getTranslator();
166+
167+
$translator->trans($id, ['%count%' => $number]);
168+
}
169+
170+
public function getNonMatchingMessages()
171+
{
172+
return [
173+
['{0} There are no apples|{1} There is one apple', 2],
174+
['{1} There is one apple|]1,Inf] There are %count% apples', 0],
175+
['{1} There is one apple|]2,Inf] There are %count% apples', 2],
176+
['{0} There are no apples|There is one apple', 2],
177+
];
178+
}
179+
180+
public function getChooseTests()
181+
{
182+
return [
183+
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
184+
['There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
185+
['There are no apples', '{0}There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0],
186+
187+
['There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1],
188+
189+
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
190+
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf]There are %count% apples', 10],
191+
['There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10],
192+
193+
['There are 0 apples', 'There is one apple|There are %count% apples', 0],
194+
['There is one apple', 'There is one apple|There are %count% apples', 1],
195+
['There are 10 apples', 'There is one apple|There are %count% apples', 10],
196+
197+
['There are 0 apples', 'one: There is one apple|more: There are %count% apples', 0],
198+
['There is one apple', 'one: There is one apple|more: There are %count% apples', 1],
199+
['There are 10 apples', 'one: There is one apple|more: There are %count% apples', 10],
200+
201+
['There are no apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 0],
202+
['There is one apple', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 1],
203+
['There are 10 apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 10],
204+
205+
['', '{0}|{1} There is one apple|]1,Inf] There are %count% apples', 0],
206+
['', '{0} There are no apples|{1}|]1,Inf] There are %count% apples', 1],
207+
208+
// Indexed only tests which are Gettext PoFile* compatible strings.
209+
['There are 0 apples', 'There is one apple|There are %count% apples', 0],
210+
['There is one apple', 'There is one apple|There are %count% apples', 1],
211+
['There are 2 apples', 'There is one apple|There are %count% apples', 2],
212+
213+
// Tests for float numbers
214+
['There is almost one apple', '{0} There are no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7],
215+
['There is one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1],
216+
['There is more than one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7],
217+
['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0],
218+
['There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0],
219+
['There are no apples', '{0.0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0],
220+
221+
// Test texts with new-lines
222+
// with double-quotes and \n in id & double-quotes and actual newlines in text
223+
["This is a text with a\n new-line in it. Selector = 0.", '{0}This is a text with a
224+
new-line in it. Selector = 0.|{1}This is a text with a
225+
new-line in it. Selector = 1.|[1,Inf]This is a text with a
226+
new-line in it. Selector > 1.', 0],
227+
// with double-quotes and \n in id and single-quotes and actual newlines in text
228+
["This is a text with a\n new-line in it. Selector = 1.", '{0}This is a text with a
229+
new-line in it. Selector = 0.|{1}This is a text with a
230+
new-line in it. Selector = 1.|[1,Inf]This is a text with a
231+
new-line in it. Selector > 1.', 1],
232+
["This is a text with a\n new-line in it. Selector > 1.", '{0}This is a text with a
233+
new-line in it. Selector = 0.|{1}This is a text with a
234+
new-line in it. Selector = 1.|[1,Inf]This is a text with a
235+
new-line in it. Selector > 1.', 5],
236+
// with double-quotes and id split accros lines
237+
['This is a text with a
238+
new-line in it. Selector = 1.', '{0}This is a text with a
239+
new-line in it. Selector = 0.|{1}This is a text with a
240+
new-line in it. Selector = 1.|[1,Inf]This is a text with a
241+
new-line in it. Selector > 1.', 1],
242+
// with single-quotes and id split accros lines
243+
['This is a text with a
244+
new-line in it. Selector > 1.', '{0}This is a text with a
245+
new-line in it. Selector = 0.|{1}This is a text with a
246+
new-line in it. Selector = 1.|[1,Inf]This is a text with a
247+
new-line in it. Selector > 1.', 5],
248+
// with single-quotes and \n in text
249+
['This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0],
250+
// with double-quotes and id split accros lines
251+
["This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1],
252+
// esacape pipe
253+
['This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0],
254+
// Empty plural set (2 plural forms) from a .PO file
255+
['', '|', 1],
256+
// Empty plural set (3 plural forms) from a .PO file
257+
['', '||', 1],
258+
];
259+
}
260+
261+
/**
262+
* @dataProvider failingLangcodes
263+
*/
264+
public function testFailedLangcodes($nplural, $langCodes)
265+
{
266+
$matrix = $this->generateTestData($langCodes);
267+
$this->validateMatrix($nplural, $matrix, false);
268+
}
269+
270+
/**
271+
* @dataProvider successLangcodes
272+
*/
273+
public function testLangcodes($nplural, $langCodes)
274+
{
275+
$matrix = $this->generateTestData($langCodes);
276+
$this->validateMatrix($nplural, $matrix);
277+
}
278+
279+
/**
280+
* This array should contain all currently known langcodes.
281+
*
282+
* As it is impossible to have this ever complete we should try as hard as possible to have it almost complete.
283+
*
284+
* @return array
285+
*/
286+
public function successLangcodes()
287+
{
288+
return [
289+
['1', ['ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky']],
290+
['2', ['nl', 'fr', 'en', 'de', 'de_GE', 'hy', 'hy_AM']],
291+
['3', ['be', 'bs', 'cs', 'hr']],
292+
['4', ['cy', 'mt', 'sl']],
293+
['6', ['ar']],
294+
];
295+
}
296+
297+
/**
298+
* This array should be at least empty within the near future.
299+
*
300+
* This both depends on a complete list trying to add above as understanding
301+
* the plural rules of the current failing languages.
302+
*
303+
* @return array with nplural together with langcodes
304+
*/
305+
public function failingLangcodes()
306+
{
307+
return [
308+
['1', ['fa']],
309+
['2', ['jbo']],
310+
['3', ['cbs']],
311+
['4', ['gd', 'kw']],
312+
['5', ['ga']],
313+
];
314+
}
315+
316+
/**
317+
* We validate only on the plural coverage. Thus the real rules is not tested.
318+
*
319+
* @param string $nplural Plural expected
320+
* @param array $matrix Containing langcodes and their plural index values
321+
* @param bool $expectSuccess
322+
*/
323+
protected function validateMatrix($nplural, $matrix, $expectSuccess = true)
324+
{
325+
foreach ($matrix as $langCode => $data) {
326+
$indexes = array_flip($data);
327+
if ($expectSuccess) {
328+
$this->assertEquals($nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
329+
} else {
330+
$this->assertNotEquals((int) $nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms.");
331+
}
332+
}
333+
}
334+
335+
protected function generateTestData($langCodes)
336+
{
337+
$translator = new class() {
338+
use TranslatorTrait {
339+
getPluralizationRule as public;
340+
}
341+
};
342+
343+
$matrix = [];
344+
foreach ($langCodes as $langCode) {
345+
for ($count = 0; $count < 200; ++$count) {
346+
$plural = $translator->getPluralizationRule($count, $langCode);
347+
$matrix[$langCode][$count] = $plural;
348+
}
349+
}
350+
351+
return $matrix;
352+
}
353+
}

0 commit comments

Comments
 (0)