Skip to content

[Form] Improved multi-byte handling of NumberToLocalizedStringTransformer #7902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 3, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ public function transform($value)
throw new TransformationFailedException($formatter->getErrorMessage());
}

// Convert fixed spaces to normal ones
$value = str_replace("\xc2\xa0", ' ', $value);

return $value;
}

Expand Down Expand Up @@ -130,19 +133,31 @@ public function reverseTransform($value)
throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like');
}

if (function_exists('mb_detect_encoding') && false !== $encoding = mb_detect_encoding($value)) {
$strlen = function ($string) use ($encoding) {
return mb_strlen($string, $encoding);
};
$substr = function ($string, $offset, $length) use ($encoding) {
return mb_substr($string, $offset, $length, $encoding);
};
} else {
$strlen = 'strlen';
$substr = 'substr';
}

$length = $strlen($value);

// After parsing, position holds the index of the character where the
// parsing stopped
if ($position < strlen($value)) {
if ($position < $length) {
// Check if there are unrecognized characters at the end of the
// number
$remainder = substr($value, $position);
// number (excluding whitespace characters)
$remainder = trim($substr($value, $position, $length), " \t\n\r\0\x0b\xc2\xa0");

// Remove all whitespace characters
if ('' !== preg_replace('/[\s\xc2\xa0]*/', '', $remainder)) {
if ('' !== $remainder) {
throw new TransformationFailedException(
sprintf('The number contains unrecognized characters: "%s"',
$remainder
));
sprintf('The number contains unrecognized characters: "%s"', $remainder)
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,52 @@ protected function setUp()
\Locale::setDefault('de_AT');
}

public function testTransform()
public function provideTransformations()
{
$transformer = new NumberToLocalizedStringTransformer();

$this->assertEquals('1', $transformer->transform(1));
$this->assertEquals('1,5', $transformer->transform(1.5));
$this->assertEquals('1234,5', $transformer->transform(1234.5));
$this->assertEquals('12345,912', $transformer->transform(12345.9123));
return array(
array(null, '', 'de_AT'),
array(1, '1', 'de_AT'),
array(1.5, '1,5', 'de_AT'),
array(1234.5, '1234,5', 'de_AT'),
array(12345.912, '12345,912', 'de_AT'),
array(1234.5, '1234,5', 'ru'),
array(1234.5, '1234,5', 'fi'),
);
}

public function testTransformEmpty()
/**
* @dataProvider provideTransformations
*/
public function testTransform($from, $to, $locale)
{
\Locale::setDefault($locale);

$transformer = new NumberToLocalizedStringTransformer();

$this->assertSame('', $transformer->transform(null));
$this->assertSame($to, $transformer->transform($from));
}

public function provideTransformationsWithGrouping()
{
return array(
array(1234.5, '1.234,5', 'de_AT'),
array(12345.912, '12.345,912', 'de_AT'),
array(1234.5, '1 234,5', 'fr'),
array(1234.5, '1 234,5', 'ru'),
array(1234.5, '1 234,5', 'fi'),
);
}

public function testTransformWithGrouping()
/**
* @dataProvider provideTransformationsWithGrouping
*/
public function testTransformWithGrouping($from, $to, $locale)
{
\Locale::setDefault($locale);

$transformer = new NumberToLocalizedStringTransformer(null, true);

$this->assertEquals('1.234,5', $transformer->transform(1234.5));
$this->assertEquals('12.345,912', $transformer->transform(12345.9123));
$this->assertSame($to, $transformer->transform($from));
}

public function testTransformWithPrecision()
Expand All @@ -65,30 +88,48 @@ public function testTransformWithRoundingMode()

}

public function testReverseTransform()
/**
* @dataProvider provideTransformations
*/
public function testReverseTransform($to, $from, $locale)
{
\Locale::setDefault($locale);

$transformer = new NumberToLocalizedStringTransformer();

$this->assertEquals(1, $transformer->reverseTransform('1'));
$this->assertEquals(1.5, $transformer->reverseTransform('1,5'));
$this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
$this->assertEquals(12345.912, $transformer->reverseTransform('12345,912'));
$this->assertEquals($to, $transformer->reverseTransform($from));
}

public function testReverseTransformEmpty()
/**
* @dataProvider provideTransformationsWithGrouping
*/
public function testReverseTransformWithGrouping($to, $from, $locale)
{
$transformer = new NumberToLocalizedStringTransformer();
\Locale::setDefault($locale);

$transformer = new NumberToLocalizedStringTransformer(null, true);

$this->assertEquals($to, $transformer->reverseTransform($from));
}

// https://github.com/symfony/symfony/issues/7609
public function testReverseTransformWithGroupingAndFixedSpaces()
{
if (!extension_loaded('mbstring')) {
$this->markTestSkipped('The "mbstring" extension is required for this test.');
}

\Locale::setDefault('ru');

$transformer = new NumberToLocalizedStringTransformer(null, true);

$this->assertNull($transformer->reverseTransform(''));
$this->assertEquals(1234.5, $transformer->reverseTransform("1\xc2\xa0234,5"));
}

public function testReverseTransformWithGrouping()
public function testReverseTransformWithGroupingButWithoutGroupSeparator()
{
$transformer = new NumberToLocalizedStringTransformer(null, true);

// completely valid format
$this->assertEquals(1234.5, $transformer->reverseTransform('1.234,5'));
$this->assertEquals(12345.912, $transformer->reverseTransform('12.345,912'));
// omit group separator
$this->assertEquals(1234.5, $transformer->reverseTransform('1234,5'));
$this->assertEquals(12345.912, $transformer->reverseTransform('12345,912'));
Expand Down Expand Up @@ -299,6 +340,7 @@ public function testReverseTransformDisallowsLeadingExtraCharacters()

/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo3"
*/
public function testReverseTransformDisallowsCenteredExtraCharacters()
{
Expand All @@ -309,11 +351,63 @@ public function testReverseTransformDisallowsCenteredExtraCharacters()

/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo8"
*/
public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte()
{
if (!extension_loaded('mbstring')) {
$this->markTestSkipped('The "mbstring" extension is required for this test.');
}

\Locale::setDefault('ru');

$transformer = new NumberToLocalizedStringTransformer(null, true);

$transformer->reverseTransform("12\xc2\xa0345,67foo8");
}

/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo8"
*/
public function testReverseTransformIgnoresTrailingSpacesInExceptionMessage()
{
if (!extension_loaded('mbstring')) {
$this->markTestSkipped('The "mbstring" extension is required for this test.');
}

\Locale::setDefault('ru');

$transformer = new NumberToLocalizedStringTransformer(null, true);

$transformer->reverseTransform("12\xc2\xa0345,67foo8 \xc2\xa0\t");
}

/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo"
*/
public function testReverseTransformDisallowsTrailingExtraCharacters()
{
$transformer = new NumberToLocalizedStringTransformer();

$transformer->reverseTransform('123foo');
}

/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage The number contains unrecognized characters: "foo"
*/
public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
{
if (!extension_loaded('mbstring')) {
$this->markTestSkipped('The "mbstring" extension is required for this test.');
}

\Locale::setDefault('ru');

$transformer = new NumberToLocalizedStringTransformer(null, true);

$transformer->reverseTransform("12\xc2\xa0345,678foo");
}
}