1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;
13
14use PHPUnit\Framework\TestCase;
15use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer;
16use Symfony\Component\Intl\Util\IntlTestHelper;
17
18class NumberToLocalizedStringTransformerTest extends TestCase
19{
20    private $defaultLocale;
21
22    protected function setUp()
23    {
24        $this->defaultLocale = \Locale::getDefault();
25        \Locale::setDefault('en');
26    }
27
28    protected function tearDown()
29    {
30        \Locale::setDefault($this->defaultLocale);
31    }
32
33    public function provideTransformations()
34    {
35        return [
36            [null, '', 'de_AT'],
37            [1, '1', 'de_AT'],
38            [1.5, '1,5', 'de_AT'],
39            [1234.5, '1234,5', 'de_AT'],
40            [12345.912, '12345,912', 'de_AT'],
41            [1234.5, '1234,5', 'ru'],
42            [1234.5, '1234,5', 'fi'],
43        ];
44    }
45
46    /**
47     * @dataProvider provideTransformations
48     */
49    public function testTransform($from, $to, $locale)
50    {
51        // Since we test against other locales, we need the full implementation
52        IntlTestHelper::requireFullIntl($this, false);
53
54        \Locale::setDefault($locale);
55
56        $transformer = new NumberToLocalizedStringTransformer();
57
58        $this->assertSame($to, $transformer->transform($from));
59    }
60
61    public function provideTransformationsWithGrouping()
62    {
63        return [
64            [1234.5, '1.234,5', 'de_DE'],
65            [12345.912, '12.345,912', 'de_DE'],
66            [1234.5, '1 234,5', 'fr'],
67            [1234.5, '1 234,5', 'ru'],
68            [1234.5, '1 234,5', 'fi'],
69        ];
70    }
71
72    /**
73     * @dataProvider provideTransformationsWithGrouping
74     */
75    public function testTransformWithGrouping($from, $to, $locale)
76    {
77        // Since we test against other locales, we need the full implementation
78        IntlTestHelper::requireFullIntl($this, false);
79
80        \Locale::setDefault($locale);
81
82        $transformer = new NumberToLocalizedStringTransformer(null, true);
83
84        $this->assertSame($to, $transformer->transform($from));
85    }
86
87    public function testTransformWithScale()
88    {
89        // Since we test against "de_AT", we need the full implementation
90        IntlTestHelper::requireFullIntl($this, false);
91
92        \Locale::setDefault('de_AT');
93
94        $transformer = new NumberToLocalizedStringTransformer(2);
95
96        $this->assertEquals('1234,50', $transformer->transform(1234.5));
97        $this->assertEquals('678,92', $transformer->transform(678.916));
98    }
99
100    public function transformWithRoundingProvider()
101    {
102        return [
103            // towards positive infinity (1.6 -> 2, -1.6 -> -1)
104            [0, 1234.5, '1235', NumberToLocalizedStringTransformer::ROUND_CEILING],
105            [0, 1234.4, '1235', NumberToLocalizedStringTransformer::ROUND_CEILING],
106            [0, -1234.5, '-1234', NumberToLocalizedStringTransformer::ROUND_CEILING],
107            [0, -1234.4, '-1234', NumberToLocalizedStringTransformer::ROUND_CEILING],
108            [1, 123.45, '123,5', NumberToLocalizedStringTransformer::ROUND_CEILING],
109            [1, 123.44, '123,5', NumberToLocalizedStringTransformer::ROUND_CEILING],
110            [1, -123.45, '-123,4', NumberToLocalizedStringTransformer::ROUND_CEILING],
111            [1, -123.44, '-123,4', NumberToLocalizedStringTransformer::ROUND_CEILING],
112            // towards negative infinity (1.6 -> 1, -1.6 -> -2)
113            [0, 1234.5, '1234', NumberToLocalizedStringTransformer::ROUND_FLOOR],
114            [0, 1234.4, '1234', NumberToLocalizedStringTransformer::ROUND_FLOOR],
115            [0, -1234.5, '-1235', NumberToLocalizedStringTransformer::ROUND_FLOOR],
116            [0, -1234.4, '-1235', NumberToLocalizedStringTransformer::ROUND_FLOOR],
117            [1, 123.45, '123,4', NumberToLocalizedStringTransformer::ROUND_FLOOR],
118            [1, 123.44, '123,4', NumberToLocalizedStringTransformer::ROUND_FLOOR],
119            [1, -123.45, '-123,5', NumberToLocalizedStringTransformer::ROUND_FLOOR],
120            [1, -123.44, '-123,5', NumberToLocalizedStringTransformer::ROUND_FLOOR],
121            // away from zero (1.6 -> 2, -1.6 -> 2)
122            [0, 1234.5, '1235', NumberToLocalizedStringTransformer::ROUND_UP],
123            [0, 1234.4, '1235', NumberToLocalizedStringTransformer::ROUND_UP],
124            [0, -1234.5, '-1235', NumberToLocalizedStringTransformer::ROUND_UP],
125            [0, -1234.4, '-1235', NumberToLocalizedStringTransformer::ROUND_UP],
126            [1, 123.45, '123,5', NumberToLocalizedStringTransformer::ROUND_UP],
127            [1, 123.44, '123,5', NumberToLocalizedStringTransformer::ROUND_UP],
128            [1, -123.45, '-123,5', NumberToLocalizedStringTransformer::ROUND_UP],
129            [1, -123.44, '-123,5', NumberToLocalizedStringTransformer::ROUND_UP],
130            // towards zero (1.6 -> 1, -1.6 -> -1)
131            [0, 1234.5, '1234', NumberToLocalizedStringTransformer::ROUND_DOWN],
132            [0, 1234.4, '1234', NumberToLocalizedStringTransformer::ROUND_DOWN],
133            [0, -1234.5, '-1234', NumberToLocalizedStringTransformer::ROUND_DOWN],
134            [0, -1234.4, '-1234', NumberToLocalizedStringTransformer::ROUND_DOWN],
135            [1, 123.45, '123,4', NumberToLocalizedStringTransformer::ROUND_DOWN],
136            [1, 123.44, '123,4', NumberToLocalizedStringTransformer::ROUND_DOWN],
137            [1, -123.45, '-123,4', NumberToLocalizedStringTransformer::ROUND_DOWN],
138            [1, -123.44, '-123,4', NumberToLocalizedStringTransformer::ROUND_DOWN],
139            // round halves (.5) to the next even number
140            [0, 1234.6, '1235', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
141            [0, 1234.5, '1234', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
142            [0, 1234.4, '1234', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
143            [0, 1233.5, '1234', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
144            [0, 1232.5, '1232', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
145            [0, -1234.6, '-1235', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
146            [0, -1234.5, '-1234', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
147            [0, -1234.4, '-1234', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
148            [0, -1233.5, '-1234', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
149            [0, -1232.5, '-1232', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
150            [1, 123.46, '123,5', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
151            [1, 123.45, '123,4', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
152            [1, 123.44, '123,4', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
153            [1, 123.35, '123,4', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
154            [1, 123.25, '123,2', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
155            [1, -123.46, '-123,5', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
156            [1, -123.45, '-123,4', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
157            [1, -123.44, '-123,4', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
158            [1, -123.35, '-123,4', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
159            [1, -123.25, '-123,2', NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
160            // round halves (.5) away from zero
161            [0, 1234.6, '1235', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
162            [0, 1234.5, '1235', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
163            [0, 1234.4, '1234', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
164            [0, -1234.6, '-1235', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
165            [0, -1234.5, '-1235', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
166            [0, -1234.4, '-1234', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
167            [1, 123.46, '123,5', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
168            [1, 123.45, '123,5', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
169            [1, 123.44, '123,4', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
170            [1, -123.46, '-123,5', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
171            [1, -123.45, '-123,5', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
172            [1, -123.44, '-123,4', NumberToLocalizedStringTransformer::ROUND_HALF_UP],
173            // round halves (.5) towards zero
174            [0, 1234.6, '1235', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
175            [0, 1234.5, '1234', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
176            [0, 1234.4, '1234', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
177            [0, -1234.6, '-1235', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
178            [0, -1234.5, '-1234', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
179            [0, -1234.4, '-1234', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
180            [1, 123.46, '123,5', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
181            [1, 123.45, '123,4', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
182            [1, 123.44, '123,4', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
183            [1, -123.46, '-123,5', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
184            [1, -123.45, '-123,4', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
185            [1, -123.44, '-123,4', NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
186        ];
187    }
188
189    /**
190     * @dataProvider transformWithRoundingProvider
191     */
192    public function testTransformWithRounding($scale, $input, $output, $roundingMode)
193    {
194        // Since we test against "de_AT", we need the full implementation
195        IntlTestHelper::requireFullIntl($this, false);
196
197        \Locale::setDefault('de_AT');
198
199        $transformer = new NumberToLocalizedStringTransformer($scale, null, $roundingMode);
200
201        $this->assertEquals($output, $transformer->transform($input));
202    }
203
204    public function testTransformDoesNotRoundIfNoScale()
205    {
206        // Since we test against "de_AT", we need the full implementation
207        IntlTestHelper::requireFullIntl($this, false);
208
209        \Locale::setDefault('de_AT');
210
211        $transformer = new NumberToLocalizedStringTransformer(null, null, NumberToLocalizedStringTransformer::ROUND_DOWN);
212
213        $this->assertEquals('1234,547', $transformer->transform(1234.547));
214    }
215
216    /**
217     * @dataProvider provideTransformations
218     */
219    public function testReverseTransform($to, $from, $locale)
220    {
221        // Since we test against other locales, we need the full implementation
222        IntlTestHelper::requireFullIntl($this, false);
223
224        \Locale::setDefault($locale);
225
226        $transformer = new NumberToLocalizedStringTransformer();
227
228        $this->assertEquals($to, $transformer->reverseTransform($from));
229    }
230
231    /**
232     * @dataProvider provideTransformationsWithGrouping
233     */
234    public function testReverseTransformWithGrouping($to, $from, $locale)
235    {
236        // Since we test against other locales, we need the full implementation
237        IntlTestHelper::requireFullIntl($this, '4.8.1.1');
238
239        \Locale::setDefault($locale);
240
241        $transformer = new NumberToLocalizedStringTransformer(null, true);
242
243        $this->assertEquals($to, $transformer->reverseTransform($from));
244    }
245
246    /**
247     * @see https://github.com/symfony/symfony/issues/7609
248     */
249    public function testReverseTransformWithGroupingAndFixedSpaces()
250    {
251        // Since we test against other locales, we need the full implementation
252        IntlTestHelper::requireFullIntl($this, false);
253
254        \Locale::setDefault('ru');
255
256        $transformer = new NumberToLocalizedStringTransformer(null, true);
257
258        $this->assertEquals(1234.5, $transformer->reverseTransform("1\xc2\xa0234,5"));
259    }
260
261    public function testReverseTransformWithGroupingButWithoutGroupSeparator()
262    {
263        // Since we test against "de_AT", we need the full implementation
264        IntlTestHelper::requireFullIntl($this, false);
265
266        \Locale::setDefault('de_AT');
267
268        $transformer = new NumberToLocalizedStringTransformer(null, true);
269
270        // omit group separator
271        $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
272        $this->assertEquals(12345.912, $transformer->reverseTransform('12345,912'));
273    }
274
275    public function reverseTransformWithRoundingProvider()
276    {
277        return [
278            // towards positive infinity (1.6 -> 2, -1.6 -> -1)
279            [0, '1234,5', 1235, NumberToLocalizedStringTransformer::ROUND_CEILING],
280            [0, '1234,4', 1235, NumberToLocalizedStringTransformer::ROUND_CEILING],
281            [0, '-1234,5', -1234, NumberToLocalizedStringTransformer::ROUND_CEILING],
282            [0, '-1234,4', -1234, NumberToLocalizedStringTransformer::ROUND_CEILING],
283            [1, '123,45', 123.5, NumberToLocalizedStringTransformer::ROUND_CEILING],
284            [1, '123,44', 123.5, NumberToLocalizedStringTransformer::ROUND_CEILING],
285            [1, '-123,45', -123.4, NumberToLocalizedStringTransformer::ROUND_CEILING],
286            [1, '-123,44', -123.4, NumberToLocalizedStringTransformer::ROUND_CEILING],
287            // towards negative infinity (1.6 -> 1, -1.6 -> -2)
288            [0, '1234,5', 1234, NumberToLocalizedStringTransformer::ROUND_FLOOR],
289            [0, '1234,4', 1234, NumberToLocalizedStringTransformer::ROUND_FLOOR],
290            [0, '-1234,5', -1235, NumberToLocalizedStringTransformer::ROUND_FLOOR],
291            [0, '-1234,4', -1235, NumberToLocalizedStringTransformer::ROUND_FLOOR],
292            [1, '123,45', 123.4, NumberToLocalizedStringTransformer::ROUND_FLOOR],
293            [1, '123,44', 123.4, NumberToLocalizedStringTransformer::ROUND_FLOOR],
294            [1, '-123,45', -123.5, NumberToLocalizedStringTransformer::ROUND_FLOOR],
295            [1, '-123,44', -123.5, NumberToLocalizedStringTransformer::ROUND_FLOOR],
296            // away from zero (1.6 -> 2, -1.6 -> 2)
297            [0, '1234,5', 1235, NumberToLocalizedStringTransformer::ROUND_UP],
298            [0, '1234,4', 1235, NumberToLocalizedStringTransformer::ROUND_UP],
299            [0, '-1234,5', -1235, NumberToLocalizedStringTransformer::ROUND_UP],
300            [0, '-1234,4', -1235, NumberToLocalizedStringTransformer::ROUND_UP],
301            [1, '123,45', 123.5, NumberToLocalizedStringTransformer::ROUND_UP],
302            [1, '123,44', 123.5, NumberToLocalizedStringTransformer::ROUND_UP],
303            [1, '-123,45', -123.5, NumberToLocalizedStringTransformer::ROUND_UP],
304            [1, '-123,44', -123.5, NumberToLocalizedStringTransformer::ROUND_UP],
305            // towards zero (1.6 -> 1, -1.6 -> -1)
306            [0, '1234,5', 1234, NumberToLocalizedStringTransformer::ROUND_DOWN],
307            [0, '1234,4', 1234, NumberToLocalizedStringTransformer::ROUND_DOWN],
308            [0, '-1234,5', -1234, NumberToLocalizedStringTransformer::ROUND_DOWN],
309            [0, '-1234,4', -1234, NumberToLocalizedStringTransformer::ROUND_DOWN],
310            [1, '123,45', 123.4, NumberToLocalizedStringTransformer::ROUND_DOWN],
311            [1, '123,44', 123.4, NumberToLocalizedStringTransformer::ROUND_DOWN],
312            [1, '-123,45', -123.4, NumberToLocalizedStringTransformer::ROUND_DOWN],
313            [1, '-123,44', -123.4, NumberToLocalizedStringTransformer::ROUND_DOWN],
314            [2, '37.37', 37.37, NumberToLocalizedStringTransformer::ROUND_DOWN],
315            [2, '2.01', 2.01, NumberToLocalizedStringTransformer::ROUND_DOWN],
316            // round halves (.5) to the next even number
317            [0, '1234,6', 1235, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
318            [0, '1234,5', 1234, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
319            [0, '1234,4', 1234, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
320            [0, '1233,5', 1234, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
321            [0, '1232,5', 1232, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
322            [0, '-1234,6', -1235, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
323            [0, '-1234,5', -1234, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
324            [0, '-1234,4', -1234, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
325            [0, '-1233,5', -1234, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
326            [0, '-1232,5', -1232, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
327            [1, '123,46', 123.5, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
328            [1, '123,45', 123.4, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
329            [1, '123,44', 123.4, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
330            [1, '123,35', 123.4, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
331            [1, '123,25', 123.2, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
332            [1, '-123,46', -123.5, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
333            [1, '-123,45', -123.4, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
334            [1, '-123,44', -123.4, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
335            [1, '-123,35', -123.4, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
336            [1, '-123,25', -123.2, NumberToLocalizedStringTransformer::ROUND_HALF_EVEN],
337            // round halves (.5) away from zero
338            [0, '1234,6', 1235, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
339            [0, '1234,5', 1235, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
340            [0, '1234,4', 1234, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
341            [0, '-1234,6', -1235, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
342            [0, '-1234,5', -1235, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
343            [0, '-1234,4', -1234, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
344            [1, '123,46', 123.5, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
345            [1, '123,45', 123.5, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
346            [1, '123,44', 123.4, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
347            [1, '-123,46', -123.5, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
348            [1, '-123,45', -123.5, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
349            [1, '-123,44', -123.4, NumberToLocalizedStringTransformer::ROUND_HALF_UP],
350            // round halves (.5) towards zero
351            [0, '1234,6', 1235, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
352            [0, '1234,5', 1234, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
353            [0, '1234,4', 1234, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
354            [0, '-1234,6', -1235, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
355            [0, '-1234,5', -1234, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
356            [0, '-1234,4', -1234, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
357            [1, '123,46', 123.5, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
358            [1, '123,45', 123.4, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
359            [1, '123,44', 123.4, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
360            [1, '-123,46', -123.5, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
361            [1, '-123,45', -123.4, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
362            [1, '-123,44', -123.4, NumberToLocalizedStringTransformer::ROUND_HALF_DOWN],
363        ];
364    }
365
366    /**
367     * @dataProvider reverseTransformWithRoundingProvider
368     */
369    public function testReverseTransformWithRounding($scale, $input, $output, $roundingMode)
370    {
371        $transformer = new NumberToLocalizedStringTransformer($scale, null, $roundingMode);
372
373        $this->assertSame($output, $transformer->reverseTransform($input));
374    }
375
376    public function testReverseTransformDoesNotRoundIfNoScale()
377    {
378        $transformer = new NumberToLocalizedStringTransformer(null, null, NumberToLocalizedStringTransformer::ROUND_DOWN);
379
380        $this->assertEquals(1234.547, $transformer->reverseTransform('1234,547'));
381    }
382
383    public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsNotDot()
384    {
385        // Since we test against other locales, we need the full implementation
386        IntlTestHelper::requireFullIntl($this, '4.8.1.1');
387
388        \Locale::setDefault('fr');
389        $transformer = new NumberToLocalizedStringTransformer(null, true);
390
391        // completely valid format
392        $this->assertEquals(1234.5, $transformer->reverseTransform('1 234,5'));
393        // accept dots
394        $this->assertEquals(1234.5, $transformer->reverseTransform('1 234.5'));
395        // omit group separator
396        $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
397        $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
398    }
399
400    public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDot()
401    {
402        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
403        // Since we test against "de_DE", we need the full implementation
404        IntlTestHelper::requireFullIntl($this, '4.8.1.1');
405
406        \Locale::setDefault('de_DE');
407
408        $transformer = new NumberToLocalizedStringTransformer(null, true);
409
410        $transformer->reverseTransform('1.234.5');
411    }
412
413    public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDotWithNoGroupSep()
414    {
415        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
416        // Since we test against "de_DE", we need the full implementation
417        IntlTestHelper::requireFullIntl($this, '4.8.1.1');
418
419        \Locale::setDefault('de_DE');
420
421        $transformer = new NumberToLocalizedStringTransformer(null, true);
422
423        $transformer->reverseTransform('1234.5');
424    }
425
426    public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsDotButNoGroupingUsed()
427    {
428        // Since we test against other locales, we need the full implementation
429        IntlTestHelper::requireFullIntl($this, false);
430
431        \Locale::setDefault('fr');
432        $transformer = new NumberToLocalizedStringTransformer();
433
434        $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
435        $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
436    }
437
438    public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsNotComma()
439    {
440        // Since we test against other locales, we need the full implementation
441        IntlTestHelper::requireFullIntl($this, '4.8.1.1');
442
443        \Locale::setDefault('bg');
444        $transformer = new NumberToLocalizedStringTransformer(null, true);
445
446        // completely valid format
447        $this->assertEquals(1234.5, $transformer->reverseTransform('1 234.5'));
448        // accept commas
449        $this->assertEquals(1234.5, $transformer->reverseTransform('1 234,5'));
450        // omit group separator
451        $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
452        $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
453    }
454
455    public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsComma()
456    {
457        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
458        IntlTestHelper::requireFullIntl($this, '4.8.1.1');
459
460        $transformer = new NumberToLocalizedStringTransformer(null, true);
461
462        $transformer->reverseTransform('1,234,5');
463    }
464
465    public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsCommaWithNoGroupSep()
466    {
467        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
468        IntlTestHelper::requireFullIntl($this, '4.8.1.1');
469
470        $transformer = new NumberToLocalizedStringTransformer(null, true);
471
472        $transformer->reverseTransform('1234,5');
473    }
474
475    public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsCommaButNoGroupingUsed()
476    {
477        $transformer = new NumberToLocalizedStringTransformer();
478
479        $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
480        $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5'));
481    }
482
483    public function testTransformExpectsNumeric()
484    {
485        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
486        $transformer = new NumberToLocalizedStringTransformer();
487
488        $transformer->transform('foo');
489    }
490
491    public function testReverseTransformExpectsString()
492    {
493        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
494        $transformer = new NumberToLocalizedStringTransformer();
495
496        $transformer->reverseTransform(1);
497    }
498
499    public function testReverseTransformExpectsValidNumber()
500    {
501        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
502        $transformer = new NumberToLocalizedStringTransformer();
503
504        $transformer->reverseTransform('foo');
505    }
506
507    /**
508     * @dataProvider nanRepresentationProvider
509     *
510     * @see https://github.com/symfony/symfony/issues/3161
511     */
512    public function testReverseTransformDisallowsNaN($nan)
513    {
514        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
515        $transformer = new NumberToLocalizedStringTransformer();
516
517        $transformer->reverseTransform($nan);
518    }
519
520    public function nanRepresentationProvider()
521    {
522        return [
523            ['nan'],
524            ['NaN'], // see https://github.com/symfony/symfony/issues/3161
525            ['NAN'],
526        ];
527    }
528
529    public function testReverseTransformDisallowsInfinity()
530    {
531        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
532        $transformer = new NumberToLocalizedStringTransformer();
533
534        $transformer->reverseTransform('∞');
535    }
536
537    public function testReverseTransformDisallowsInfinity2()
538    {
539        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
540        $transformer = new NumberToLocalizedStringTransformer();
541
542        $transformer->reverseTransform('∞,123');
543    }
544
545    public function testReverseTransformDisallowsNegativeInfinity()
546    {
547        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
548        $transformer = new NumberToLocalizedStringTransformer();
549
550        $transformer->reverseTransform('-∞');
551    }
552
553    public function testReverseTransformDisallowsLeadingExtraCharacters()
554    {
555        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
556        $transformer = new NumberToLocalizedStringTransformer();
557
558        $transformer->reverseTransform('foo123');
559    }
560
561    public function testReverseTransformDisallowsCenteredExtraCharacters()
562    {
563        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
564        $this->expectExceptionMessage('The number contains unrecognized characters: "foo3"');
565        $transformer = new NumberToLocalizedStringTransformer();
566
567        $transformer->reverseTransform('12foo3');
568    }
569
570    public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte()
571    {
572        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
573        $this->expectExceptionMessage('The number contains unrecognized characters: "foo8"');
574        // Since we test against other locales, we need the full implementation
575        IntlTestHelper::requireFullIntl($this, false);
576
577        \Locale::setDefault('ru');
578
579        $transformer = new NumberToLocalizedStringTransformer(null, true);
580
581        $transformer->reverseTransform("12\xc2\xa0345,67foo8");
582    }
583
584    public function testReverseTransformIgnoresTrailingSpacesInExceptionMessage()
585    {
586        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
587        $this->expectExceptionMessage('The number contains unrecognized characters: "foo8"');
588        // Since we test against other locales, we need the full implementation
589        IntlTestHelper::requireFullIntl($this, false);
590
591        \Locale::setDefault('ru');
592
593        $transformer = new NumberToLocalizedStringTransformer(null, true);
594
595        $transformer->reverseTransform("12\xc2\xa0345,67foo8  \xc2\xa0\t");
596    }
597
598    public function testReverseTransformDisallowsTrailingExtraCharacters()
599    {
600        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
601        $this->expectExceptionMessage('The number contains unrecognized characters: "foo"');
602        $transformer = new NumberToLocalizedStringTransformer();
603
604        $transformer->reverseTransform('123foo');
605    }
606
607    public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
608    {
609        $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException');
610        $this->expectExceptionMessage('The number contains unrecognized characters: "foo"');
611        // Since we test against other locales, we need the full implementation
612        IntlTestHelper::requireFullIntl($this, false);
613
614        \Locale::setDefault('ru');
615
616        $transformer = new NumberToLocalizedStringTransformer(null, true);
617
618        $transformer->reverseTransform("12\xc2\xa0345,678foo");
619    }
620
621    public function testReverseTransformBigInt()
622    {
623        $transformer = new NumberToLocalizedStringTransformer(null, true);
624
625        $this->assertEquals(\PHP_INT_MAX - 1, (int) $transformer->reverseTransform((string) (\PHP_INT_MAX - 1)));
626    }
627
628    public function testReverseTransformSmallInt()
629    {
630        $transformer = new NumberToLocalizedStringTransformer(null, true);
631
632        $this->assertSame(1.0, $transformer->reverseTransform('1'));
633    }
634}
635