Merge branch '2.3' into 2.4
* 2.3: [Console]Improve formatter for double-width character Lower mbstring dep, remove it for Yaml and CssSelector components [Security] Add check for supported attributes in AclVoter [Form] Fixed TrimListenerTest as of PHP 5.5 Added more IDE links [DependencyInjection] Fix parameter description in ConfigurationExtensionInterface [Finder] fixed typehint of the Finder::addAdapter() method [TwigBridge][Transchoice] set %count% from the current context. [DependencyInjection] Fix travis unit tests Update PHPUnit before run [Validator] fixed wrong test [WebProfilerBundle] added test case for #10773 [WebProfilerBundle] fixed profiler homepage, fixed #10806 [WebProfilerBundle] Added test case for #10806 changed travis to run on the nightly builds of HHVM until everything gets stable Fixed issue #5427 Allow URLs that don't contain a path Conflicts: .travis.yml
This commit is contained in:
commit
934cd28ba6
15
.travis.yml
15
.travis.yml
@ -6,22 +6,23 @@ php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
- hhvm-nightly
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
- php: hhvm-nightly
|
||||
|
||||
services: mongodb
|
||||
|
||||
before_script:
|
||||
- travis_retry sudo apt-get install parallel
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ] && [ $(php -r "echo PHP_MINOR_VERSION;") -le 4 ]; then echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm-nightly" ]; then echo "" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm-nightly" ]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm-nightly" ] && [ $(php -r "echo PHP_MINOR_VERSION;") -le 4 ]; then echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm-nightly" ]; then echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- sh -c 'if [ "$TRAVIS_PHP_VERSION" != "hhvm-nightly" ]; then echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi;'
|
||||
- COMPOSER_ROOT_VERSION=dev-master composer --prefer-source --dev install
|
||||
- wget https://phar.phpunit.de/phpunit.phar && rm `which phpunit` && sudo cp phpunit.phar /usr/local/bin/phpunit && sudo chmod +x /usr/local/bin/phpunit
|
||||
|
||||
script:
|
||||
- ls -d src/Symfony/*/* | parallel --gnu --keep-order 'echo "Running {} tests"; phpunit --exclude-group tty,benchmark {};' || exit 1
|
||||
|
@ -98,11 +98,15 @@ class TransNode extends \Twig_Node
|
||||
foreach ($matches[1] as $var) {
|
||||
$key = new \Twig_Node_Expression_Constant('%'.$var.'%', $body->getLine());
|
||||
if (!$vars->hasElement($key)) {
|
||||
if ('count' === $var) {
|
||||
$vars->addElement($this->getNode('count'), $key);
|
||||
} else {
|
||||
$varExpr = new \Twig_Node_Expression_Name($var, $body->getLine());
|
||||
$varExpr->setAttribute('ignore_strict_check', $ignoreStrictCheck);
|
||||
$vars->addElement($varExpr, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array(new \Twig_Node_Expression_Constant(str_replace('%%', '%', trim($msg)), $body->getLine()), $vars);
|
||||
}
|
||||
|
@ -96,6 +96,8 @@ class TranslationExtensionTest extends \PHPUnit_Framework_TestCase
|
||||
'There is 5 apples (Symfony2)', array('count' => 5)),
|
||||
array('{% transchoice count into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
|
||||
'There is no apples', array('count' => 0)),
|
||||
array('{% transchoice 5 into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
|
||||
'There is 5 apples'),
|
||||
|
||||
// trans filter
|
||||
array('{{ "Hello"|trans }}', 'Hello'),
|
||||
|
@ -398,6 +398,8 @@ class FrameworkExtension extends Extension
|
||||
$links = array(
|
||||
'textmate' => 'txmt://open?url=file://%%f&line=%%l',
|
||||
'macvim' => 'mvim://open?url=file://%%f&line=%%l',
|
||||
'emacs' => 'emacs://open?url=file://%file&line=%line',
|
||||
'sublime' => 'subl://open?url=file://%file&line=%line',
|
||||
);
|
||||
|
||||
$container->setParameter('templating.helper.code.file_link_format', isset($links[$ide]) ? $links[$ide] : $ide);
|
||||
|
@ -232,7 +232,7 @@ class ProfilerController
|
||||
$session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
|
||||
}
|
||||
|
||||
if (null === $token) {
|
||||
if ('empty' === $token || null === $token) {
|
||||
return new Response('', 200, array('Content-Type' => 'text/html'));
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,77 @@
|
||||
<?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\Bundle\WebProfilerBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||
use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profile;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ProfilerControllerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider getEmptyTokenCases
|
||||
*/
|
||||
public function testEmptyToken($token)
|
||||
{
|
||||
$urlGenerator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
|
||||
$twig = $this->getMock('Twig_Environment');
|
||||
$profiler = $this
|
||||
->getMockBuilder('Symfony\Component\HttpKernel\Profiler\Profiler')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$controller = new ProfilerController($urlGenerator, $profiler, $twig, array());
|
||||
|
||||
$response = $controller->toolbarAction(Request::create('/_wdt/empty'), $token);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function getEmptyTokenCases()
|
||||
{
|
||||
return array(
|
||||
array(null),
|
||||
// "empty" is also a valid empty token case, see https://github.com/symfony/symfony/issues/10806
|
||||
array('empty'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testReturns404onTokenNotFound()
|
||||
{
|
||||
$urlGenerator = $this->getMock('Symfony\Component\Routing\Generator\UrlGeneratorInterface');
|
||||
$twig = $this->getMock('Twig_Environment');
|
||||
$profiler = $this
|
||||
->getMockBuilder('Symfony\Component\HttpKernel\Profiler\Profiler')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$controller = new ProfilerController($urlGenerator, $profiler, $twig, array());
|
||||
|
||||
$profiler
|
||||
->expects($this->exactly(2))
|
||||
->method('loadProfile')
|
||||
->will($this->returnCallback(function ($token) {
|
||||
if ('found' == $token) {
|
||||
return new Profile($token);
|
||||
}
|
||||
|
||||
return;
|
||||
}))
|
||||
;
|
||||
|
||||
$response = $controller->toolbarAction(Request::create('/_wdt/found'), 'found');
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
|
||||
$response = $controller->toolbarAction(Request::create('/_wdt/notFound'), 'notFound');
|
||||
$this->assertEquals(404, $response->getStatusCode());
|
||||
}
|
||||
}
|
@ -152,12 +152,12 @@ class Cookie
|
||||
);
|
||||
|
||||
if (null !== $url) {
|
||||
if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host']) || !isset($urlParts['path'])) {
|
||||
if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host'])) {
|
||||
throw new \InvalidArgumentException(sprintf('The URL "%s" is not valid.', $url));
|
||||
}
|
||||
|
||||
$values['domain'] = $urlParts['host'];
|
||||
$values['path'] = substr($urlParts['path'], 0, strrpos($urlParts['path'], '/'));
|
||||
$values['path'] = isset($urlParts['path']) ? substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')) : '';
|
||||
}
|
||||
|
||||
foreach ($parts as $part) {
|
||||
|
@ -75,6 +75,8 @@ class CookieTest extends \PHPUnit_Framework_TestCase
|
||||
public function testFromStringWithUrl()
|
||||
{
|
||||
$this->assertEquals('foo=bar; domain=www.example.com; path=/', (string) Cookie::FromString('foo=bar', 'http://www.example.com/'));
|
||||
$this->assertEquals('foo=bar; domain=www.example.com; path=/', (string) Cookie::FromString('foo=bar', 'http://www.example.com'));
|
||||
$this->assertEquals('foo=bar; domain=www.example.com; path=/', (string) Cookie::FromString('foo=bar', 'http://www.example.com?foo'));
|
||||
$this->assertEquals('foo=bar; domain=www.example.com; path=/foo', (string) Cookie::FromString('foo=bar', 'http://www.example.com/foo/bar'));
|
||||
$this->assertEquals('foo=bar; domain=www.example.com; path=/', (string) Cookie::FromString('foo=bar; path=/', 'http://www.example.com/foo/bar'));
|
||||
$this->assertEquals('foo=bar; domain=www.myotherexample.com; path=/', (string) Cookie::FromString('foo=bar; domain=www.myotherexample.com', 'http://www.example.com/'));
|
||||
|
@ -680,21 +680,11 @@ class Application
|
||||
*/
|
||||
public function renderException($e, $output)
|
||||
{
|
||||
$strlen = function ($string) {
|
||||
if (!function_exists('mb_strlen')) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string)) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
return mb_strlen($string, $encoding);
|
||||
};
|
||||
|
||||
do {
|
||||
$title = sprintf(' [%s] ', get_class($e));
|
||||
$len = $strlen($title);
|
||||
|
||||
$len = $this->stringWidth($title);
|
||||
|
||||
$width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
|
||||
// HHVM only accepts 32 bits integer in str_split, even when PHP_INT_MAX is a 64 bit integer: https://github.com/facebook/hhvm/issues/1327
|
||||
if (defined('HHVM_VERSION') && $width > 1 << 31) {
|
||||
@ -703,9 +693,9 @@ class Application
|
||||
$formatter = $output->getFormatter();
|
||||
$lines = array();
|
||||
foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) {
|
||||
foreach (str_split($line, $width - 4) as $line) {
|
||||
foreach ($this->splitStringByWidth($line, $width - 4) as $line) {
|
||||
// pre-format lines to get the right string length
|
||||
$lineLength = $strlen(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4;
|
||||
$lineLength = $this->stringWidth(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4;
|
||||
$lines[] = array($line, $lineLength);
|
||||
|
||||
$len = max($lineLength, $len);
|
||||
@ -714,7 +704,7 @@ class Application
|
||||
|
||||
$messages = array('', '');
|
||||
$messages[] = $emptyLine = $formatter->format(sprintf('<error>%s</error>', str_repeat(' ', $len)));
|
||||
$messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $strlen($title)))));
|
||||
$messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $this->stringWidth($title)))));
|
||||
foreach ($lines as $line) {
|
||||
$messages[] = $formatter->format(sprintf('<error> %s %s</error>', $line[0], str_repeat(' ', $len - $line[1])));
|
||||
}
|
||||
@ -1101,4 +1091,53 @@ class Application
|
||||
|
||||
return array_keys($alternatives);
|
||||
}
|
||||
|
||||
private function stringWidth($string)
|
||||
{
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string)) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
return mb_strwidth($string, $encoding);
|
||||
}
|
||||
|
||||
private function splitStringByWidth($string, $width)
|
||||
{
|
||||
// str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly.
|
||||
// additionally, array_slice() is not enough as some character has doubled width.
|
||||
// we need a function to split string not by character count but by string width
|
||||
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
return str_split($string, $width);
|
||||
}
|
||||
|
||||
if (false === $encoding = mb_detect_encoding($string)) {
|
||||
return str_split($string, $width);
|
||||
}
|
||||
|
||||
$utf8String = mb_convert_encoding($string, 'utf8', $encoding);
|
||||
$lines = array();
|
||||
$line = '';
|
||||
foreach (preg_split('//u', $utf8String) as $char) {
|
||||
// test if $char could be appended to current line
|
||||
if (mb_strwidth($line.$char) <= $width) {
|
||||
$line .= $char;
|
||||
continue;
|
||||
}
|
||||
// if not, push current line to array and make new line
|
||||
$lines[] = str_pad($line, $width);
|
||||
$line = $char;
|
||||
}
|
||||
if (strlen($line)) {
|
||||
$lines[] = count($lines) ? str_pad($line, $width) : $line;
|
||||
}
|
||||
|
||||
mb_convert_variables($encoding, 'utf8', $lines);
|
||||
|
||||
return $lines;
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ abstract class Helper implements HelperInterface
|
||||
*/
|
||||
protected function strlen($string)
|
||||
{
|
||||
if (!function_exists('mb_strlen')) {
|
||||
if (!function_exists('mb_strwidth')) {
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
@ -57,6 +57,6 @@ abstract class Helper implements HelperInterface
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
return mb_strlen($string, $encoding);
|
||||
return mb_strwidth($string, $encoding);
|
||||
}
|
||||
}
|
||||
|
@ -523,6 +523,33 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception4.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal');
|
||||
}
|
||||
|
||||
public function testRenderExceptionWithDoubleWidthCharacters()
|
||||
{
|
||||
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
|
||||
$application->setAutoExit(false);
|
||||
$application->expects($this->any())
|
||||
->method('getTerminalWidth')
|
||||
->will($this->returnValue(120));
|
||||
$application->register('foo')->setCode(function () {throw new \Exception('エラーメッセージ');});
|
||||
$tester = new ApplicationTester($application);
|
||||
|
||||
$tester->run(array('command' => 'foo'), array('decorated' => false));
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1.txt', $tester->getDisplay(true), '->renderException() renderes a pretty exceptions with previous exceptions');
|
||||
|
||||
$tester->run(array('command' => 'foo'), array('decorated' => true));
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1decorated.txt', $tester->getDisplay(true), '->renderException() renderes a pretty exceptions with previous exceptions');
|
||||
|
||||
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
|
||||
$application->setAutoExit(false);
|
||||
$application->expects($this->any())
|
||||
->method('getTerminalWidth')
|
||||
->will($this->returnValue(32));
|
||||
$application->register('foo')->setCode(function () {throw new \Exception('コマンドの実行中にエラーが発生しました。');});
|
||||
$tester = new ApplicationTester($application);
|
||||
$tester->run(array('command' => 'foo'), array('decorated' => false));
|
||||
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth2.txt', $tester->getDisplay(true), '->renderException() wraps messages when they are bigger than the terminal');
|
||||
}
|
||||
|
||||
public function testRun()
|
||||
{
|
||||
$application = new Application();
|
||||
|
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
|
||||
[Exception]
|
||||
エラーメッセージ
|
||||
|
||||
|
||||
|
||||
foo
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
[37;41m [0m
|
||||
[37;41m [Exception] [0m
|
||||
[37;41m エラーメッセージ [0m
|
||||
[37;41m [0m
|
||||
|
||||
|
||||
[32mfoo[0m
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
|
||||
[Exception]
|
||||
コマンドの実行中にエラーが
|
||||
発生しました。
|
||||
|
||||
|
||||
|
||||
foo
|
||||
|
||||
|
@ -54,7 +54,7 @@ class FormatterHelperTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testFormatBlockWithDiacriticLetters()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
$this->markTestSkipped('This test requires mbstring to work.');
|
||||
}
|
||||
|
||||
@ -69,6 +69,21 @@ class FormatterHelperTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatBlockWithDoubleWidthDiacriticLetters()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
$this->markTestSkipped('This test requires mbstring to work.');
|
||||
}
|
||||
$formatter = new FormatterHelper();
|
||||
$this->assertEquals(
|
||||
'<error> </error>'."\n" .
|
||||
'<error> 表示するテキスト </error>'."\n" .
|
||||
'<error> </error>',
|
||||
$formatter->formatBlock('表示するテキスト', 'error', true),
|
||||
'::formatBlock() formats a message in a block'
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatBlockLGEscaping()
|
||||
{
|
||||
$formatter = new FormatterHelper();
|
||||
|
@ -65,14 +65,18 @@ class TokenizerEscaping
|
||||
*/
|
||||
private function replaceUnicodeSequences($value)
|
||||
{
|
||||
return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function (array $match) {
|
||||
$code = $match[1];
|
||||
return preg_replace_callback($this->patterns->getUnicodeEscapePattern(), function ($match) {
|
||||
$c = hexdec($match[1]);
|
||||
|
||||
if (bin2hex($code) > 0xFFFD) {
|
||||
$code = '\\FFFD';
|
||||
if (0x80 > $c %= 0x200000) {
|
||||
return chr($c);
|
||||
}
|
||||
if (0x800 > $c) {
|
||||
return chr(0xC0 | $c>>6).chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
if (0x10000 > $c) {
|
||||
return chr(0xE0 | $c>>12).chr(0x80 | $c>>6 & 0x3F).chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
|
||||
return mb_convert_encoding(pack('H*', $code), 'UTF-8', 'UCS-2BE');
|
||||
}, $value);
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ interface ConfigurationExtensionInterface
|
||||
/**
|
||||
* Returns extension configuration
|
||||
*
|
||||
* @param array $config $config An array of configuration values
|
||||
* @param array $config An array of configuration values
|
||||
* @param ContainerBuilder $container A ContainerBuilder instance
|
||||
*
|
||||
* @return ConfigurationInterface|null The configuration or null
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
|
@ -94,7 +94,7 @@ class Finder implements \IteratorAggregate, \Countable
|
||||
*
|
||||
* @return Finder The current Finder instance
|
||||
*/
|
||||
public function addAdapter(Adapter\AdapterInterface $adapter, $priority = 0)
|
||||
public function addAdapter(AdapterInterface $adapter, $priority = 0)
|
||||
{
|
||||
$this->adapters[$adapter->getName()] = array(
|
||||
'adapter' => $adapter,
|
||||
|
@ -195,25 +195,19 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
$length = mb_strlen($value, $encoding);
|
||||
$remainder = mb_substr($value, $position, $length, $encoding);
|
||||
} else {
|
||||
$strlen = 'strlen';
|
||||
$substr = 'substr';
|
||||
$length = strlen($value);
|
||||
$remainder = substr($value, $position, $length);
|
||||
}
|
||||
|
||||
$length = $strlen($value);
|
||||
|
||||
// After parsing, position holds the index of the character where the
|
||||
// parsing stopped
|
||||
if ($position < $length) {
|
||||
// Check if there are unrecognized characters at the end of the
|
||||
// number (excluding whitespace characters)
|
||||
$remainder = trim($substr($value, $position, $length), " \t\n\r\0\x0b\xc2\xa0");
|
||||
$remainder = trim($remainder, " \t\n\r\0\x0b\xc2\xa0");
|
||||
|
||||
if ('' !== $remainder) {
|
||||
throw new TransformationFailedException(
|
||||
|
@ -215,7 +215,7 @@ class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
|
||||
// https://github.com/symfony/symfony/issues/7609
|
||||
public function testReverseTransformWithGroupingAndFixedSpaces()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
@ -537,7 +537,7 @@ class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
@ -554,7 +554,7 @@ class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testReverseTransformIgnoresTrailingSpacesInExceptionMessage()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
@ -582,7 +582,7 @@ class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
if (!function_exists('mb_detect_encoding')) {
|
||||
$this->markTestSkipped('The "mbstring" extension is required for this test.');
|
||||
}
|
||||
|
||||
|
@ -41,32 +41,65 @@ class TrimListenerTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider codePointProvider
|
||||
* @dataProvider spaceProvider
|
||||
*/
|
||||
public function testTrimUtf8($chars)
|
||||
public function testTrimUtf8Separators($hex)
|
||||
{
|
||||
if (!function_exists('mb_check_encoding')) {
|
||||
$this->markTestSkipped('The "mb_check_encoding" function is not available');
|
||||
if (!function_exists('mb_convert_encoding')) {
|
||||
$this->markTestSkipped('The "mb_convert_encoding" function is not available');
|
||||
}
|
||||
|
||||
$data = mb_convert_encoding(pack('H*', implode('', $chars)), 'UTF-8', 'UCS-2BE');
|
||||
$data = $data."ab\ncd".$data;
|
||||
// Convert hexadecimal representation into binary
|
||||
// H: hex string, high nibble first (UCS-2BE)
|
||||
// *: repeat until end of string
|
||||
$binary = pack('H*', $hex);
|
||||
|
||||
// Convert UCS-2BE to UTF-8
|
||||
$symbol = mb_convert_encoding($binary, 'UTF-8', 'UCS-2BE');
|
||||
$symbol = $symbol."ab\ncd".$symbol;
|
||||
|
||||
$form = $this->getMock('Symfony\Component\Form\Test\FormInterface');
|
||||
$event = new FormEvent($form, $data);
|
||||
$event = new FormEvent($form, $symbol);
|
||||
|
||||
$filter = new TrimListener();
|
||||
$filter->preSubmit($event);
|
||||
|
||||
$this->assertSame("ab\ncd", $event->getData(), 'TrimListener should trim character(s): '.implode(', ', $chars));
|
||||
$this->assertSame("ab\ncd", $event->getData());
|
||||
}
|
||||
|
||||
public function codePointProvider()
|
||||
public function spaceProvider()
|
||||
{
|
||||
return array(
|
||||
'General category: Separator' => array(array('0020', '00A0', '1680', '180E', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '200A', '2028', '2029', '202F', '205F', '3000')),
|
||||
'General category: Other, control' => array(array('0009', '000A', '000B', '000C', '000D', '0085')),
|
||||
//'General category: Other, format. ZERO WIDTH SPACE' => array(array('200B')),
|
||||
// separators
|
||||
array('0020'),
|
||||
array('00A0'),
|
||||
array('1680'),
|
||||
// array('180E'),
|
||||
array('2000'),
|
||||
array('2001'),
|
||||
array('2002'),
|
||||
array('2003'),
|
||||
array('2004'),
|
||||
array('2005'),
|
||||
array('2006'),
|
||||
array('2007'),
|
||||
array('2008'),
|
||||
array('2009'),
|
||||
array('200A'),
|
||||
array('2028'),
|
||||
array('2029'),
|
||||
array('202F'),
|
||||
array('205F'),
|
||||
array('3000'),
|
||||
// controls
|
||||
array('0009'),
|
||||
array('000A'),
|
||||
array('000B'),
|
||||
array('000C'),
|
||||
array('000D'),
|
||||
array('0085'),
|
||||
// zero width space
|
||||
// array('200B'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class AclVoterTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testSupportsAttribute($attribute, $supported)
|
||||
{
|
||||
list($voter,, $permissionMap,,) = $this->getVoter();
|
||||
list($voter,, $permissionMap,,) = $this->getVoter(true, false);
|
||||
|
||||
$permissionMap
|
||||
->expects($this->once())
|
||||
@ -39,6 +39,16 @@ class AclVoterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertSame($supported, $voter->supportsAttribute($attribute));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getSupportsAttributeNonStringTests
|
||||
*/
|
||||
public function testSupportsAttributeNonString($attribute)
|
||||
{
|
||||
list($voter,,,,,) = $this->getVoter(true, false);
|
||||
|
||||
$this->assertFalse($voter->supportsAttribute($attribute));
|
||||
}
|
||||
|
||||
public function getSupportsAttributeTests()
|
||||
{
|
||||
return array(
|
||||
@ -47,6 +57,16 @@ class AclVoterTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function getSupportsAttributeNonStringTests()
|
||||
{
|
||||
return array(
|
||||
array(new \stdClass()),
|
||||
array(1),
|
||||
array(true),
|
||||
array(array()),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getSupportsClassTests
|
||||
*/
|
||||
@ -387,13 +407,20 @@ class AclVoterTest extends \PHPUnit_Framework_TestCase
|
||||
return $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
|
||||
}
|
||||
|
||||
protected function getVoter($allowIfObjectIdentityUnavailable = true)
|
||||
protected function getVoter($allowIfObjectIdentityUnavailable = true, $alwaysContains = true)
|
||||
{
|
||||
$provider = $this->getMock('Symfony\Component\Security\Acl\Model\AclProviderInterface');
|
||||
$permissionMap = $this->getMock('Symfony\Component\Security\Acl\Permission\PermissionMapInterface');
|
||||
$oidStrategy = $this->getMock('Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface');
|
||||
$sidStrategy = $this->getMock('Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface');
|
||||
|
||||
if ($alwaysContains) {
|
||||
$permissionMap
|
||||
->expects($this->any())
|
||||
->method('contains')
|
||||
->will($this->returnValue(true));
|
||||
}
|
||||
|
||||
return array(
|
||||
new AclVoter($provider, $oidStrategy, $sidStrategy, $permissionMap, null, $allowIfObjectIdentityUnavailable),
|
||||
$provider,
|
||||
|
@ -48,12 +48,16 @@ class AclVoter implements VoterInterface
|
||||
|
||||
public function supportsAttribute($attribute)
|
||||
{
|
||||
return $this->permissionMap->contains($attribute);
|
||||
return is_string($attribute) && $this->permissionMap->contains($attribute);
|
||||
}
|
||||
|
||||
public function vote(TokenInterface $token, $object, array $attributes)
|
||||
{
|
||||
foreach ($attributes as $attribute) {
|
||||
if (!$this->supportsAttribute($attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $masks = $this->permissionMap->getMasks($attribute, $object)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ class PoFileLoader extends ArrayLoader implements LoaderInterface
|
||||
private function addMessage(array &$messages, array $item)
|
||||
{
|
||||
if (is_array($item['translated'])) {
|
||||
$messages[$item['ids']['singular']] = stripslashes($item['translated'][0]);
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
|
||||
if (isset($item['ids']['plural'])) {
|
||||
$plurals = $item['translated'];
|
||||
// PO are by definition indexed so sort by index.
|
||||
@ -172,7 +172,7 @@ class PoFileLoader extends ArrayLoader implements LoaderInterface
|
||||
$messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
|
||||
}
|
||||
} elseif (!empty($item['ids']['singular'])) {
|
||||
$messages[$item['ids']['singular']] = stripslashes($item['translated']);
|
||||
$messages[$item['ids']['singular']] = stripcslashes($item['translated']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class IcuResFileDumperTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testDump()
|
||||
{
|
||||
if (!extension_loaded('mbstring')) {
|
||||
if (!function_exists('mb_convert_encoding')) {
|
||||
$this->markTestSkipped('This test requires mbstring to work.');
|
||||
}
|
||||
|
||||
|
@ -79,10 +79,16 @@ class StaticMethodLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
public function testLoadClassMetadataIgnoresAbstractMethods()
|
||||
{
|
||||
$loader = new StaticMethodLoader('loadMetadata');
|
||||
$caught = false;
|
||||
try {
|
||||
include __DIR__ . '/AbstractMethodStaticLoader.php';
|
||||
$this->fail('AbstractMethodStaticLoader should produce a strict standard error.');
|
||||
include __DIR__.'/AbstractMethodStaticLoader.php';
|
||||
} catch (\Exception $e) {
|
||||
// catching the PHP notice that is converted to an exception by PHPUnit
|
||||
$caught = true;
|
||||
}
|
||||
|
||||
if (!$caught) {
|
||||
$this->fail('AbstractMethodStaticLoader should produce a strict standard error.');
|
||||
}
|
||||
|
||||
$metadata = new ClassMetadata(__NAMESPACE__.'\AbstractMethodStaticLoader');
|
||||
|
@ -55,7 +55,7 @@ class Parser
|
||||
$this->currentLine = '';
|
||||
$this->lines = explode("\n", $this->cleanup($value));
|
||||
|
||||
if (function_exists('mb_detect_encoding') && false === mb_detect_encoding($value, 'UTF-8', true)) {
|
||||
if (!preg_match('//u', $value)) {
|
||||
throw new ParseException('The YAML value does not appear to be valid UTF-8.');
|
||||
}
|
||||
|
||||
|
@ -33,12 +33,6 @@ class ParserTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testSpecifications($file, $expected, $yaml, $comment)
|
||||
{
|
||||
if ('escapedCharacters' == $file) {
|
||||
if (!function_exists('iconv') && !function_exists('mb_convert_encoding')) {
|
||||
$this->markTestSkipped('The iconv and mbstring extensions are not available.');
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertEquals($expected, var_export($this->parser->parse($yaml), true), $comment);
|
||||
}
|
||||
|
||||
@ -446,8 +440,8 @@ EOF;
|
||||
|
||||
public function testNonUtf8Exception()
|
||||
{
|
||||
if (!function_exists('mb_detect_encoding') || !function_exists('iconv')) {
|
||||
$this->markTestSkipped('Exceptions for non-utf8 charsets require the mb_detect_encoding() and iconv() functions.');
|
||||
if (!function_exists('iconv')) {
|
||||
$this->markTestSkipped('Exceptions for non-utf8 charsets require the iconv() function.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class Unescaper
|
||||
{
|
||||
// Parser and Inline assume UTF-8 encoding, so escaped Unicode characters
|
||||
// must be converted to that encoding.
|
||||
// @deprecated since 2.5, to be removed in 3.0
|
||||
const ENCODING = 'UTF-8';
|
||||
|
||||
// Regex fragment that matches an escaped character in a double quoted
|
||||
@ -80,13 +81,13 @@ class Unescaper
|
||||
case 'n':
|
||||
return "\n";
|
||||
case 'v':
|
||||
return "\xb";
|
||||
return "\xB";
|
||||
case 'f':
|
||||
return "\xc";
|
||||
return "\xC";
|
||||
case 'r':
|
||||
return "\xd";
|
||||
return "\r";
|
||||
case 'e':
|
||||
return "\x1b";
|
||||
return "\x1B";
|
||||
case ' ':
|
||||
return ' ';
|
||||
case '"':
|
||||
@ -97,50 +98,44 @@ class Unescaper
|
||||
return '\\';
|
||||
case 'N':
|
||||
// U+0085 NEXT LINE
|
||||
return $this->convertEncoding("\x00\x85", self::ENCODING, 'UCS-2BE');
|
||||
return "\xC2\x85";
|
||||
case '_':
|
||||
// U+00A0 NO-BREAK SPACE
|
||||
return $this->convertEncoding("\x00\xA0", self::ENCODING, 'UCS-2BE');
|
||||
return "\xC2\xA0";
|
||||
case 'L':
|
||||
// U+2028 LINE SEPARATOR
|
||||
return $this->convertEncoding("\x20\x28", self::ENCODING, 'UCS-2BE');
|
||||
return "\xE2\x80\xA8";
|
||||
case 'P':
|
||||
// U+2029 PARAGRAPH SEPARATOR
|
||||
return $this->convertEncoding("\x20\x29", self::ENCODING, 'UCS-2BE');
|
||||
return "\xE2\x80\xA9";
|
||||
case 'x':
|
||||
$char = pack('n', hexdec(substr($value, 2, 2)));
|
||||
|
||||
return $this->convertEncoding($char, self::ENCODING, 'UCS-2BE');
|
||||
return self::utf8chr(hexdec(substr($value, 2, 2)));
|
||||
case 'u':
|
||||
$char = pack('n', hexdec(substr($value, 2, 4)));
|
||||
|
||||
return $this->convertEncoding($char, self::ENCODING, 'UCS-2BE');
|
||||
return self::utf8chr(hexdec(substr($value, 2, 4)));
|
||||
case 'U':
|
||||
$char = pack('N', hexdec(substr($value, 2, 8)));
|
||||
|
||||
return $this->convertEncoding($char, self::ENCODING, 'UCS-4BE');
|
||||
return self::utf8chr(hexdec(substr($value, 2, 8)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string from one encoding to another.
|
||||
* Get the UTF-8 character for the given code point.
|
||||
*
|
||||
* @param string $value The string to convert
|
||||
* @param string $to The input encoding
|
||||
* @param string $from The output encoding
|
||||
* @param int $c The unicode code point
|
||||
*
|
||||
* @return string The string with the new encoding
|
||||
*
|
||||
* @throws \RuntimeException if no suitable encoding function is found (iconv or mbstring)
|
||||
* @return string The corresponding UTF-8 character
|
||||
*/
|
||||
private function convertEncoding($value, $to, $from)
|
||||
private static function utf8chr($c)
|
||||
{
|
||||
if (function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($value, $to, $from);
|
||||
} elseif (function_exists('iconv')) {
|
||||
return iconv($from, $to, $value);
|
||||
if (0x80 > $c %= 0x200000) {
|
||||
return chr($c);
|
||||
}
|
||||
if (0x800 > $c) {
|
||||
return chr(0xC0 | $c>>6).chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
if (0x10000 > $c) {
|
||||
return chr(0xE0 | $c>>12).chr(0x80 | $c>>6 & 0x3F).chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
|
||||
throw new \RuntimeException('No suitable convert encoding function (install the iconv or mbstring extension).');
|
||||
return chr(0xF0 | $c>>18).chr(0x80 | $c>>12 & 0x3F).chr(0x80 | $c>>6 & 0x3F).chr(0x80 | $c & 0x3F);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user