diff --git a/.gitignore b/.gitignore index 76f1ab9a39..0f504231b6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ phpunit.xml composer.phar package.tar /packages.json +/.phpunit diff --git a/.travis.yml b/.travis.yml index 09fac89e0d..d6d25cc6a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ language: php sudo: false addons: - apt_packages: - - parallel - - language-pack-fr-base + apt_packages: + - parallel + - language-pack-fr-base matrix: include: @@ -15,9 +15,8 @@ matrix: - php: 5.5 - php: 5.6 env: deps=low - - php: 5.6 + - php: 7.0 env: deps=high - - php: nightly fast_finish: true services: mongodb @@ -30,26 +29,24 @@ env: before_install: - composer self-update - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then echo "memory_limit = -1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi; - - if [[ "$TRAVIS_PHP_VERSION" != "nightly" ]] && [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini; fi; - - if [[ "$TRAVIS_PHP_VERSION" != "nightly" ]] && [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi; - - if [[ "$TRAVIS_PHP_VERSION" != "nightly" ]] && [[ "$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; - - if [[ "$TRAVIS_PHP_VERSION" != "nightly" ]] && [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then (pecl install -f memcached-2.1.0 && echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini) || echo "Let's continue without memcache extension"; fi; - - if [[ "$TRAVIS_PHP_VERSION" != "nightly" ]] && [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo "extension = $(pwd)/modules/symfony_debug.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini); fi; - - if [[ "$TRAVIS_PHP_VERSION" != "nightly" ]] && [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then php -i; fi; - # Build a standalone phpunit without symfony/yaml and that works around https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223 - - (mkdir phpunit && cd phpunit && wget https://github.com/sebastianbergmann/phpunit/archive/4.7.zip && unzip 4.7.zip && cd phpunit-4.7 && composer remove --no-update symfony/yaml && composer require --prefer-source phpunit/phpunit-mock-objects '2.3.0') - - export PHPUNIT="$(readlink -f ./phpunit/phpunit-4.7/phpunit) --colors=always" - # Set the COMPOSER_ROOT_VERSION to the right version according to the branch being built - - if [ "$TRAVIS_BRANCH" = "master" ]; then export COMPOSER_ROOT_VERSION=dev-master; else export COMPOSER_ROOT_VERSION="$TRAVIS_BRANCH".x-dev; fi; + - if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then phpenv config-rm xdebug.ini; fi; + - if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi; + - if [[ "$TRAVIS_PHP_VERSION" =~ 5.[34] ]]; then echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi; + - if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then (pecl install -f memcached-2.1.0 && echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini) || echo "Let's continue without memcache extension"; fi; + - if [[ "$TRAVIS_PHP_VERSION" = 5.* ]]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo "extension = $(pwd)/modules/symfony_debug.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini); fi; + - if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then php -i; fi; + - ./phpunit install + - export PHPUNIT="$(readlink -f ./phpunit)" install: + - if [ "$TRAVIS_BRANCH" = "master" ]; then export COMPOSER_ROOT_VERSION=dev-master; else export COMPOSER_ROOT_VERSION="$TRAVIS_BRANCH".x-dev; fi; - if [ "$deps" = "no" ]; then export SYMFONY_DEPRECATIONS_HELPER=strict; fi; - if [ "$deps" = "no" ]; then composer --prefer-source install; fi; - - components=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n') - - if [ "$deps" != "no" ]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $components; fi; + - COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n') + - if [ "$deps" != "no" ]; then php .travis.php $TRAVIS_COMMIT_RANGE $TRAVIS_BRANCH $COMPONENTS; fi; script: - - if [ "$deps" = "no" ]; then echo "$components" | parallel --gnu --keep-order 'echo -e "\\nRunning {} tests"; $PHPUNIT --exclude-group tty,benchmark,intl-data {} || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; - - if [ "$deps" = "no" ]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty || (echo -e "\\e[41mKO\\e[0m tty group" && $(exit 1)); fi; - - if [ "$deps" = "high" ]; then echo "$components" | parallel --gnu --keep-order -j10% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source update; $PHPUNIT --exclude-group tty,benchmark,intl-data,legacy || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; - - if [ "$deps" = "low" ]; then echo "$components" | parallel --gnu --keep-order -j10% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; $PHPUNIT --exclude-group tty,benchmark,intl-data || (echo -e "\\e[41mKO\\e[0m {}" && $(exit 1));'; fi; + - if [ "$deps" = "no" ]; then echo "$COMPONENTS" | parallel --gnu --keep-order 'echo -e "\\nRunning {} tests"; $PHPUNIT --exclude-group tty,benchmark,intl-data {}'; fi; + - if [ "$deps" = "no" ]; then echo -e "\\nRunning tests requiring tty"; $PHPUNIT --group tty; fi; + - if [ "$deps" = "high" ]; then echo "$COMPONENTS" | parallel --gnu --keep-order -j10% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source update; $PHPUNIT --exclude-group tty,benchmark,intl-data,legacy'; fi; + - if [ "$deps" = "low" ]; then echo "$COMPONENTS" | parallel --gnu --keep-order -j10% 'echo -e "\\nRunning {} tests"; cd {}; composer --prefer-source --prefer-lowest --prefer-stable update; $PHPUNIT --exclude-group tty,benchmark,intl-data'; fi; diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..f0484755f9 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,53 @@ +build: false +shallow_clone: true +platform: x86 +clone_folder: c:\projects\symfony + +environment: + matrix: + - PHP_EXT: 1 + - PHP_EXT: 0 + +cache: + - c:\php -> appveyor.yml + - .phpunit -> phpunit + +init: + - SET PATH=c:\php;%PATH% + - SET COMPOSER_NO_INTERACTION=1 + - SET SYMFONY_DEPRECATIONS_HELPER=strict + - SET PHP=1 + - SET ANSICON=121x90 (121x90) + +install: + - IF EXIST c:\php (SET PHP=0) ELSE (mkdir c:\php) + - cd c:\php + - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-5.4.43-nts-Win32-VC9-x86.zip + - IF %PHP%==1 7z x php-5.4.43-nts-Win32-VC9-x86.zip -y > 7z.log + - IF %PHP%==1 appveyor DownloadFile http://nebm.ist.utl.pt/~glopes/misc/intl_win/ICU-51.2-dlls.zip + - IF %PHP%==1 7z x ICU-51.2-dlls.zip -y > 7z.log + - IF %PHP%==1 cd ext + - IF %PHP%==1 appveyor DownloadFile http://nebm.ist.utl.pt/~glopes/misc/intl_win/php_intl-3.0.0-5.4-nts-vc9-x86.zip + - IF %PHP%==1 7z x php_intl-3.0.0-5.4-nts-vc9-x86.zip -y > 7z.log + - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/pecl/releases/apc/3.1.13/php_apc-3.1.13-5.4-nts-vc9-x86.zip + - IF %PHP%==1 7z x php_apc-3.1.13-5.4-nts-vc9-x86.zip -y > 7z.log + - IF %PHP%==1 cd .. + - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat + - appveyor DownloadFile https://getcomposer.org/composer.phar + - copy php.ini-production php.ini /Y + - echo date.timezone="UTC" >> php.ini + - echo extension_dir=ext >> php.ini + - echo extension=php_openssl.dll >> php.ini + - IF %PHP_EXT%==1 echo extension=php_apc.dll >> php.ini + - IF %PHP_EXT%==1 echo extension=php_intl.dll >> php.ini + - IF %PHP_EXT%==1 echo extension=php_mbstring.dll >> php.ini + - IF %PHP_EXT%==1 echo extension=php_fileinfo.dll >> php.ini + - IF %PHP_EXT%==1 echo extension=php_pdo_sqlite.dll >> php.ini + - cd c:\projects\symfony + - php phpunit install + - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) + - composer update --prefer-source --no-progress --ansi + +test_script: + - cd c:\projects\symfony + - php phpunit symfony --exclude-group benchmark,intl-data diff --git a/phpunit b/phpunit new file mode 100755 index 0000000000..cc1bbc8e83 --- /dev/null +++ b/phpunit @@ -0,0 +1,126 @@ +#!/usr/bin/env php +open("$PHPUNIT_VERSION.zip"); + $zip->extractTo(getcwd()); + $zip->close(); + chdir("phpunit-$PHPUNIT_VERSION"); + passthru("composer remove --no-update symfony/yaml"); + passthru("composer install --prefer-source --no-progress --ansi"); + chdir($oldPwd); +} + +$cmd = array_map('escapeshellarg', $argv); +$exit = 0; + +if (isset($argv[1]) && 'symfony' === $argv[1]) { + // Find Symfony components in plain php for Windows portability + + $finder = new RecursiveDirectoryIterator('src/Symfony', FilesystemIterator::KEY_AS_FILENAME | FilesystemIterator::UNIX_PATHS); + $finder = new RecursiveIteratorIterator($finder); + $finder->setMaxDepth(3); + + array_shift($cmd); + $cmd[0] = "php $PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit --colors=always"; + $procs = array(); + + foreach ($finder as $file => $fileInfo) { + if ('phpunit.xml.dist' === $file) { + $component = dirname($fileInfo->getPathname()); + + // Run phpunit tests in parallel + + $c = escapeshellarg($component); + + if ($proc = proc_open(implode(' ', $cmd)." $c > $c/phpunit.stdout 2> $c/phpunit.stderr", array(), $pipes)) { + $procs[$component] = $proc; + } else { + $exit = 1; + echo "\033[41mKO\033[0m $component\n\n"; + } + } + } + + // Fixes for colors support on appveyor + // See http://help.appveyor.com/discussions/suggestions/197-support-ansi-color-codes + $colorFixes = array( + array("S\033[0m\033[0m\033[36m\033[1mS", "E\033[0m\033[0m\033[31m\033[1mE", "I\033[0m\033[0m\033[33m\033[1mI", "F\033[0m\033[0m\033[41m\033[37mF"), + array("SS", "EE", "II", "FF"), + ); + $colorFixes[0] = array_merge($colorFixes[0], $colorFixes[0]); + $colorFixes[1] = array_merge($colorFixes[1], $colorFixes[1]); + + foreach ($procs as $component => $proc) { + $procStatus = proc_close($proc); + + foreach (array('out', 'err') as $file) { + $file = "$component/phpunit.std$file"; + + if ('\\' === DIRECTORY_SEPARATOR) { + $h = fopen($file, 'rb'); + while (false !== $line = fgets($h)) { + echo str_replace($colorFixes[0], $colorFixes[1], preg_replace( + '/(\033\[[0-9]++);([0-9]++m)(?:(.)(\033\[0m))?/', + "$1m\033[$2$3$4$4", + $line + )); + } + fclose($h); + } else { + readfile($file); + } + unlink($file); + } + + if ($procStatus) { + $exit = 1; + echo "\033[41mKO\033[0m $component\n\n"; + } else { + echo "\033[32mOK\033[0m $component\n\n"; + } + } + +} elseif (!isset($argv[1]) || 'install' !== $argv[1]) { + // Run regular phpunit in a subprocess + + $cmd[0] = "php $PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit --colors=always"; + + $errFile = tempnam(sys_get_temp_dir(), 'phpunit.stderr.'); + if ($proc = proc_open(implode(' ', $cmd).' 2> '.escapeshellarg($errFile), array(1 => array('pipe', 'w')), $pipes)) { + stream_copy_to_stream($pipes[1], STDOUT); + fclose($pipes[1]); + $exit = proc_close($proc); + + readfile($errFile); + unlink($errFile); + } + + if (!file_exists($component = array_pop($argv))) { + $component = basename(getcwd()); + } + + if ($exit) { + echo "\033[41mKO\033[0m $component\n\n"; + } else { + echo "\033[32mOK\033[0m $component\n\n"; + } +} + +exit($exit); diff --git a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php index e4955db0d0..b7c3605d95 100644 --- a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php @@ -32,7 +32,7 @@ class CodeExtension extends \Twig_Extension public function __construct($fileLinkFormat, $rootDir, $charset) { $this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); - $this->rootDir = str_replace('\\', '/', dirname($rootDir)).'/'; + $this->rootDir = str_replace('/', DIRECTORY_SEPARATOR, dirname($rootDir)).DIRECTORY_SEPARATOR; $this->charset = $charset; } @@ -163,11 +163,11 @@ class CodeExtension extends \Twig_Extension $file = trim($file); if (null === $text) { - $text = str_replace('\\', '/', $file); + $text = str_replace('/', DIRECTORY_SEPARATOR, $file); if (0 === strpos($text, $this->rootDir)) { $text = substr($text, strlen($this->rootDir)); - $text = explode('/', $text, 2); - $text = sprintf('%s%s', $this->rootDir, $text[0], isset($text[1]) ? '/'.$text[1] : ''); + $text = explode(DIRECTORY_SEPARATOR, $text, 2); + $text = sprintf('%s%s', $this->rootDir, $text[0], isset($text[1]) ? DIRECTORY_SEPARATOR.$text[1] : ''); } } diff --git a/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php b/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php index a86f74b548..877e4b98eb 100644 --- a/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php @@ -28,7 +28,7 @@ class LintCommandTest extends \PHPUnit_Framework_TestCase $tester = $this->createCommandTester(); $filename = $this->createFile('{{ foo }}'); - $ret = $tester->execute(array('filename' => array($filename)), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE)); + $ret = $tester->execute(array('filename' => array($filename)), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false)); $this->assertEquals(0, $ret, 'Returns 0 in case of success'); $this->assertRegExp('/^OK in /', $tester->getDisplay()); @@ -39,7 +39,7 @@ class LintCommandTest extends \PHPUnit_Framework_TestCase $tester = $this->createCommandTester(); $filename = $this->createFile('{{ foo'); - $ret = $tester->execute(array('filename' => array($filename))); + $ret = $tester->execute(array('filename' => array($filename)), array('decorated' => false)); $this->assertEquals(1, $ret, 'Returns 1 in case of error'); $this->assertRegExp('/^KO in /', $tester->getDisplay()); @@ -54,7 +54,7 @@ class LintCommandTest extends \PHPUnit_Framework_TestCase $filename = $this->createFile(''); unlink($filename); - $ret = $tester->execute(array('filename' => array($filename))); + $ret = $tester->execute(array('filename' => array($filename)), array('decorated' => false)); } public function testLintFileCompileTimeException() @@ -62,7 +62,7 @@ class LintCommandTest extends \PHPUnit_Framework_TestCase $tester = $this->createCommandTester(); $filename = $this->createFile("{{ 2|number_format(2, decimal_point='.', ',') }}"); - $ret = $tester->execute(array('filename' => array($filename))); + $ret = $tester->execute(array('filename' => array($filename)), array('decorated' => false)); $this->assertEquals(1, $ret, 'Returns 1 in case of error'); $this->assertRegExp('/^KO in /', $tester->getDisplay()); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index bad9f51c32..023276e476 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -424,7 +424,7 @@ class Configuration implements ConfigurationInterface ->addDefaultChildrenIfNoneSet() ->prototype('scalar')->defaultValue('FrameworkBundle:Form')->end() ->validate() - ->ifNotInArray(array('FrameworkBundle:Form')) + ->ifTrue(function ($v) {return !in_array('FrameworkBundle:Form', $v); }) ->then(function ($v) { return array_merge(array('FrameworkBundle:Form'), $v); }) diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateFilenameParser.php b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateFilenameParser.php index a4a5e92cf3..df3ab19c4d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateFilenameParser.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateFilenameParser.php @@ -31,7 +31,7 @@ class TemplateFilenameParser implements TemplateNameParserInterface return $name; } - $parts = explode('/', strtr($name, '\\', '/')); + $parts = explode('/', str_replace('\\', '/', $name)); $elements = explode('.', array_pop($parts)); if (3 > count($elements)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php index 5730807fac..e4a7053d25 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php @@ -49,7 +49,7 @@ class TemplateNameParser extends BaseTemplateNameParser } // normalize name - $name = str_replace(':/', ':', preg_replace('#/{2,}#', '/', strtr($name, '\\', '/'))); + $name = str_replace(':/', ':', preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name))); if (false !== strpos($name, '..')) { throw new \RuntimeException(sprintf('Template name "%s" contains invalid characters.', $name)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 621ea4bdee..04b6c95b46 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -27,6 +27,19 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase ); } + public function testDoNoDuplicateDefaultFormResources() + { + $input = array('templating' => array( + 'form' => array('resources' => array('FrameworkBundle:Form')), + 'engines' => array('php'), + )); + + $processor = new Processor(); + $config = $processor->processConfiguration(new Configuration(true), array($input)); + + $this->assertEquals(array('FrameworkBundle:Form'), $config['templating']['form']['resources']); + } + /** * @dataProvider getTestValidTrustedProxiesData */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 7d3445ec7a..6e220740a5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -276,7 +276,7 @@ abstract class FrameworkExtensionTest extends TestCase $container = $this->createContainerFromFile('full'); $ref = new \ReflectionClass('Symfony\Component\Form\Form'); - $xmlMappings = array(realpath(dirname($ref->getFileName()).'/Resources/config/validation.xml')); + $xmlMappings = array(dirname($ref->getFileName()).'/Resources/config/validation.xml'); $calls = $container->getDefinition('validator.builder')->getMethodCalls(); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index 8f8e6ba7e0..86a69fdb76 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -33,8 +33,8 @@ class UserPasswordEncoderCommandTest extends WebTestCase 'password' => 'password', 'user-class' => 'Symfony\Component\Security\Core\User\User', '--empty-salt' => true, - )); - $expected = file_get_contents(__DIR__.'/app/PasswordEncode/emptysalt.txt'); + ), array('decorated' => false)); + $expected = str_replace("\n", PHP_EOL, file_get_contents(__DIR__.'/app/PasswordEncode/emptysalt.txt')); $this->assertEquals($expected, $this->passwordEncoderCommandTester->getDisplay()); } diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php index 9056ea299e..52c70f3318 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php @@ -81,7 +81,7 @@ class Configuration implements ConfigurationInterface ->prototype('scalar')->defaultValue('form_div_layout.html.twig')->end() ->example(array('MyBundle::form.html.twig')) ->validate() - ->ifNotInArray(array('form_div_layout.html.twig')) + ->ifTrue(function ($v) {return !in_array('form_div_layout.html.twig', $v); }) ->then(function ($v) { return array_merge(array('form_div_layout.html.twig'), $v); }) diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php new file mode 100644 index 0000000000..4dfb54eb76 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection; + +use Symfony\Bundle\TwigBundle\DependencyInjection\Configuration; +use Symfony\Component\Config\Definition\Processor; + +class ConfigurationTest extends \PHPUnit_Framework_TestCase +{ + public function testDoNoDuplicateDefaultFormResources() + { + $input = array( + 'form_themes' => array('form_div_layout.html.twig'), + ); + + $processor = new Processor(); + $config = $processor->processConfiguration(new Configuration(), array($input)); + + $this->assertEquals(array('form_div_layout.html.twig'), $config['form_themes']); + } +} diff --git a/src/Symfony/Component/ClassLoader/Tests/ClassMapGeneratorTest.php b/src/Symfony/Component/ClassLoader/Tests/ClassMapGeneratorTest.php index e6756f1898..7bdf5aa0dc 100644 --- a/src/Symfony/Component/ClassLoader/Tests/ClassMapGeneratorTest.php +++ b/src/Symfony/Component/ClassLoader/Tests/ClassMapGeneratorTest.php @@ -140,10 +140,10 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase protected function assertEqualsNormalized($expected, $actual, $message = null) { foreach ($expected as $ns => $path) { - $expected[$ns] = strtr($path, '\\', '/'); + $expected[$ns] = str_replace('\\', '/', $path); } foreach ($actual as $ns => $path) { - $actual[$ns] = strtr($path, '\\', '/'); + $actual[$ns] = str_replace('\\', '/', $path); } $this->assertEquals($expected, $actual, $message); } diff --git a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php index 0c891ca20a..c3b2fcdea3 100644 --- a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php +++ b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php @@ -257,7 +257,7 @@ class XmlReferenceDumper $indent = strlen($text) + $indent; $format = '%'.$indent.'s'; - $this->reference .= sprintf($format, $text)."\n"; + $this->reference .= sprintf($format, $text).PHP_EOL; } /** diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php index ab6bdaa79e..699751da7a 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php @@ -34,7 +34,7 @@ class XmlReferenceDumperTest extends \PHPUnit_Framework_TestCase private function getConfigurationAsString() { - return << @@ -75,6 +75,7 @@ class XmlReferenceDumperTest extends \PHPUnit_Framework_TestCase -EOL; +EOL + ); } } diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index dfee2321d5..45242cf1cf 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -553,6 +553,10 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function testRenderExceptionWithDoubleWidthCharacters() { + if (!function_exists('mb_strwidth')) { + $this->markTestSkipped('The "mb_strwidth" function is not available'); + } + $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); $application->setAutoExit(false); $application->expects($this->any()) diff --git a/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php index 9f83885a50..a51fb4359d 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php @@ -75,7 +75,7 @@ EOT; EOT; $syntaxErrorOutputDebug = <<42\';"', StreamOutput::VERBOSITY_DEBUG, null), array('', 'php -r "syntax error"', StreamOutput::VERBOSITY_VERBOSE, null), array($syntaxErrorOutputVerbose, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, null), - array($syntaxErrorOutputDebug, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, null), + array($syntaxErrorOutputDebug, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, null), array($errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERBOSE, $errorMessage), array($syntaxErrorOutputVerbose.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_VERY_VERBOSE, $errorMessage), - array($syntaxErrorOutputDebug.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(50000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, $errorMessage), + array($syntaxErrorOutputDebug.$errorMessage.PHP_EOL, 'php -r "fwrite(STDERR, \'error message\');usleep(500000);fwrite(STDOUT, \'out message\');exit(252);"', StreamOutput::VERBOSITY_DEBUG, $errorMessage), array($successOutputProcessDebug, array('php', '-r', 'echo 42;'), StreamOutput::VERBOSITY_DEBUG, null), array($successOutputDebug, new Process('php -r "echo 42;"'), StreamOutput::VERBOSITY_DEBUG, null), ); diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 3fd87bd766..0ab6b98221 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -166,20 +166,43 @@ class Crawler extends \SplObjectStorage $dom = new \DOMDocument('1.0', $charset); $dom->validateOnParse = true; - if (function_exists('mb_convert_encoding')) { - $hasError = false; - set_error_handler(function () use (&$hasError) { - $hasError = true; - }); - $tmpContent = @mb_convert_encoding($content, 'HTML-ENTITIES', $charset); + set_error_handler(function () {throw new \Exception();}); - restore_error_handler(); + try { + // Convert charset to HTML-entities to work around bugs in DOMDocument::loadHTML() - if (!$hasError) { - $content = $tmpContent; + if (function_exists('mb_convert_encoding')) { + $content = mb_convert_encoding($content, 'HTML-ENTITIES', $charset); + } elseif (function_exists('iconv')) { + $content = preg_replace_callback( + '/[\x80-\xFF]+/', + function ($m) { + $m = unpack('C*', $m[0]); + $i = 1; + $entities = ''; + + while (isset($m[$i])) { + if (0xF0 <= $m[$i]) { + $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } elseif (0xE0 <= $m[$i]) { + $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } else { + $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; + } + + $entities .= '&#'.$c.';'; + } + + return $entities; + }, + iconv($charset, 'UTF-8', $content) + ); } + } catch (\Exception $e) { } + restore_error_handler(); + if ('' !== trim($content)) { @$dom->loadHTML($content); } diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php index 3c281eb479..9560d06999 100755 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -81,6 +81,7 @@ class CrawlerTest extends \PHPUnit_Framework_TestCase /** * @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent + * @requires extension mbstring */ public function testAddHtmlContentCharset() { @@ -115,6 +116,7 @@ class CrawlerTest extends \PHPUnit_Framework_TestCase /** * @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent + * @requires extension mbstring */ public function testAddHtmlContentCharsetGbk() { @@ -235,7 +237,7 @@ EOF $this->assertEquals('中文', $crawler->filterXPath('//span')->text(), '->addContent() guess wrong charset'); $crawler = new Crawler(); - $crawler->addContent(mb_convert_encoding('日本語', 'SJIS', 'UTF-8')); + $crawler->addContent(iconv('UTF-8', 'SJIS', '日本語')); $this->assertEquals('日本語', $crawler->filterXPath('//body')->text(), '->addContent() can recognize "Shift_JIS" in html5 meta charset tag'); } diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 4a77f939ad..1bb7db350b 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -309,11 +309,10 @@ class Filesystem $report = error_get_last(); if (is_array($report)) { if ('\\' === DIRECTORY_SEPARATOR && false !== strpos($report['message'], 'error code(1314)')) { - throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?'); + throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', 0, null, $targetDir); } - throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir); } - throw new IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir)); + throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir); } } @@ -329,8 +328,8 @@ class Filesystem { // Normalize separators on Windows if ('\\' === DIRECTORY_SEPARATOR) { - $endPath = strtr($endPath, '\\', '/'); - $startPath = strtr($startPath, '\\', '/'); + $endPath = str_replace('\\', '/', $endPath); + $startPath = str_replace('\\', '/', $startPath); } // Split the paths into arrays diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index ae8885f3d6..b0f4152ecb 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -11,24 +11,11 @@ namespace Symfony\Component\Filesystem\Tests; -use Symfony\Component\Filesystem\Filesystem; - /** * Test class for Filesystem. */ class FilesystemTest extends FilesystemTestCase { - /** - * @var \Symfony\Component\Filesystem\Filesystem - */ - private $filesystem = null; - - protected function setUp() - { - parent::setUp(); - $this->filesystem = new Filesystem(); - } - public function testCopyCreatesNewFile() { $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file'; @@ -681,7 +668,9 @@ class FilesystemTest extends FilesystemTestCase public function testSymlink() { - $this->markAsSkippedIfSymlinkIsMissing(); + if ('\\' === DIRECTORY_SEPARATOR) { + $this->markAsSkipped('Windows does not support creating "broken" symlinks'); + } $file = $this->workspace.DIRECTORY_SEPARATOR.'file'; $link = $this->workspace.DIRECTORY_SEPARATOR.'link'; @@ -1011,6 +1000,8 @@ class FilesystemTest extends FilesystemTestCase public function testCopyShouldKeepExecutionPermission() { + $this->markAsSkippedIfChmodIsMissing(); + $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file'; $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file'; diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php index 74802fc314..0ef9c8dddd 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php @@ -11,29 +11,33 @@ namespace Symfony\Component\Filesystem\Tests; +use Symfony\Component\Filesystem\Filesystem; + class FilesystemTestCase extends \PHPUnit_Framework_TestCase { private $umask; + /** + * @var \Symfony\Component\Filesystem\Filesystem + */ + protected $filesystem = null; + /** * @var string */ protected $workspace = null; - protected static $symlinkOnWindows = null; + private static $symlinkOnWindows = null; public static function setUpBeforeClass() { - if ('\\' === DIRECTORY_SEPARATOR) { - static::$symlinkOnWindows = true; - $originDir = tempnam(sys_get_temp_dir(), 'sl'); - $targetDir = tempnam(sys_get_temp_dir(), 'sl'); - if (true !== @symlink($originDir, $targetDir)) { - $report = error_get_last(); - if (is_array($report) && false !== strpos($report['message'], 'error code(1314)')) { - static::$symlinkOnWindows = false; - } + if ('\\' === DIRECTORY_SEPARATOR && null === self::$symlinkOnWindows) { + $target = tempnam(sys_get_temp_dir(), 'sl'); + $link = sys_get_temp_dir().'/sl'.microtime(true).mt_rand(); + if (self::$symlinkOnWindows = @symlink($target, $link)) { + unlink($link); } + unlink($target); } } @@ -43,31 +47,15 @@ class FilesystemTestCase extends \PHPUnit_Framework_TestCase $this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().mt_rand(0, 1000); mkdir($this->workspace, 0777, true); $this->workspace = realpath($this->workspace); + $this->filesystem = new Filesystem(); } protected function tearDown() { - $this->clean($this->workspace); + $this->filesystem->remove($this->workspace); umask($this->umask); } - /** - * @param string $file - */ - protected function clean($file) - { - if (is_dir($file) && !is_link($file)) { - $dir = new \FilesystemIterator($file); - foreach ($dir as $childFile) { - $this->clean($childFile); - } - - rmdir($file); - } else { - unlink($file); - } - } - /** * @param int $expectedFilePerms expected file permissions as three digits (i.e. 755) * @param string $filePath @@ -110,7 +98,7 @@ class FilesystemTestCase extends \PHPUnit_Framework_TestCase $this->markTestSkipped('symlink is not supported'); } - if ('\\' === DIRECTORY_SEPARATOR && false === static::$symlinkOnWindows) { + if ('\\' === DIRECTORY_SEPARATOR && false === self::$symlinkOnWindows) { $this->markTestSkipped('symlink requires "Create symbolic links" privilege on windows'); } } diff --git a/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php b/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php index c2058ffc58..f229ffd83e 100644 --- a/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php +++ b/src/Symfony/Component/Filesystem/Tests/LockHandlerTest.php @@ -12,6 +12,9 @@ class LockHandlerTest extends \PHPUnit_Framework_TestCase */ public function testConstructWhenRepositoryDoesNotExist() { + if (!getenv('USER') || 'root' === getenv('USER')) { + $this->markTestSkipped('This test will fail if run under superuser'); + } new LockHandler('lock', '/a/b/c/d/e'); } @@ -21,6 +24,9 @@ class LockHandlerTest extends \PHPUnit_Framework_TestCase */ public function testConstructWhenRepositoryIsNotWriteable() { + if (!getenv('USER') || 'root' === getenv('USER')) { + $this->markTestSkipped('This test will fail if run under superuser'); + } new LockHandler('lock', '/'); } diff --git a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php index 1ddde851b9..f15d953e4d 100644 --- a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -43,7 +43,7 @@ class ExcludeDirectoryFilterIterator extends FilterIterator public function accept() { $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath(); - $path = strtr($path, '\\', '/'); + $path = str_replace('\\', '/', $path); foreach ($this->patterns as $pattern) { if (preg_match($pattern, $path)) { return false; diff --git a/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php b/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php index 2bb8ebd223..4971692c69 100644 --- a/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/PathFilterIterator.php @@ -29,7 +29,7 @@ class PathFilterIterator extends MultiplePcreFilterIterator $filename = $this->current()->getRelativePathname(); if ('\\' === DIRECTORY_SEPARATOR) { - $filename = strtr($filename, '\\', '/'); + $filename = str_replace('\\', '/', $filename); } // should at least not match one rule to exclude diff --git a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php index 412054b379..436d8af560 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/RecursiveDirectoryIteratorTest.php @@ -60,9 +60,6 @@ class RecursiveDirectoryIteratorTest extends IteratorTestCase $i->seek(1); $actual[] = $i->getPathname(); - $i->seek(2); - $actual[] = $i->getPathname(); - $this->assertEquals($contains, $actual); } @@ -73,7 +70,6 @@ class RecursiveDirectoryIteratorTest extends IteratorTestCase // ftp $contains = array( 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'README', - 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'index.html', 'ftp://ftp.mozilla.org'.DIRECTORY_SEPARATOR.'pub', ); $data[] = array('ftp://ftp.mozilla.org/', false, $contains); diff --git a/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php index effaf76868..ed24f3ea0d 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php @@ -33,7 +33,11 @@ class SortableIteratorTest extends RealIteratorTestCase if (!is_callable($mode)) { switch ($mode) { case SortableIterator::SORT_BY_ACCESSED_TIME : - file_get_contents(self::toAbsolute('.git')); + if ('\\' === DIRECTORY_SEPARATOR) { + touch(self::toAbsolute('.git')); + } else { + file_get_contents(self::toAbsolute('.git')); + } sleep(1); file_get_contents(self::toAbsolute('.bar')); break; @@ -56,7 +60,11 @@ class SortableIteratorTest extends RealIteratorTestCase if ($mode === SortableIterator::SORT_BY_ACCESSED_TIME || $mode === SortableIterator::SORT_BY_CHANGED_TIME - || $mode === SortableIterator::SORT_BY_MODIFIED_TIME) { + || $mode === SortableIterator::SORT_BY_MODIFIED_TIME + ) { + if ('\\' === DIRECTORY_SEPARATOR && SortableIterator::SORT_BY_MODIFIED_TIME !== $mode) { + $this->markTestSkipped('Sorting by atime or ctime is not supported on Windows'); + } $this->assertOrderedIteratorForGroups($expected, $iterator); } else { $this->assertOrderedIterator($expected, $iterator); diff --git a/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php b/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php index f967cdaa54..e9145127ea 100644 --- a/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php +++ b/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php @@ -86,7 +86,7 @@ class CommandTest extends \PHPUnit_Framework_TestCase $cmd = Command::create()->add('--force'); $cmd->arg('--run'); - $this->assertSame('--force \'--run\'', $cmd->join()); + $this->assertSame('--force '.escapeshellarg('--run'), $cmd->join()); } public function testCmd() diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index 9996966f19..156735b817 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -155,7 +155,7 @@ class ArrayChoiceList implements ChoiceListInterface $givenValues = array(); foreach ($choices as $i => $givenChoice) { - $givenValues[$i] = call_user_func($this->valueCallback, $givenChoice); + $givenValues[$i] = (string) call_user_func($this->valueCallback, $givenChoice); } return array_intersect($givenValues, array_keys($this->choices)); diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php index 8796acfc4d..0692781f40 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/CachingFactoryDecorator.php @@ -62,7 +62,7 @@ class CachingFactoryDecorator implements ChoiceListFactoryInterface }); } - return hash('sha256', $namespace.':'.json_encode($value)); + return hash('sha256', $namespace.':'.serialize($value)); } /** diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php index ef41d497be..87a364a5f4 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php @@ -141,7 +141,13 @@ class PropertyAccessDecorator implements ChoiceListFactoryInterface if ($value instanceof PropertyPath) { $accessor = $this->propertyAccessor; $value = function ($choice) use ($accessor, $value) { - return $accessor->getValue($choice, $value); + // The callable may be invoked with a non-object/array value + // when such values are passed to + // ChoiceListInterface::getValuesForChoices(). Handle this case + // so that the call to getValue() doesn't break. + if (is_object($choice) || is_array($choice)) { + return $accessor->getValue($choice, $value); + } }; } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php index 59500c8915..2a620a1220 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -275,7 +275,7 @@ class DateType extends AbstractType $pattern = $formatter->getPattern(); $timezone = $formatter->getTimezoneId(); - if ($setTimeZone = method_exists($formatter, 'setTimeZone')) { + if ($setTimeZone = PHP_VERSION_ID >= 50500 || method_exists($formatter, 'setTimeZone')) { $formatter->setTimeZone('UTC'); } else { $formatter->setTimeZoneId('UTC'); diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php index 8697a9cac5..311db477b1 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php @@ -93,6 +93,36 @@ class PropertyAccessDecoratorTest extends \PHPUnit_Framework_TestCase $this->assertSame('value', $this->factory->createListFromLoader($loader, 'property')); } + // https://github.com/symfony/symfony/issues/5494 + public function testCreateFromChoicesAssumeNullIfValuePropertyPathUnreadable() + { + $choices = array(null); + + $this->decoratedFactory->expects($this->once()) + ->method('createListFromChoices') + ->with($choices, $this->isInstanceOf('\Closure')) + ->will($this->returnCallback(function ($choices, $callback) { + return array_map($callback, $choices); + })); + + $this->assertSame(array(null), $this->factory->createListFromChoices($choices, 'property')); + } + + // https://github.com/symfony/symfony/issues/5494 + public function testCreateFromChoiceLoaderAssumeNullIfValuePropertyPathUnreadable() + { + $loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface'); + + $this->decoratedFactory->expects($this->once()) + ->method('createListFromLoader') + ->with($loader, $this->isInstanceOf('\Closure')) + ->will($this->returnCallback(function ($loader, $callback) { + return $callback(null); + })); + + $this->assertNull($this->factory->createListFromLoader($loader, 'property')); + } + public function testCreateFromLoaderPropertyPathInstance() { $loader = $this->getMock('Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface'); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index 21a74ab486..8f23af510a 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -92,11 +92,6 @@ class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase public function transformWithRoundingProvider() { - // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this); - - \Locale::setDefault('de_AT'); - return array( // towards positive infinity (1.6 -> 2, -1.6 -> -1) array(0, 1234.5, '1235', NumberToLocalizedStringTransformer::ROUND_CEILING), @@ -189,6 +184,11 @@ class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase */ public function testTransformWithRounding($scale, $input, $output, $roundingMode) { + // Since we test against "de_AT", we need the full implementation + IntlTestHelper::requireFullIntl($this); + + \Locale::setDefault('de_AT'); + $transformer = new NumberToLocalizedStringTransformer($scale, null, $roundingMode); $this->assertEquals($output, $transformer->transform($input)); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 67241a1be9..cf15b0a3b7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -1337,6 +1337,42 @@ class ChoiceTypeTest extends \Symfony\Component\Form\Test\TypeTestCase $this->assertNull($form[4]->getViewData()); } + public function testSingleSelectedObjectChoices() + { + $form = $this->factory->create('choice', $this->objectChoices[3], array( + 'multiple' => false, + 'expanded' => false, + 'choices' => $this->objectChoices, + 'choices_as_values' => true, + 'choice_label' => 'name', + 'choice_value' => 'id', + )); + + $view = $form->createView(); + $selectedChecker = $view->vars['is_selected']; + + $this->assertTrue($selectedChecker($view->vars['choices'][3]->value, $view->vars['value'])); + $this->assertFalse($selectedChecker($view->vars['choices'][1]->value, $view->vars['value'])); + } + + public function testMultipleSelectedObjectChoices() + { + $form = $this->factory->create('choice', array($this->objectChoices[3]), array( + 'multiple' => true, + 'expanded' => false, + 'choices' => $this->objectChoices, + 'choices_as_values' => true, + 'choice_label' => 'name', + 'choice_value' => 'id', + )); + + $view = $form->createView(); + $selectedChecker = $view->vars['is_selected']; + + $this->assertTrue($selectedChecker($view->vars['choices'][3]->value, $view->vars['value'])); + $this->assertFalse($selectedChecker($view->vars['choices'][1]->value, $view->vars['value'])); + } + /* * We need this functionality to create choice fields for Boolean types, * e.g. false => 'No', true => 'Yes' diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 36ae61ba41..510a97175e 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1852,9 +1852,9 @@ class Request return $prefix; } - if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/').'/')) { + if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(dirname($baseUrl), '/'.DIRECTORY_SEPARATOR).'/')) { // directory portion of $baseUrl matches - return rtrim($prefix, '/'); + return rtrim($prefix, '/'.DIRECTORY_SEPARATOR); } $truncatedRequestUri = $requestUri; @@ -1875,7 +1875,7 @@ class Request $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl)); } - return rtrim($baseUrl, '/'); + return rtrim($baseUrl, '/'.DIRECTORY_SEPARATOR); } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index 47e4d4fed8..550014dc73 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -54,7 +54,7 @@ class BinaryFileResponseTest extends ResponseTestCase */ public function testRequests($requestRange, $offset, $length, $responseRange) { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif')->setAutoEtag(); + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag(); // do a request to get the ETag $request = Request::create('/'); @@ -96,7 +96,7 @@ class BinaryFileResponseTest extends ResponseTestCase */ public function testFullFileRequests($requestRange) { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif')->setAutoEtag(); + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag(); // prepare a request for a range of the testing file $request = Request::create('/'); @@ -131,7 +131,7 @@ class BinaryFileResponseTest extends ResponseTestCase */ public function testInvalidRequests($requestRange) { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif')->setAutoEtag(); + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream'))->setAutoEtag(); // prepare a request for a range of the testing file $request = Request::create('/'); @@ -159,7 +159,7 @@ class BinaryFileResponseTest extends ResponseTestCase $request->headers->set('X-Sendfile-Type', 'X-Sendfile'); BinaryFileResponse::trustXSendfileTypeHeader(); - $response = BinaryFileResponse::create(__DIR__.'/../README.md'); + $response = BinaryFileResponse::create(__DIR__.'/../README.md', 200, array('Content-Type' => 'application/octet-stream')); $response->prepare($request); $this->expectOutputString(''); @@ -180,7 +180,7 @@ class BinaryFileResponseTest extends ResponseTestCase $file = new FakeFile($realpath, __DIR__.'/File/Fixtures/test'); BinaryFileResponse::trustXSendfileTypeHeader(); - $response = new BinaryFileResponse($file); + $response = new BinaryFileResponse($file, 200, array('Content-Type' => 'application/octet-stream')); $reflection = new \ReflectionObject($response); $property = $reflection->getProperty('file'); $property->setAccessible(true); @@ -199,7 +199,7 @@ class BinaryFileResponseTest extends ResponseTestCase $realPath = realpath($path); $this->assertFileExists($realPath); - $response = new BinaryFileResponse($realPath); + $response = new BinaryFileResponse($realPath, 200, array('Content-Type' => 'application/octet-stream')); $response->deleteFileAfterSend(true); $response->prepare($request); @@ -211,7 +211,7 @@ class BinaryFileResponseTest extends ResponseTestCase public function testAcceptRangeOnUnsafeMethods() { $request = Request::create('/', 'POST'); - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif'); + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream')); $response->prepare($request); $this->assertEquals('none', $response->headers->get('Accept-Ranges')); @@ -220,7 +220,7 @@ class BinaryFileResponseTest extends ResponseTestCase public function testAcceptRangeNotOverriden() { $request = Request::create('/', 'POST'); - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif'); + $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, array('Content-Type' => 'application/octet-stream')); $response->headers->set('Accept-Ranges', 'foo'); $response->prepare($request); @@ -237,7 +237,7 @@ class BinaryFileResponseTest extends ResponseTestCase protected function provideResponse() { - return new BinaryFileResponse(__DIR__.'/../README.md'); + return new BinaryFileResponse(__DIR__.'/../README.md', 200, array('Content-Type' => 'application/octet-stream')); } public static function tearDownAfterClass() diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php index 6777849c8a..d216eab516 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php @@ -45,6 +45,9 @@ class FileTest extends \PHPUnit_Framework_TestCase $this->assertEquals('gif', $file->guessExtension()); } + /** + * @requires extension fileinfo + */ public function testGuessExtensionWithReset() { $file = new File(__DIR__.'/Fixtures/other-file.example'); diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php index b2a573e27a..1d5648eada 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php @@ -14,17 +14,16 @@ namespace Symfony\Component\HttpFoundation\Tests\File\MimeType; use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser; +/** + * @requires extension fileinfo + */ class MimeTypeTest extends \PHPUnit_Framework_TestCase { protected $path; public function testGuessImageWithoutExtension() { - if (extension_loaded('fileinfo')) { - $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); - } else { - $this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); - } + $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); } public function testGuessImageWithDirectory() @@ -38,29 +37,17 @@ class MimeTypeTest extends \PHPUnit_Framework_TestCase { $guesser = MimeTypeGuesser::getInstance(); $guesser->register(new FileBinaryMimeTypeGuesser()); - if (extension_loaded('fileinfo')) { - $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); - } else { - $this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); - } + $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); } public function testGuessImageWithKnownExtension() { - if (extension_loaded('fileinfo')) { - $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.gif')); - } else { - $this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.gif')); - } + $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.gif')); } public function testGuessFileWithUnknownExtension() { - if (extension_loaded('fileinfo')) { - $this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension')); - } else { - $this->assertNull(MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension')); - } + $this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension')); } public function testGuessWithIncorrectPath() @@ -75,7 +62,7 @@ class MimeTypeTest extends \PHPUnit_Framework_TestCase $this->markTestSkipped('Can not verify chmod operations on Windows'); } - if ('root' === get_current_user()) { + if (!getenv('USER') || 'root' === getenv('USER')) { $this->markTestSkipped('This test will fail if run under superuser'); } @@ -83,7 +70,7 @@ class MimeTypeTest extends \PHPUnit_Framework_TestCase touch($path); @chmod($path, 0333); - if (get_current_user() != 'root' && substr(sprintf('%o', fileperms($path)), -4) == '0333') { + if (substr(sprintf('%o', fileperms($path)), -4) == '0333') { $this->setExpectedException('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException'); MimeTypeGuesser::getInstance()->guess($path); } else { diff --git a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php index 1b5b90091c..af398afc91 100644 --- a/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php +++ b/src/Symfony/Component/Intl/DateFormatter/IntlDateFormatter.php @@ -209,7 +209,7 @@ class IntlDateFormatter $argumentError = null; if (!is_int($timestamp) && !$timestamp instanceof \DateTime) { $argumentError = 'datefmt_format: takes either an array or an integer timestamp value or a DateTime object'; - if (PHP_VERSION_ID >= 50500 && !is_int($timestamp)) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $argumentError = sprintf('datefmt_format: string \'%s\' is not numeric, which would be required for it to be a valid date', $timestamp); } } @@ -371,7 +371,7 @@ class IntlDateFormatter } // In PHP 5.5 default timezone depends on `date_default_timezone_get()` method - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { return date_default_timezone_get(); } } @@ -536,7 +536,7 @@ class IntlDateFormatter { if (null === $timeZoneId) { // In PHP 5.5 if $timeZoneId is null it fallbacks to `date_default_timezone_get()` method - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $timeZoneId = date_default_timezone_get(); } else { // TODO: changes were made to ext/intl in PHP 5.4.4 release that need to be investigated since it will @@ -563,8 +563,16 @@ class IntlDateFormatter try { $this->dateTimeZone = new \DateTimeZone($timeZoneId); + if ('GMT' !== $timeZoneId && $this->dateTimeZone->getName() !== $timeZoneId) { + $timeZoneId = $timeZone = $this->getTimeZoneId(); + } } catch (\Exception $e) { - $this->dateTimeZone = new \DateTimeZone('UTC'); + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { + $timeZoneId = $timeZone = $this->getTimeZoneId(); + } else { + $timeZoneId = 'UTC'; + } + $this->dateTimeZone = new \DateTimeZone($timeZoneId); } $this->timeZoneId = $timeZone; @@ -630,7 +638,7 @@ class IntlDateFormatter if (self::NONE !== $this->timetype) { $patternParts[] = $this->defaultTimeFormats[$this->timetype]; } - $pattern = implode(' ', $patternParts); + $pattern = implode(', ', $patternParts); return $pattern; } diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index fe8a307428..eaed44781c 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -538,22 +538,30 @@ class NumberFormatter return false; } - preg_match('/^([^0-9\-\.]{0,})(.*)/', $value, $matches); + $groupSep = $this->getAttribute(self::GROUPING_USED) ? ',' : ''; // Any string before the numeric value causes error in the parsing - if (isset($matches[1]) && !empty($matches[1])) { + if (preg_match("/^-?(?:\.\d++|([\d{$groupSep}]++)(?:\.\d++)?)/", $value, $matches)) { + $value = $matches[0]; + $position = strlen($value); + if ($error = $groupSep && isset($matches[1]) && !preg_match('/^\d{1,3}+(?:(?:,\d{3})++|\d*+)$/', $matches[1])) { + $position -= strlen(preg_replace('/^\d{1,3}+(?:(?:,\d++)++|\d*+)/', '', $matches[1])); + } + } else { + $error = 1; + $position = 0; + } + + if ($error) { IntlGlobals::setError(IntlGlobals::U_PARSE_ERROR, 'Number parsing failed'); $this->errorCode = IntlGlobals::getErrorCode(); $this->errorMessage = IntlGlobals::getErrorMessage(); - $position = 0; return false; } - preg_match('/^[0-9\-\.\,]*/', $value, $matches); - $value = preg_replace('/[^0-9\.\-]/', '', $matches[0]); + $value = str_replace(',', '', $value); $value = $this->convertValueDataType($value, $type); - $position = strlen($matches[0]); // behave like the intl extension $this->resetError(); diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php index 6cae5aedd0..a3000957be 100644 --- a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php @@ -38,11 +38,16 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase $formatter = $this->getDateFormatter('en', IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT); // In PHP 5.5 default timezone depends on `date_default_timezone_get()` method - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $this->assertEquals(date_default_timezone_get(), $formatter->getTimeZoneId()); } else { $this->assertNull($formatter->getTimeZoneId()); } + + $this->assertEquals( + $this->getDateTime(0, $formatter->getTimeZoneId())->format('M j, Y, g:i A'), + $formatter->format(0) + ); } /** @@ -267,7 +272,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase public function formatErrorProvider() { // With PHP 5.5 IntlDateFormatter accepts empty values ('0') - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { return array( array('y-M-d', 'foobar', 'datefmt_format: string \'foobar\' is not numeric, which would be required for it to be a valid date: U_ILLEGAL_ARGUMENT_ERROR'), ); @@ -320,7 +325,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase ); // As of PHP 5.5, intl ext no longer fallbacks invalid time zones to UTC - if (PHP_VERSION_ID < 50500) { + if (PHP_VERSION_ID < 50500 && !(extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { // When time zone not exists, uses UTC by default $data[] = array(0, 'Foo/Bar', '1970-01-01 00:00:00'); $data[] = array(0, 'UTC+04:30', '1970-01-01 00:00:00'); @@ -334,7 +339,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase { $formatter = $this->getDefaultDateFormatter('zzzz'); - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $formatter->setTimeZone('GMT+03:00'); } else { $formatter->setTimeZoneId('GMT+03:00'); @@ -347,7 +352,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase { $formatter = $this->getDefaultDateFormatter('zzzz'); - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $formatter->setTimeZone('GMT+00:30'); } else { $formatter->setTimeZoneId('GMT+00:30'); @@ -360,7 +365,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase { $formatter = $this->getDefaultDateFormatter('zzzz'); - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $formatter->setTimeZone('Pacific/Fiji'); } else { $formatter->setTimeZoneId('Pacific/Fiji'); @@ -397,7 +402,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase public function testFormatWithIntlTimeZone() { - if (PHP_VERSION_ID < 50500) { + if (PHP_VERSION_ID < 50500 && !(extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $this->markTestSkipped('Only in PHP 5.5+ IntlDateFormatter allows to use DateTimeZone objects.'); } @@ -412,7 +417,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase public function testFormatWithTimezoneFromEnvironmentVariable() { - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $this->markTestSkipped('IntlDateFormatter in PHP 5.5 no longer depends on TZ environment.'); } @@ -435,7 +440,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase public function testFormatWithTimezoneFromPhp() { - if (PHP_VERSION_ID < 50500) { + if (PHP_VERSION_ID < 50500 && !(extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $this->markTestSkipped('Only in PHP 5.5 IntlDateFormatter depends on default timezone (`date_default_timezone_get()`).'); } @@ -866,7 +871,7 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase { $formatter = $this->getDefaultDateFormatter(); - if (PHP_VERSION_ID >= 50500) { + if (PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone'))) { $formatter->setTimeZone($timeZoneId); } else { $formatter->setTimeZoneId($timeZoneId); @@ -877,15 +882,17 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase public function setTimeZoneIdProvider() { + $isPhp55 = PHP_VERSION_ID >= 50500 || (extension_loaded('intl') && method_exists('IntlDateFormatter', 'setTimeZone')); + return array( array('UTC', 'UTC'), array('GMT', 'GMT'), array('GMT-03:00', 'GMT-03:00'), array('Europe/Zurich', 'Europe/Zurich'), - array('GMT-0300', 'GMT-0300'), - array('Foo/Bar', 'Foo/Bar'), - array('GMT+00:AA', 'GMT+00:AA'), - array('GMT+00AA', 'GMT+00AA'), + array(null, $isPhp55 ? date_default_timezone_get() : null), + array('Foo/Bar', $isPhp55 ? 'UTC' : 'Foo/Bar'), + array('GMT+00:AA', $isPhp55 ? 'UTC' : 'GMT+00:AA'), + array('GMT+00AA', $isPhp55 ? 'UTC' : 'GMT+00AA'), ); } @@ -898,7 +905,9 @@ abstract class AbstractIntlDateFormatterTest extends \PHPUnit_Framework_TestCase { $dateTime = new \DateTime(); $dateTime->setTimestamp(null === $timestamp ? time() : $timestamp); - $dateTime->setTimezone(new \DateTimeZone($timeZone)); + if (null !== $timeZone) { + $dateTime->setTimezone(new \DateTimeZone($timeZone)); + } return $dateTime; } diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php index bf4cdae26a..dcf38473f2 100644 --- a/src/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/DateFormatter/Verification/IntlDateFormatterTest.php @@ -45,7 +45,11 @@ class IntlDateFormatterTest extends AbstractIntlDateFormatterTest protected function getDateFormatter($locale, $datetype, $timetype, $timezone = null, $calendar = IntlDateFormatter::GREGORIAN, $pattern = null) { - return new \IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern); + if (!$formatter = new \IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern)) { + throw new \InvalidArgumentException(intl_get_error_message()); + } + + return $formatter; } protected function getIntlErrorMessage() diff --git a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php index 9bde822486..c0eec6ebc1 100644 --- a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php @@ -602,10 +602,11 @@ abstract class AbstractNumberFormatterTest extends \PHPUnit_Framework_TestCase /** * @dataProvider parseProvider */ - public function testParse($value, $expected, $message, $expectedPosition) + public function testParse($value, $expected, $message, $expectedPosition, $groupingUsed = true) { $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); @@ -631,6 +632,11 @@ abstract class AbstractNumberFormatterTest extends \PHPUnit_Framework_TestCase return array( array('prefix1', false, '->parse() does not parse a number with a string prefix.', 0), array('1.4suffix', (float) 1.4, '->parse() parses a number with a string suffix.', 3), + array('-.4suffix', (float) -0.4, '->parse() parses a negative dot float with suffix.', 3), + array('-123,4', false, '->parse() does not parse when invalid grouping used.', 6), + array('-1234,567', false, '->parse() does not parse when invalid grouping used.', 5), + array('-123,,456', false, '->parse() does not parse when invalid grouping used.', 4), + array('-123,,456', -123.0, '->parse() parses when grouping is disabled.', 4, false), ); } diff --git a/src/Symfony/Component/Locale/Tests/LocaleTest.php b/src/Symfony/Component/Locale/Tests/LocaleTest.php index 033d68903c..7419d28369 100644 --- a/src/Symfony/Component/Locale/Tests/LocaleTest.php +++ b/src/Symfony/Component/Locale/Tests/LocaleTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Locale\Tests; use Symfony\Component\Locale\Locale; +use Symfony\Component\Intl\Util\IntlTestHelper; /** * Test case for the {@link Locale} class. @@ -35,6 +36,8 @@ class LocaleTest extends \PHPUnit_Framework_TestCase public function testGetDisplayCountriesForSwitzerland() { + IntlTestHelper::requireFullIntl($this); + $countries = Locale::getDisplayCountries('de_CH'); $this->assertEquals('Schweiz', $countries['CH']); } diff --git a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php index eb3f65dc93..93b5779ad2 100644 --- a/src/Symfony/Component/Process/Tests/AbstractProcessTest.php +++ b/src/Symfony/Component/Process/Tests/AbstractProcessTest.php @@ -172,6 +172,9 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase */ public function testSetStreamAsInput($code, $size) { + if ('\\' === DIRECTORY_SEPARATOR) { + $this->markTestIncomplete('This test fails with a timeout on Windows, can someone investigate please?'); + } $expected = str_repeat(str_repeat('*', 1024), $size).'!'; $expectedLength = (1024 * $size) + 1; @@ -179,7 +182,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase fwrite($stream, $expected); rewind($stream); - $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code))); + $p = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg($code)), null, null, null, 5); $p->setInput($stream); $p->run(); @@ -559,7 +562,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase $start = microtime(true); $process->start(); $end = microtime(true); - $this->assertLessThan(0.2, $end - $start); + $this->assertLessThan(0.4, $end - $start); $process->wait(); } @@ -637,8 +640,10 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase { $process = $this->getProcess(self::$phpBin.' -r "sleep(1);"'); $process->start(); + + $this->assertFalse($process->isSuccessful()); + while ($process->isRunning()) { - $this->assertFalse($process->isSuccessful()); usleep(300000); } @@ -844,6 +849,9 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase public function testIdleTimeoutNotExceededWhenOutputIsSent() { + if ('\\' === DIRECTORY_SEPARATOR) { + $this->markTestIncomplete('This test fails with a timeout on Windows, can someone investigate please?'); + } $process = $this->getProcess(sprintf('%s -r %s', self::$phpBin, escapeshellarg('$n = 30; while ($n--) {echo "foo\n"; usleep(100000); }'))); $process->setTimeout(2); $process->setIdleTimeout(1); diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index 1d12ab0dba..7538648b13 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -33,7 +33,7 @@ abstract class AbstractToken implements TokenInterface /** * Constructor. * - * @param RoleInterface[] $roles An array of roles + * @param RoleInterface[]|string[] $roles An array of roles * * @throws \InvalidArgumentException */ diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php index abcd2bffa3..1798203690 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Core\Authentication\Token; +use Symfony\Component\Security\Core\Role\RoleInterface; + /** * PreAuthenticatedToken implements a pre-authenticated token. * @@ -23,6 +25,11 @@ class PreAuthenticatedToken extends AbstractToken /** * Constructor. + * + * @param string|object $user The user + * @param mixed $credentials The user credentials + * @param string $providerKey The provider key + * @param RoleInterface[]|string[] $roles An array of roles */ public function __construct($user, $credentials, $providerKey, array $roles = array()) { diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index f2cbacb4f0..937fa097a7 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -48,14 +48,14 @@ class XliffFileLoader implements LoaderInterface foreach ($xml->xpath('//xliff:trans-unit') as $translation) { $attributes = $translation->attributes(); - if (!(isset($attributes['resname']) || isset($translation->source)) || !isset($translation->target)) { + if (!(isset($attributes['resname']) || isset($translation->source))) { continue; } $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; // If the xlf file has another encoding specified, try to convert it because // simple_xml will always return utf-8 encoded values - $target = $this->utf8ToCharset((string) $translation->target, $encoding); + $target = $this->utf8ToCharset((string) (isset($translation->target) ? $translation->target : $source), $encoding); $catalogue->set((string) $source, $target, $domain); diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index 18c3aaeb25..a67af1a340 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -25,6 +25,7 @@ class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals('en', $catalogue->getLocale()); $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources()); $this->assertSame(array(), libxml_get_errors()); + $this->assertContainsOnly('string', $catalogue->all('domain1')); } public function testLoadWithInternalErrorsEnabled() @@ -55,8 +56,7 @@ class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase $loader = new XliffFileLoader(); $catalogue = $loader->load(__DIR__.'/../fixtures/resources.xlf', 'en', 'domain1'); - $this->assertEquals(array('foo' => 'bar', 'key' => '', 'test' => 'with'), $catalogue->all('domain1')); - $this->assertFalse($catalogue->has('extra', 'domain1')); + $this->assertEquals(array('foo' => 'bar', 'extra' => 'extra', 'key' => '', 'test' => 'with'), $catalogue->all('domain1')); } public function testEncoding() @@ -145,7 +145,8 @@ class XliffFileLoaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(array('notes' => array(array('priority' => 1, 'content' => 'foo'))), $catalogue->getMetadata('foo', 'domain1')); // message without target - $this->assertNull($catalogue->getMetadata('extra', 'domain1')); + $this->assertEquals(array('notes' => array(array('content' => 'bar', 'from' => 'foo'))), $catalogue->getMetadata('extra', 'domain1')); + // message with empty target $this->assertEquals(array('notes' => array(array('content' => 'baz'), array('priority' => 2, 'from' => 'bar', 'content' => 'qux'))), $catalogue->getMetadata('key', 'domain1')); } } diff --git a/src/Symfony/Component/Validator/Constraints/LengthValidator.php b/src/Symfony/Component/Validator/Constraints/LengthValidator.php index 9597f3869a..7ef9f269d0 100644 --- a/src/Symfony/Component/Validator/Constraints/LengthValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LengthValidator.php @@ -45,23 +45,25 @@ class LengthValidator extends ConstraintValidator $charset = 'UTF-8'; } - if (function_exists('iconv_strlen')) { - $length = @iconv_strlen($stringValue, $constraint->charset); - $invalidCharset = false === $length; + if ('UTF-8' === $charset) { + if (!preg_match('//u', $stringValue)) { + $invalidCharset = true; + } elseif (function_exists('utf8_decode')) { + $length = strlen(utf8_decode($stringValue)); + } else { + preg_replace('/./u', '', $stringValue, -1, $length); + } } elseif (function_exists('mb_strlen')) { - if (mb_check_encoding($stringValue, $constraint->charset)) { + if (@mb_check_encoding($stringValue, $constraint->charset)) { $length = mb_strlen($stringValue, $constraint->charset); } else { $invalidCharset = true; } - } elseif ('UTF-8' !== $charset) { - $length = strlen($stringValue); - } elseif (!preg_match('//u', $stringValue)) { - $invalidCharset = true; - } elseif (function_exists('utf8_decode')) { - $length = strlen(utf8_decode($stringValue)); + } elseif (function_exists('iconv_strlen')) { + $length = @iconv_strlen($stringValue, $constraint->charset); + $invalidCharset = false === $length; } else { - preg_replace('/./u', '', $stringValue, -1, $length); + $length = strlen($stringValue); } if ($invalidCharset) { diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php index 18f9c1bc06..4605a06577 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php @@ -15,6 +15,9 @@ use Symfony\Component\Validator\Constraints\Image; use Symfony\Component\Validator\Constraints\ImageValidator; use Symfony\Component\Validator\Validation; +/** + * @requires extension fileinfo + */ class ImageValidatorTest extends AbstractConstraintValidatorTest { protected $context; diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php index 399465938c..48d5cffa40 100644 --- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php @@ -129,7 +129,7 @@ var refStyle = doc.createElement('style'), e.addEventListener(n, cb, false); }; -doc.documentElement.firstChild.appendChild(refStyle); +(doc.documentElement.firstElementChild || doc.documentElement.children[0]).appendChild(refStyle); if (!doc.addEventListener) { addEventListener = function (element, eventName, callback) {