Merge branch '2.7' into 2.8

* 2.7:
  [Validator] Test DNS Url constraints using checkdnsrr() mock
  Improved the PHPdoc of FileSystem::copy()
  [Validator] Test DNS Email constraints using checkdnsrr() mock
  [travis] Run real php subprocesses on hhvm for Process component tests
  bug #18161 [Translation] Add support for fuzzy tags in PoFileLoader
  [Form] Fix NumberToLocalizedStringTransformer::reverseTransform with big integers
  [Form] Fix INT64 cast to float in IntegerType.
  [SecurityBundle][PHPDoc] Added method doumentation for SecurityFactoryInterface
  FrameworkBundle: Client: getContainer(): fixed phpdoc
  [Validator] Updating inaccurate docblock comment
This commit is contained in:
Nicolas Grekas 2016-03-16 17:13:58 +01:00
commit 40c4f0dffd
17 changed files with 165 additions and 26 deletions

View File

@ -13,6 +13,7 @@ addons:
env: env:
global: global:
- MIN_PHP=5.3.9 - MIN_PHP=5.3.9
- SYMFONY_PROCESS_PHP_TEST_BINARY=~/.phpenv/versions/5.6/bin/php
matrix: matrix:
include: include:

View File

@ -11,7 +11,7 @@
*/ */
// Please update when phpunit needs to be reinstalled with fresh deps: // Please update when phpunit needs to be reinstalled with fresh deps:
// Cache-Id-Version: 2015-11-28 09:05 UTC // Cache-Id-Version: 2016-03-16 15:36 UTC
use Symfony\Component\Process\ProcessUtils; use Symfony\Component\Process\ProcessUtils;
@ -52,7 +52,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__
$zip->close(); $zip->close();
chdir("phpunit-$PHPUNIT_VERSION"); chdir("phpunit-$PHPUNIT_VERSION");
passthru("$COMPOSER remove --no-update symfony/yaml"); passthru("$COMPOSER remove --no-update symfony/yaml");
passthru("$COMPOSER require --dev --no-update symfony/phpunit-bridge \">=2.8@dev\""); passthru("$COMPOSER require --dev --no-update symfony/phpunit-bridge \">=3.1@dev\"");
passthru("$COMPOSER install --prefer-dist --no-progress --ansi"); passthru("$COMPOSER install --prefer-dist --no-progress --ansi");
file_put_contents('phpunit', <<<EOPHP file_put_contents('phpunit', <<<EOPHP
<?php <?php

View File

@ -52,7 +52,7 @@
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"> <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
<arguments> <arguments>
<array> <array>
<element><string>Symfony\Component\HttpFoundation</string></element> <element key="time-sensitive"><string>Symfony\Component\HttpFoundation</string></element>
</array> </array>
</arguments> </arguments>
</listener> </listener>

View File

@ -42,7 +42,7 @@ class Client extends BaseClient
/** /**
* Returns the container. * Returns the container.
* *
* @return ContainerInterface * @return ContainerInterface|null Returns null when the Kernel has been shutdown or not started yet
*/ */
public function getContainer() public function getContainer()
{ {

View File

@ -21,6 +21,20 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
*/ */
interface SecurityFactoryInterface interface SecurityFactoryInterface
{ {
/**
* Configures the container services required to use the authentication listener.
*
* @param ContainerBuilder $container
* @param string $id The unique id of the firewall
* @param array $config The options array for the listener
* @param string $userProvider The service id of the user provider
* @param string $defaultEntryPoint
*
* @return array containing three values:
* - the provider id
* - the listener id
* - the entry point id
*/
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint); public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint);
/** /**
@ -31,6 +45,12 @@ interface SecurityFactoryInterface
*/ */
public function getPosition(); public function getPosition();
/**
* Defines the configuration key used to reference the provider
* in the firewall configuration.
*
* @return string
*/
public function getKey(); public function getKey();
public function addConfiguration(NodeDefinition $builder); public function addConfiguration(NodeDefinition $builder);

View File

@ -24,18 +24,18 @@ class Filesystem
/** /**
* Copies a file. * Copies a file.
* *
* This method only copies the file if the origin file is newer than the target file. * If the target file is older than the origin file, it's always overwritten.
* If the target file is newer, it is overwritten only when the
* $overwriteNewerFiles option is set to true.
* *
* By default, if the target already exists, it is not overridden. * @param string $originFile The original filename
* * @param string $targetFile The target filename
* @param string $originFile The original filename * @param bool $overwriteNewerFiles If true, target files newer than origin files are overwritten
* @param string $targetFile The target filename
* @param bool $override Whether to override an existing file or not
* *
* @throws FileNotFoundException When originFile doesn't exist * @throws FileNotFoundException When originFile doesn't exist
* @throws IOException When copy fails * @throws IOException When copy fails
*/ */
public function copy($originFile, $targetFile, $override = false) public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
{ {
if (stream_is_local($originFile) && !is_file($originFile)) { if (stream_is_local($originFile) && !is_file($originFile)) {
throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile); throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
@ -44,7 +44,7 @@ class Filesystem
$this->mkdir(dirname($targetFile)); $this->mkdir(dirname($targetFile));
$doCopy = true; $doCopy = true;
if (!$override && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) { if (!$overwriteNewerFiles && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
$doCopy = filemtime($originFile) > filemtime($targetFile); $doCopy = filemtime($originFile) > filemtime($targetFile);
} }

View File

@ -187,7 +187,15 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface
$value = str_replace(',', $decSep, $value); $value = str_replace(',', $decSep, $value);
} }
$result = $formatter->parse($value, \NumberFormatter::TYPE_DOUBLE, $position); if (false !== strpos($value, $decSep)) {
$type = \NumberFormatter::TYPE_DOUBLE;
} else {
$type = PHP_INT_SIZE === 8
? \NumberFormatter::TYPE_INT64
: \NumberFormatter::TYPE_INT32;
}
$result = $formatter->parse($value, $type, $position);
if (intl_is_failure($formatter->getErrorCode())) { if (intl_is_failure($formatter->getErrorCode())) {
throw new TransformationFailedException($formatter->getErrorMessage()); throw new TransformationFailedException($formatter->getErrorMessage());

View File

@ -636,4 +636,11 @@ class NumberToLocalizedStringTransformerTest extends \PHPUnit_Framework_TestCase
$transformer->reverseTransform("12\xc2\xa0345,678foo"); $transformer->reverseTransform("12\xc2\xa0345,678foo");
} }
public function testReverseTransformBigint()
{
$transformer = new NumberToLocalizedStringTransformer(null, true);
$this->assertEquals(PHP_INT_MAX - 1, (int) $transformer->reverseTransform((string) (PHP_INT_MAX - 1)));
}
} }

View File

@ -16,13 +16,13 @@
namespace Symfony\Component\HttpKernel\Tests\HttpCache; namespace Symfony\Component\HttpKernel\Tests\HttpCache;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpCache\EsiResponseCacheStrategy; use Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategy;
class EsiResponseCacheStrategyTest extends \PHPUnit_Framework_TestCase class ResponseCacheStrategyTest extends \PHPUnit_Framework_TestCase
{ {
public function testMinimumSharedMaxAgeWins() public function testMinimumSharedMaxAgeWins()
{ {
$cacheStrategy = new EsiResponseCacheStrategy(); $cacheStrategy = new ResponseCacheStrategy();
$response1 = new Response(); $response1 = new Response();
$response1->setSharedMaxAge(60); $response1->setSharedMaxAge(60);
@ -41,7 +41,7 @@ class EsiResponseCacheStrategyTest extends \PHPUnit_Framework_TestCase
public function testSharedMaxAgeNotSetIfNotSetInAnyEmbeddedRequest() public function testSharedMaxAgeNotSetIfNotSetInAnyEmbeddedRequest()
{ {
$cacheStrategy = new EsiResponseCacheStrategy(); $cacheStrategy = new ResponseCacheStrategy();
$response1 = new Response(); $response1 = new Response();
$response1->setSharedMaxAge(60); $response1->setSharedMaxAge(60);
@ -59,7 +59,7 @@ class EsiResponseCacheStrategyTest extends \PHPUnit_Framework_TestCase
public function testSharedMaxAgeNotSetIfNotSetInMasterRequest() public function testSharedMaxAgeNotSetIfNotSetInMasterRequest()
{ {
$cacheStrategy = new EsiResponseCacheStrategy(); $cacheStrategy = new ResponseCacheStrategy();
$response1 = new Response(); $response1 = new Response();
$response1->setSharedMaxAge(60); $response1->setSharedMaxAge(60);

View File

@ -30,7 +30,7 @@
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"> <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
<arguments> <arguments>
<array> <array>
<element><string>Symfony\Component\HttpFoundation</string></element> <element key="time-sensitive"><string>Symfony\Component\HttpFoundation</string></element>
</array> </array>
</arguments> </arguments>
</listener> </listener>

View File

@ -31,7 +31,7 @@ class ProcessTest extends \PHPUnit_Framework_TestCase
public static function setUpBeforeClass() public static function setUpBeforeClass()
{ {
$phpBin = new PhpExecutableFinder(); $phpBin = new PhpExecutableFinder();
self::$phpBin = 'phpdbg' === PHP_SAPI ? 'php' : $phpBin->find(); self::$phpBin = getenv('SYMFONY_PROCESS_PHP_TEST_BINARY') ?: ('phpdbg' === PHP_SAPI ? 'php' : $phpBin->find());
if ('\\' !== DIRECTORY_SEPARATOR) { if ('\\' !== DIRECTORY_SEPARATOR) {
// exec is mandatory to deal with sending a signal to the process // exec is mandatory to deal with sending a signal to the process
// see https://github.com/symfony/symfony/issues/5030 about prepending // see https://github.com/symfony/symfony/issues/5030 about prepending

View File

@ -71,14 +71,20 @@ class PoFileLoader extends FileLoader
$messages = array(); $messages = array();
$item = $defaults; $item = $defaults;
$flags = array();
while ($line = fgets($stream)) { while ($line = fgets($stream)) {
$line = trim($line); $line = trim($line);
if ($line === '') { if ($line === '') {
// Whitespace indicated current item is done // Whitespace indicated current item is done
$this->addMessage($messages, $item); if (!in_array('fuzzy', $flags)) {
$this->addMessage($messages, $item);
}
$item = $defaults; $item = $defaults;
$flags = array();
} elseif (substr($line, 0, 2) === '#,') {
$flags = array_map('trim', explode(',', substr($line, 2)));
} elseif (substr($line, 0, 7) === 'msgid "') { } elseif (substr($line, 0, 7) === 'msgid "') {
// We start a new msg so save previous // We start a new msg so save previous
// TODO: this fails when comments or contexts are added // TODO: this fails when comments or contexts are added
@ -104,7 +110,9 @@ class PoFileLoader extends FileLoader
} }
} }
// save last item // save last item
$this->addMessage($messages, $item); if (!in_array('fuzzy', $flags)) {
$this->addMessage($messages, $item);
}
fclose($stream); fclose($stream);
return $messages; return $messages;

View File

@ -93,4 +93,16 @@ class PoFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('escaped "bar"', $messages['escaped "foo"']); $this->assertEquals('escaped "bar"', $messages['escaped "foo"']);
$this->assertEquals('escaped "bar"|escaped "bars"', $messages['escaped "foos"']); $this->assertEquals('escaped "bar"|escaped "bars"', $messages['escaped "foos"']);
} }
public function testSkipFuzzyTranslations()
{
$loader = new PoFileLoader();
$resource = __DIR__.'/../fixtures/fuzzy-translations.po';
$catalogue = $loader->load($resource, 'en', 'domain1');
$messages = $catalogue->all('domain1');
$this->assertArrayHasKey('foo1', $messages);
$this->assertArrayNotHasKey('foo2', $messages);
$this->assertArrayHasKey('foo3', $messages);
}
} }

View File

@ -0,0 +1,10 @@
#, php-format
msgid "foo1"
msgstr "bar1"
#, fuzzy, php-format
msgid "foo2"
msgstr "fuzzy bar2"
msgid "foo3"
msgstr "bar3"

View File

@ -118,9 +118,9 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface
* This method returns the equivalent PHP tokens for most scalar types * This method returns the equivalent PHP tokens for most scalar types
* (i.e. "false" for false, "1" for 1 etc.). Strings are always wrapped * (i.e. "false" for false, "1" for 1 etc.). Strings are always wrapped
* in double quotes ("). Objects, arrays and resources are formatted as * in double quotes ("). Objects, arrays and resources are formatted as
* "object", "array" and "resource". If the parameter $prettyDateTime * "object", "array" and "resource". If the $format bitmask contains
* is set to true, {@link \DateTime} objects will be formatted as * the PRETTY_DATE bit, then {@link \DateTime} objects will be formatted
* RFC-3339 dates ("Y-m-d H:i:s"). * as RFC-3339 dates ("Y-m-d H:i:s").
* *
* Be careful when passing message parameters to a constraint violation * Be careful when passing message parameters to a constraint violation
* that (may) contain objects, arrays or resources. These parameters * that (may) contain objects, arrays or resources. These parameters
@ -159,7 +159,7 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface
} }
if (is_object($value)) { if (is_object($value)) {
if ($format & self::OBJECT_TO_STRING && method_exists($value, '__toString')) { if (($format & self::OBJECT_TO_STRING) && method_exists($value, '__toString')) {
return $value->__toString(); return $value->__toString();
} }

View File

@ -11,10 +11,14 @@
namespace Symfony\Component\Validator\Tests\Constraints; namespace Symfony\Component\Validator\Tests\Constraints;
use Symfony\Bridge\PhpUnit\DnsMock;
use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\EmailValidator; use Symfony\Component\Validator\Constraints\EmailValidator;
use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Validation;
/**
* @group dns-sensitive
*/
class EmailValidatorTest extends AbstractConstraintValidatorTest class EmailValidatorTest extends AbstractConstraintValidatorTest
{ {
protected function getApiVersion() protected function getApiVersion()
@ -103,4 +107,40 @@ class EmailValidatorTest extends AbstractConstraintValidatorTest
$this->assertNoViolation(); $this->assertNoViolation();
} }
/**
* @dataProvider getDnsChecks
*/
public function testDnsChecks($type, $violation)
{
DnsMock::withMockedHosts(array('example.com' => array(array('type' => $violation ? false : $type))));
$constraint = new Email(array(
'message' => 'myMessage',
'MX' === $type ? 'checkMX' : 'checkHost' => true,
));
$this->validator->validate('foo@example.com', $constraint);
if (!$violation) {
$this->assertNoViolation();
} else {
$this->buildViolation('myMessage')
->setParameter('{{ value }}', '"foo@example.com"')
->setCode($violation)
->assertRaised();
}
}
public function getDnsChecks()
{
return array(
array('MX', false),
array('MX', Email::MX_CHECK_FAILED_ERROR),
array('A', false),
array('A', Email::HOST_CHECK_FAILED_ERROR),
array('AAAA', false),
array('AAAA', Email::HOST_CHECK_FAILED_ERROR),
);
}
} }

View File

@ -11,10 +11,14 @@
namespace Symfony\Component\Validator\Tests\Constraints; namespace Symfony\Component\Validator\Tests\Constraints;
use Symfony\Bridge\PhpUnit\DnsMock;
use Symfony\Component\Validator\Constraints\Url; use Symfony\Component\Validator\Constraints\Url;
use Symfony\Component\Validator\Constraints\UrlValidator; use Symfony\Component\Validator\Constraints\UrlValidator;
use Symfony\Component\Validator\Validation; use Symfony\Component\Validator\Validation;
/**
* @group dns-sensitive
*/
class UrlValidatorTest extends AbstractConstraintValidatorTest class UrlValidatorTest extends AbstractConstraintValidatorTest
{ {
protected function getApiVersion() protected function getApiVersion()
@ -188,6 +192,35 @@ class UrlValidatorTest extends AbstractConstraintValidatorTest
array('git://[::1]/'), array('git://[::1]/'),
); );
} }
/**
* @dataProvider getCheckDns
*/
public function testCheckDns($violation)
{
DnsMock::withMockedHosts(array('example.com' => array(array('type' => $violation ? '' : 'A'))));
$constraint = new Url(array(
'checkDNS' => true,
'dnsMessage' => 'myMessage',
));
$this->validator->validate('http://example.com', $constraint);
if (!$violation) {
$this->assertNoViolation();
} else {
$this->buildViolation('myMessage')
->setParameter('{{ value }}', '"example.com"')
->setCode(Url::INVALID_URL_ERROR)
->assertRaised();
}
}
public function getCheckDns()
{
return array(array(true), array(false));
}
} }
class EmailProvider class EmailProvider