Files
Chamilo/vendor/symfony/intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php
2025-08-14 22:41:49 +02:00

890 lines
32 KiB
PHP

<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Intl\Tests\NumberFormatter;
use PHPUnit\Framework\Error\Warning;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Intl\Globals\IntlGlobals;
use Symfony\Component\Intl\NumberFormatter\NumberFormatter;
use Symfony\Component\Intl\Util\IntlTestHelper;
/**
* Note that there are some values written like -2147483647 - 1. This is the lower 32bit int max and is a known
* behavior of PHP.
*/
abstract class AbstractNumberFormatterTest extends TestCase
{
/**
* @dataProvider formatCurrencyWithDecimalStyleProvider
*/
public function testFormatCurrencyWithDecimalStyle($value, $currency, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$this->assertEquals($expected, $formatter->formatCurrency($value, $currency));
}
public function formatCurrencyWithDecimalStyleProvider()
{
return [
[100, 'ALL', '100'],
[100, 'BRL', '100'],
[100, 'CRC', '100'],
[100, 'JPY', '100'],
[100, 'CHF', '100'],
[-100, 'ALL', '-100'],
[-100, 'BRL', '-100'],
[-100, 'CRC', '-100'],
[-100, 'JPY', '-100'],
[-100, 'CHF', '-100'],
[1000.12, 'ALL', '1,000.12'],
[1000.12, 'BRL', '1,000.12'],
[1000.12, 'CRC', '1,000.12'],
[1000.12, 'JPY', '1,000.12'],
[1000.12, 'CHF', '1,000.12'],
];
}
/**
* @dataProvider formatCurrencyWithCurrencyStyleProvider
*/
public function testFormatCurrencyWithCurrencyStyle($value, $currency, $expected)
{
IntlTestHelper::requireIntl($this, '63.1');
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$this->assertEquals($expected, $formatter->formatCurrency($value, $currency));
}
public function formatCurrencyWithCurrencyStyleProvider()
{
return [
[100, 'ALL', "ALL\xc2\xa0100"],
[-100, 'ALL', "-ALL\xc2\xa0100"],
[1000.12, 'ALL', "ALL\xc2\xa01,000"],
[100, 'JPY', '¥100'],
[-100, 'JPY', '-¥100'],
[1000.12, 'JPY', '¥1,000'],
[100, 'EUR', '€100.00'],
[-100, 'EUR', '-€100.00'],
[1000.12, 'EUR', '€1,000.12'],
];
}
/**
* @dataProvider formatCurrencyWithCurrencyStyleCostaRicanColonsRoundingProvider
*/
public function testFormatCurrencyWithCurrencyStyleCostaRicanColonsRounding($value, $currency, $symbol, $expected)
{
IntlTestHelper::requireIntl($this, '63.1');
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
}
public function formatCurrencyWithCurrencyStyleCostaRicanColonsRoundingProvider()
{
return [
[100, 'CRC', 'CRC', "%s\xc2\xa0100.00"],
[-100, 'CRC', 'CRC', "-%s\xc2\xa0100.00"],
[1000.12, 'CRC', 'CRC', "%s\xc2\xa01,000.12"],
];
}
/**
* @dataProvider formatCurrencyWithCurrencyStyleBrazilianRealRoundingProvider
*/
public function testFormatCurrencyWithCurrencyStyleBrazilianRealRounding($value, $currency, $symbol, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
}
public function formatCurrencyWithCurrencyStyleBrazilianRealRoundingProvider()
{
return [
[100, 'BRL', 'R', '%s$100.00'],
[-100, 'BRL', 'R', '-%s$100.00'],
[1000.12, 'BRL', 'R', '%s$1,000.12'],
// Rounding checks
[1000.121, 'BRL', 'R', '%s$1,000.12'],
[1000.123, 'BRL', 'R', '%s$1,000.12'],
[1000.125, 'BRL', 'R', '%s$1,000.12'],
[1000.127, 'BRL', 'R', '%s$1,000.13'],
[1000.129, 'BRL', 'R', '%s$1,000.13'],
[11.50999, 'BRL', 'R', '%s$11.51'],
[11.9999464, 'BRL', 'R', '%s$12.00'],
];
}
/**
* @dataProvider formatCurrencyWithCurrencyStyleSwissRoundingProvider
*/
public function testFormatCurrencyWithCurrencyStyleSwissRounding($value, $currency, $symbol, $expected)
{
IntlTestHelper::requireIntl($this, '62.1');
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$this->assertEquals(sprintf($expected, $symbol), $formatter->formatCurrency($value, $currency));
}
public function formatCurrencyWithCurrencyStyleSwissRoundingProvider()
{
return [
[100, 'CHF', 'CHF', "%s\xc2\xa0100.00"],
[-100, 'CHF', 'CHF', "-%s\xc2\xa0100.00"],
[1000.12, 'CHF', 'CHF', "%s\xc2\xa01,000.12"],
['1000.12', 'CHF', 'CHF', "%s\xc2\xa01,000.12"],
// Rounding checks
[1000.121, 'CHF', 'CHF', "%s\xc2\xa01,000.12"],
[1000.123, 'CHF', 'CHF', "%s\xc2\xa01,000.12"],
[1000.125, 'CHF', 'CHF', "%s\xc2\xa01,000.12"],
[1000.127, 'CHF', 'CHF', "%s\xc2\xa01,000.13"],
[1000.129, 'CHF', 'CHF', "%s\xc2\xa01,000.13"],
[1200000.00, 'CHF', 'CHF', "%s\xc2\xa01,200,000.00"],
[1200000.1, 'CHF', 'CHF', "%s\xc2\xa01,200,000.10"],
[1200000.10, 'CHF', 'CHF', "%s\xc2\xa01,200,000.10"],
[1200000.101, 'CHF', 'CHF', "%s\xc2\xa01,200,000.10"],
];
}
public function testFormat()
{
$errorCode = IntlGlobals::U_ZERO_ERROR;
$errorMessage = 'U_ZERO_ERROR';
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$this->assertSame('9.555', $formatter->format(9.555));
$this->assertSame($errorMessage, $this->getIntlErrorMessage());
$this->assertSame($errorCode, $this->getIntlErrorCode());
$this->assertFalse($this->isIntlFailure($this->getIntlErrorCode()));
$this->assertSame($errorMessage, $formatter->getErrorMessage());
$this->assertSame($errorCode, $formatter->getErrorCode());
$this->assertFalse($this->isIntlFailure($formatter->getErrorCode()));
}
public function testFormatWithCurrencyStyle()
{
IntlTestHelper::requireIntl($this, '63.1');
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$this->assertEquals('¤1.00', $formatter->format(1));
}
/**
* @dataProvider formatTypeInt32Provider
*/
public function testFormatTypeInt32($formatter, $value, $expected, $message = '')
{
$formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT32);
$this->assertEquals($expected, $formattedValue, $message);
}
public function formatTypeInt32Provider()
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$message = '->format() TYPE_INT32 formats inconsistently an integer if out of the 32 bit range.';
return [
[$formatter, 1, '1'],
[$formatter, 1.1, '1'],
[$formatter, 2147483648, '-2,147,483,648', $message],
[$formatter, -2147483649, '2,147,483,647', $message],
];
}
/**
* @dataProvider formatTypeInt32WithCurrencyStyleProvider
*/
public function testFormatTypeInt32WithCurrencyStyle($formatter, $value, $expected, $message = '')
{
IntlTestHelper::requireIntl($this, '63.1');
$formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT32);
$this->assertEquals($expected, $formattedValue, $message);
}
public function formatTypeInt32WithCurrencyStyleProvider()
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$message = '->format() TYPE_INT32 formats inconsistently an integer if out of the 32 bit range.';
return [
[$formatter, 1, '¤1.00'],
[$formatter, 1.1, '¤1.00'],
[$formatter, 2147483648, '-¤2,147,483,648.00', $message],
[$formatter, -2147483649, '¤2,147,483,647.00', $message],
];
}
/**
* The parse() method works differently with integer out of the 32 bit range. format() works fine.
*
* @dataProvider formatTypeInt64Provider
*/
public function testFormatTypeInt64($formatter, $value, $expected)
{
$formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT64);
$this->assertEquals($expected, $formattedValue);
}
public function formatTypeInt64Provider()
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
return [
[$formatter, 1, '1'],
[$formatter, 1.1, '1'],
[$formatter, 2147483648, '2,147,483,648'],
[$formatter, -2147483649, '-2,147,483,649'],
];
}
/**
* @dataProvider formatTypeInt64WithCurrencyStyleProvider
*/
public function testFormatTypeInt64WithCurrencyStyle($formatter, $value, $expected)
{
IntlTestHelper::requireIntl($this, '63.1');
$formattedValue = $formatter->format($value, NumberFormatter::TYPE_INT64);
$this->assertEquals($expected, $formattedValue);
}
public function formatTypeInt64WithCurrencyStyleProvider()
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
return [
[$formatter, 1, '¤1.00'],
[$formatter, 1.1, '¤1.00'],
[$formatter, 2147483648, '¤2,147,483,648.00'],
[$formatter, -2147483649, '-¤2,147,483,649.00'],
];
}
/**
* @dataProvider formatTypeDoubleProvider
*/
public function testFormatTypeDouble($formatter, $value, $expected)
{
$formattedValue = $formatter->format($value, NumberFormatter::TYPE_DOUBLE);
$this->assertEquals($expected, $formattedValue);
}
public function formatTypeDoubleProvider()
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
return [
[$formatter, 1, '1'],
[$formatter, 1.1, '1.1'],
];
}
/**
* @dataProvider formatTypeDoubleWithCurrencyStyleProvider
*/
public function testFormatTypeDoubleWithCurrencyStyle($formatter, $value, $expected)
{
IntlTestHelper::requireIntl($this, '63.1');
$formattedValue = $formatter->format($value, NumberFormatter::TYPE_DOUBLE);
$this->assertEquals($expected, $formattedValue);
}
public function formatTypeDoubleWithCurrencyStyleProvider()
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
return [
[$formatter, 1, '¤1.00'],
[$formatter, 1.1, '¤1.10'],
];
}
/**
* @dataProvider formatTypeCurrencyProvider
*/
public function testFormatTypeCurrency($formatter, $value)
{
if (\PHP_VERSION_ID >= 80000) {
$this->expectException(\ValueError::class);
} elseif (method_exists($this, 'expectWarning')) {
$this->expectWarning();
} else {
$this->expectException(Warning::class);
}
$formatter->format($value, NumberFormatter::TYPE_CURRENCY);
}
/**
* @dataProvider formatTypeCurrencyProvider
*/
public function testFormatTypeCurrencyReturn($formatter, $value)
{
if (\PHP_VERSION_ID >= 80000) {
$this->expectException(\ValueError::class);
}
$this->assertFalse(@$formatter->format($value, NumberFormatter::TYPE_CURRENCY));
}
public function formatTypeCurrencyProvider()
{
$df = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$cf = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
return [
[$df, 1],
[$cf, 1],
];
}
/**
* @dataProvider formatFractionDigitsProvider
*/
public function testFormatFractionDigits($value, $expected, $fractionDigits = null, $expectedFractionDigits = 1)
{
IntlTestHelper::requireIntl($this, '62.1');
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$attributeRet = null;
if (null !== $fractionDigits) {
$attributeRet = $formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $fractionDigits);
}
$formattedValue = $formatter->format($value);
$this->assertSame($expected, $formattedValue);
$this->assertSame($expectedFractionDigits, $formatter->getAttribute(NumberFormatter::FRACTION_DIGITS));
if (null !== $attributeRet) {
$this->assertTrue($attributeRet);
}
}
public function formatFractionDigitsProvider()
{
yield [1.123, '1.123', null, 0];
yield [1.123, '1', 0, 0];
yield [1.123, '1.1', 1, 1];
yield [1.123, '1.12', 2, 2];
yield [1.123, '1.123', -1, 0];
if (\PHP_VERSION_ID < 80000) {
// This dataset will produce a TypeError on php 8.
yield [1.123, '1', 'abc', 0];
}
}
/**
* @dataProvider formatGroupingUsedProvider
*/
public function testFormatGroupingUsed($value, $expected, $groupingUsed = null, $expectedGroupingUsed = 1)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$attributeRet = null;
if (null !== $groupingUsed) {
$attributeRet = $formatter->setAttribute(NumberFormatter::GROUPING_USED, $groupingUsed);
}
$formattedValue = $formatter->format($value);
$this->assertSame($expected, $formattedValue);
$this->assertSame($expectedGroupingUsed, $formatter->getAttribute(NumberFormatter::GROUPING_USED));
if (null !== $attributeRet) {
$this->assertTrue($attributeRet);
}
}
public function formatGroupingUsedProvider()
{
yield [1000, '1,000', null, 1];
yield [1000, '1000', 0, 0];
yield [1000, '1,000', 1, 1];
yield [1000, '1,000', 2, 1];
yield [1000, '1,000', -1, 1];
if (\PHP_VERSION_ID < 80000) {
// This dataset will produce a TypeError on php 8.
yield [1000, '1000', 'abc', 0];
}
}
/**
* @dataProvider formatRoundingModeRoundHalfUpProvider
*/
public function testFormatRoundingModeHalfUp($value, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFUP);
$this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFUP rounding mode.');
}
public function formatRoundingModeRoundHalfUpProvider()
{
// The commented value is differently rounded by intl's NumberFormatter in 32 and 64 bit architectures
return [
[1.121, '1.12'],
[1.123, '1.12'],
// [1.125, '1.13'],
[1.127, '1.13'],
[1.129, '1.13'],
[1020 / 100, '10.20'],
];
}
/**
* @dataProvider formatRoundingModeRoundHalfDownProvider
*/
public function testFormatRoundingModeHalfDown($value, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFDOWN);
$this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFDOWN rounding mode.');
}
public function formatRoundingModeRoundHalfDownProvider()
{
return [
[1.121, '1.12'],
[1.123, '1.12'],
[1.125, '1.12'],
[1.127, '1.13'],
[1.129, '1.13'],
[1020 / 100, '10.20'],
];
}
/**
* @dataProvider formatRoundingModeRoundHalfEvenProvider
*/
public function testFormatRoundingModeHalfEven($value, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFEVEN);
$this->assertSame($expected, $formatter->format($value), '->format() with ROUND_HALFEVEN rounding mode.');
}
public function formatRoundingModeRoundHalfEvenProvider()
{
return [
[1.121, '1.12'],
[1.123, '1.12'],
[1.125, '1.12'],
[1.127, '1.13'],
[1.129, '1.13'],
[1020 / 100, '10.20'],
];
}
/**
* @dataProvider formatRoundingModeRoundCeilingProvider
*/
public function testFormatRoundingModeCeiling($value, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_CEILING);
$this->assertSame($expected, $formatter->format($value), '->format() with ROUND_CEILING rounding mode.');
}
public function formatRoundingModeRoundCeilingProvider()
{
return [
[1.123, '1.13'],
[1.125, '1.13'],
[1.127, '1.13'],
[-1.123, '-1.12'],
[-1.125, '-1.12'],
[-1.127, '-1.12'],
[1020 / 100, '10.20'],
];
}
/**
* @dataProvider formatRoundingModeRoundFloorProvider
*/
public function testFormatRoundingModeFloor($value, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_FLOOR);
$this->assertSame($expected, $formatter->format($value), '->format() with ROUND_FLOOR rounding mode.');
}
public function formatRoundingModeRoundFloorProvider()
{
return [
[1.123, '1.12'],
[1.125, '1.12'],
[1.127, '1.12'],
[-1.123, '-1.13'],
[-1.125, '-1.13'],
[-1.127, '-1.13'],
[1020 / 100, '10.20'],
];
}
/**
* @dataProvider formatRoundingModeRoundDownProvider
*/
public function testFormatRoundingModeDown($value, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_DOWN);
$this->assertSame($expected, $formatter->format($value), '->format() with ROUND_DOWN rounding mode.');
}
public function formatRoundingModeRoundDownProvider()
{
return [
[1.123, '1.12'],
[1.125, '1.12'],
[1.127, '1.12'],
[-1.123, '-1.12'],
[-1.125, '-1.12'],
[-1.127, '-1.12'],
[1020 / 100, '10.20'],
];
}
/**
* @dataProvider formatRoundingModeRoundUpProvider
*/
public function testFormatRoundingModeUp($value, $expected)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::FRACTION_DIGITS, 2);
$formatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_UP);
$this->assertSame($expected, $formatter->format($value), '->format() with ROUND_UP rounding mode.');
}
public function formatRoundingModeRoundUpProvider()
{
return [
[1.123, '1.13'],
[1.125, '1.13'],
[1.127, '1.13'],
[-1.123, '-1.13'],
[-1.125, '-1.13'],
[-1.127, '-1.13'],
[1020 / 100, '10.20'],
];
}
public function testGetLocale()
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$this->assertEquals('en', $formatter->getLocale());
}
public function testGetSymbol()
{
$decimalFormatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$currencyFormatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enSymbols');
$r->setAccessible(true);
$expected = $r->getValue();
for ($i = 0; $i <= 17; ++$i) {
$this->assertSame($expected[1][$i], $decimalFormatter->getSymbol($i));
$this->assertSame($expected[2][$i], $currencyFormatter->getSymbol($i));
}
}
public function testGetTextAttribute()
{
IntlTestHelper::requireIntl($this, '63.1');
$decimalFormatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$currencyFormatter = $this->getNumberFormatter('en', NumberFormatter::CURRENCY);
$r = new \ReflectionProperty('Symfony\Component\Intl\NumberFormatter\NumberFormatter', 'enTextAttributes');
$r->setAccessible(true);
$expected = $r->getValue();
for ($i = 0; $i <= 5; ++$i) {
$this->assertSame($expected[1][$i], $decimalFormatter->getTextAttribute($i));
$this->assertSame($expected[2][$i], $currencyFormatter->getTextAttribute($i));
}
}
/**
* @dataProvider parseProvider
*/
public function testParse($value, $expected, $message, $expectedPosition, $groupingUsed = true)
{
IntlTestHelper::requireIntl($this, '62.1');
$position = 0;
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->setAttribute(NumberFormatter::GROUPING_USED, $groupingUsed);
$parsedValue = $formatter->parse($value, NumberFormatter::TYPE_DOUBLE, $position);
$this->assertSame($expected, $parsedValue, $message);
$this->assertSame($expectedPosition, $position, $message);
if (false === $expected) {
$errorCode = IntlGlobals::U_PARSE_ERROR;
$errorMessage = 'Number parsing failed: U_PARSE_ERROR';
} else {
$errorCode = IntlGlobals::U_ZERO_ERROR;
$errorMessage = 'U_ZERO_ERROR';
}
$this->assertSame($errorMessage, $this->getIntlErrorMessage());
$this->assertSame($errorCode, $this->getIntlErrorCode());
$this->assertSame(0 !== $errorCode, $this->isIntlFailure($this->getIntlErrorCode()));
$this->assertSame($errorMessage, $formatter->getErrorMessage());
$this->assertSame($errorCode, $formatter->getErrorCode());
$this->assertSame(0 !== $errorCode, $this->isIntlFailure($formatter->getErrorCode()));
}
public function parseProvider()
{
return [
['prefix1', false, '->parse() does not parse a number with a string prefix.', 0],
['prefix1', false, '->parse() does not parse a number with a string prefix.', 0, false],
['1.4suffix', (float) 1.4, '->parse() parses a number with a string suffix.', 3],
['1.4suffix', (float) 1.4, '->parse() parses a number with a string suffix.', 3, false],
['1,234.4suffix', 1234.4, '->parse() parses a number with a string suffix.', 7],
['1,234.4suffix', 1.0, '->parse() parses a number with a string suffix.', 1, false],
['-.4suffix', (float) -0.4, '->parse() parses a negative dot float with suffix.', 3],
['-.4suffix', (float) -0.4, '->parse() parses a negative dot float with suffix.', 3, false],
[',4', false, '->parse() does not parse when invalid grouping used.', 0],
[',4', false, '->parse() does not parse when invalid grouping used.', 0, false],
['123,4', false, '->parse() does not parse when invalid grouping used.', 0],
['123,4', 123.0, '->parse() truncates invalid grouping when grouping is disabled.', 3, false],
['123,a4', 123.0, '->parse() truncates a string suffix.', 3],
['123,a4', 123.0, '->parse() truncates a string suffix.', 3, false],
['-123,4', false, '->parse() does not parse when invalid grouping used.', 1],
['-123,4', -123.0, '->parse() truncates invalid grouping when grouping is disabled.', 4, false],
['-123,4567', false, '->parse() does not parse when invalid grouping used.', 1],
['-123,4567', -123.0, '->parse() truncates invalid grouping when grouping is disabled.', 4, false],
['-123,456,789', -123456789.0, '->parse() parses a number with grouping.', 12],
['-123,456,789', -123.0, '->parse() truncates a group if grouping is disabled.', 4, false],
['-123,456,789.66', -123456789.66, '->parse() parses a number with grouping.', 15],
['-123,456,789.66', -123.00, '->parse() truncates a group if grouping is disabled.', 4, false],
['-123,456789.66', false, '->parse() does not parse when invalid grouping used.', 1],
['-123,456789.66', -123.00, '->parse() truncates a group if grouping is disabled.', 4, false],
['-123456,789.66', false, '->parse() does not parse when invalid grouping used.', 1],
['-123456,789.66', -123456.00, '->parse() truncates a group if grouping is disabled.', 7, false],
['-123,456,78', false, '->parse() does not parse when invalid grouping used.', 1],
['-123,456,78', -123.0, '->parse() truncates a group if grouping is disabled.', 4, false],
['-123,45,789', false, '->parse() does not parse when invalid grouping used.', 1],
['-123,45,789', -123.0, '->parse() truncates a group if grouping is disabled.', 4, false],
['-123,,456', -123.0, '->parse() parses when grouping is duplicated.', 4],
['-123,,456', -123.0, '->parse() parses when grouping is disabled.', 4, false],
['-123,,4', -123.0, '->parse() parses when grouping is duplicated.', 4],
['-123,,4', -123.0, '->parse() parses when grouping is duplicated.', 4, false],
['239.', 239.0, '->parse() parses when string ends with decimal separator.', 4],
['239.', 239.0, '->parse() parses when string ends with decimal separator.', 4, false],
];
}
public function testParseTypeDefault()
{
if (\PHP_VERSION_ID >= 80000) {
$this->expectException(\ValueError::class);
} elseif (method_exists($this, 'expectWarning')) {
$this->expectWarning();
} else {
$this->expectException(Warning::class);
}
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->parse('1', NumberFormatter::TYPE_DEFAULT);
}
/**
* @dataProvider parseTypeInt32Provider
*/
public function testParseTypeInt32($value, $expected, $message = '')
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$parsedValue = $formatter->parse($value, NumberFormatter::TYPE_INT32);
$this->assertSame($expected, $parsedValue, $message);
}
public function parseTypeInt32Provider()
{
return [
['1', 1],
['1.1', 1],
['.1', 0],
['2,147,483,647', 2147483647],
['-2,147,483,648', -2147483647 - 1],
['2,147,483,648', false, '->parse() TYPE_INT32 returns false when the number is greater than the integer positive range.'],
['-2,147,483,649', false, '->parse() TYPE_INT32 returns false when the number is greater than the integer negative range.'],
];
}
public function testParseTypeInt64With32BitIntegerInPhp32Bit()
{
IntlTestHelper::require32Bit($this);
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$parsedValue = $formatter->parse('2,147,483,647', NumberFormatter::TYPE_INT64);
$this->assertIsInt($parsedValue);
$this->assertEquals(2147483647, $parsedValue);
$parsedValue = $formatter->parse('-2,147,483,648', NumberFormatter::TYPE_INT64);
$this->assertIsInt($parsedValue);
$this->assertEquals(-2147483648, $parsedValue);
}
public function testParseTypeInt64With32BitIntegerInPhp64Bit()
{
IntlTestHelper::require64Bit($this);
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$parsedValue = $formatter->parse('2,147,483,647', NumberFormatter::TYPE_INT64);
$this->assertIsInt($parsedValue);
$this->assertEquals(2147483647, $parsedValue);
$parsedValue = $formatter->parse('-2,147,483,648', NumberFormatter::TYPE_INT64);
$this->assertIsInt($parsedValue);
$this->assertEquals(-2147483647 - 1, $parsedValue);
}
/**
* If PHP is compiled in 32bit mode, the returned value for a 64bit integer are float numbers.
*/
public function testParseTypeInt64With64BitIntegerInPhp32Bit()
{
IntlTestHelper::require32Bit($this);
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
// int 64 using only 32 bit range strangeness
$parsedValue = $formatter->parse('2,147,483,648', NumberFormatter::TYPE_INT64);
$this->assertIsFloat($parsedValue);
$this->assertEquals(2147483648, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range.');
$parsedValue = $formatter->parse('-2,147,483,649', NumberFormatter::TYPE_INT64);
$this->assertIsFloat($parsedValue);
$this->assertEquals(-2147483649, $parsedValue, '->parse() TYPE_INT64 does not use true 64 bit integers, using only the 32 bit range.');
}
/**
* If PHP is compiled in 64bit mode, the returned value for a 64bit integer are 32bit integer numbers.
*/
public function testParseTypeInt64With64BitIntegerInPhp64Bit()
{
IntlTestHelper::require64Bit($this);
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$parsedValue = $formatter->parse('2,147,483,648', NumberFormatter::TYPE_INT64);
$this->assertIsInt($parsedValue);
$this->assertEquals(2147483648, $parsedValue, '->parse() TYPE_INT64 uses true 64 bit integers (PHP >= 5.3.14 and PHP >= 5.4.4).');
$parsedValue = $formatter->parse('-2,147,483,649', NumberFormatter::TYPE_INT64);
$this->assertIsInt($parsedValue);
$this->assertEquals(-2147483649, $parsedValue, '->parse() TYPE_INT64 uses true 64 bit integers (PHP >= 5.3.14 and PHP >= 5.4.4).');
}
/**
* @dataProvider parseTypeDoubleProvider
*/
public function testParseTypeDouble($value, $expectedValue)
{
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$parsedValue = $formatter->parse($value, NumberFormatter::TYPE_DOUBLE);
$this->assertEqualsWithDelta($expectedValue, $parsedValue, 0.001);
}
public function parseTypeDoubleProvider()
{
return [
['1', (float) 1],
['1.1', 1.1],
['9,223,372,036,854,775,808', 9223372036854775808],
['-9,223,372,036,854,775,809', -9223372036854775809],
];
}
public function testParseTypeCurrency()
{
if (\PHP_VERSION_ID >= 80000) {
$this->expectException(\ValueError::class);
} elseif (method_exists($this, 'expectWarning')) {
$this->expectWarning();
} else {
$this->expectException(Warning::class);
}
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->parse('1', NumberFormatter::TYPE_CURRENCY);
}
public function testParseWithNotNullPositionValue()
{
$position = 1;
$formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL);
$formatter->parse('123', NumberFormatter::TYPE_DOUBLE, $position);
$this->assertEquals(3, $position);
}
/**
* @param string $locale
* @param null $style
* @param null $pattern
*
* @return \NumberFormatter
*/
abstract protected function getNumberFormatter($locale = 'en', $style = null, $pattern = null);
/**
* @return string
*/
abstract protected function getIntlErrorMessage();
/**
* @return int
*/
abstract protected function getIntlErrorCode();
/**
* @param int $errorCode
*
* @return bool
*/
abstract protected function isIntlFailure($errorCode);
}