Merge branch '2.7' into 2.8

* 2.7:
  [DomCrawler] Invalid uri created from forms if base tag present
  [Console] update param type phpdoc for StreamOutput
  [Console] fix typo in OutputInterface
  Use stderr by default when a specific output is not injected
  [Debug] Fix case mismatch detection
  [HttpKernel] fix broken multiline <esi:remove>
  [DoctrineBridge] Fixed #14840
  [FrameworkBundle] add a suggest for the serializer component
  [Yaml] Fix the parsing of float keys
  [Console] Ensure the console output is only detected as decorated when both stderr and stdout support colors
  [HttpKernel] fix DumpDataCollector compat with Twig 2.0
  Improve exception messages.
  Fix that two DirectoryResources with different patterns would be deduplicated
  Tests fix clockmock
  [WebProfilerBundle] Added tabindex="-1" to not interfer with normal UX
  missing "YAML" in the exception message.
  [Translator][warmup][fallback locales] fixed missing cache file generation.
  [framework-bundle] Add Test for TranslationUpdateCommand
  Use ObjectManager interface instead of EntityManager
This commit is contained in:
Fabien Potencier 2015-09-14 16:15:17 +02:00
commit 6393ec3169
37 changed files with 400 additions and 61 deletions

View File

@ -129,11 +129,15 @@ abstract class AbstractDoctrineExtension extends Extension
*/
protected function setMappingDriverConfig(array $mappingConfig, $mappingName)
{
if (!is_dir($mappingConfig['dir'])) {
$mappingDirectory = $mappingConfig['dir'];
if (!is_dir($mappingDirectory)) {
throw new \InvalidArgumentException(sprintf('Invalid Doctrine mapping path given. Cannot load Doctrine mapping/bundle named "%s".', $mappingName));
}
$this->drivers[$mappingConfig['type']][$mappingConfig['prefix']] = realpath($mappingConfig['dir']);
if (substr($mappingDirectory, 0, 7) !== 'phar://') {
$mappingDirectory = realpath($mappingDirectory);
}
$this->drivers[$mappingConfig['type']][$mappingConfig['prefix']] = $mappingDirectory;
}
/**

View File

@ -14,7 +14,7 @@ namespace Symfony\Bridge\Doctrine\Form\ChoiceList;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Doctrine\ORM\QueryBuilder;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\Persistence\ObjectManager;
/**
* Loads entities using a {@link QueryBuilder} instance.
@ -43,7 +43,7 @@ class ORMQueryBuilderLoader implements EntityLoaderInterface
* deprecated and will not be
* supported anymore as of
* Symfony 3.0.
* @param EntityManager $manager Deprecated.
* @param ObjectManager $manager Deprecated.
* @param string $class Deprecated.
*
* @throws UnexpectedTypeException
@ -59,8 +59,8 @@ class ORMQueryBuilderLoader implements EntityLoaderInterface
if ($queryBuilder instanceof \Closure) {
@trigger_error('Passing a QueryBuilder closure to '.__CLASS__.'::__construct() is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
if (!$manager instanceof EntityManager) {
throw new UnexpectedTypeException($manager, 'Doctrine\ORM\EntityManager');
if (!$manager instanceof ObjectManager) {
throw new UnexpectedTypeException($manager, 'Doctrine\Common\Persistence\ObjectManager');
}
@trigger_error('Passing an EntityManager to '.__CLASS__.'::__construct() is deprecated since version 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);

View File

@ -120,7 +120,12 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe
*/
public function onCommand(ConsoleCommandEvent $event)
{
$this->setOutput($event->getOutput());
$output = $event->getOutput();
if ($output instanceof ConsoleOutputInterface) {
$output = $output->getErrorOutput();
}
$this->setOutput($output);
}
/**
@ -149,11 +154,7 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe
*/
protected function write(array $record)
{
if ($record['level'] >= Logger::ERROR && $this->output instanceof ConsoleOutputInterface) {
$this->output->getErrorOutput()->write((string) $record['formatted']);
} else {
$this->output->write((string) $record['formatted']);
}
$this->output->write((string) $record['formatted']);
}
/**

View File

@ -110,7 +110,7 @@ class ConsoleHandlerTest extends \PHPUnit_Framework_TestCase
public function testWritingAndFormatting()
{
$output = $this->getMock('Symfony\Component\Console\Output\ConsoleOutputInterface');
$output = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$output
->expects($this->any())
->method('getVerbosity')
@ -122,19 +122,6 @@ class ConsoleHandlerTest extends \PHPUnit_Framework_TestCase
->with('<info>[2013-05-29 16:21:54] app.INFO:</info> My info message '."\n")
;
$errorOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
$errorOutput
->expects($this->once())
->method('write')
->with('<error>[2013-05-29 16:21:54] app.ERROR:</error> My error message '."\n")
;
$output
->expects($this->any())
->method('getErrorOutput')
->will($this->returnValue($errorOutput))
;
$handler = new ConsoleHandler(null, false);
$handler->setOutput($output);
@ -149,18 +136,6 @@ class ConsoleHandlerTest extends \PHPUnit_Framework_TestCase
);
$this->assertTrue($handler->handle($infoRecord), 'The handler finished handling the log as bubble is false.');
$errorRecord = array(
'message' => 'My error message',
'context' => array(),
'level' => Logger::ERROR,
'level_name' => Logger::getLevelName(Logger::ERROR),
'channel' => 'app',
'datetime' => new \DateTime('2013-05-29 16:21:54'),
'extra' => array(),
);
$this->assertTrue($handler->handle($errorRecord), 'The handler finished handling the log as bubble is false.');
}
public function testLogsFromListeners()

View File

@ -0,0 +1,141 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\Command;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Bundle\FrameworkBundle\Command\TranslationUpdateCommand;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\DependencyInjection;
use Symfony\Component\HttpKernel;
class TranslationUpdateCommandTest extends \PHPUnit_Framework_TestCase
{
private $fs;
private $translationDir;
public function testDumpMessagesAndClean()
{
$tester = $this->createCommandTester($this->getContainer(array('foo' => 'foo')));
$tester->execute(array('command' => 'translation:update', 'locale' => 'en', 'bundle' => 'foo', '--dump-messages' => true, '--clean' => true));
$this->assertRegExp('/foo/', $tester->getDisplay());
}
protected function setUp()
{
$this->fs = new Filesystem();
$this->translationDir = sys_get_temp_dir().'/'.uniqid('sf2_translation', true);
$this->fs->mkdir($this->translationDir.'/Resources/translations');
$this->fs->mkdir($this->translationDir.'/Resources/views');
}
protected function tearDown()
{
$this->fs->remove($this->translationDir);
}
/**
* @return CommandTester
*/
private function createCommandTester(DependencyInjection\ContainerInterface $container)
{
$command = new TranslationUpdateCommand();
$command->setContainer($container);
$application = new Application();
$application->add($command);
return new CommandTester($application->find('translation:update'));
}
private function getContainer($extractedMessages = array(), $loadedMessages = array(), HttpKernel\KernelInterface $kernel = null)
{
$translator = $this->getMockBuilder('Symfony\Component\Translation\Translator')
->disableOriginalConstructor()
->getMock();
$translator
->expects($this->any())
->method('getFallbackLocales')
->will($this->returnValue(array('en')));
$extractor = $this->getMock('Symfony\Component\Translation\Extractor\ExtractorInterface');
$extractor
->expects($this->any())
->method('extract')
->will(
$this->returnCallback(function ($path, $catalogue) use ($extractedMessages) {
$catalogue->add($extractedMessages);
})
);
$loader = $this->getMock('Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader');
$loader
->expects($this->any())
->method('loadMessages')
->will(
$this->returnCallback(function ($path, $catalogue) use ($loadedMessages) {
$catalogue->add($loadedMessages);
})
);
$writer = $this->getMock('Symfony\Component\Translation\Writer\TranslationWriter');
$writer
->expects($this->any())
->method('getFormats')
->will(
$this->returnValue(array('xlf', 'yml'))
);
if (null === $kernel) {
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
$kernel
->expects($this->any())
->method('getBundle')
->will($this->returnValueMap(array(
array('foo', true, $this->getBundle($this->translationDir)),
array('test', true, $this->getBundle('test')),
)));
}
$kernel
->expects($this->any())
->method('getRootDir')
->will($this->returnValue($this->translationDir));
$container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface');
$container
->expects($this->any())
->method('get')
->will($this->returnValueMap(array(
array('translation.extractor', 1, $extractor),
array('translation.loader', 1, $loader),
array('translation.writer', 1, $writer),
array('translator', 1, $translator),
array('kernel', 1, $kernel),
)));
return $container;
}
private function getBundle($path)
{
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
$bundle
->expects($this->any())
->method('getPath')
->will($this->returnValue($path))
;
return $bundle;
}
}

View File

@ -273,7 +273,7 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
// prime the cache
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles), 'yml');
$translator->setLocale('fr');
$translator->setFallbackLocales(array('fr'));
$translator->warmup($this->tmpDir);
$loader = $this->getMock('Symfony\Component\Translation\Loader\LoaderInterface');
@ -283,6 +283,7 @@ class TranslatorTest extends \PHPUnit_Framework_TestCase
$translator = $this->getTranslator($loader, array('cache_dir' => $this->tmpDir, 'resource_files' => $resourceFiles), 'yml');
$translator->setLocale('fr');
$translator->setFallbackLocales(array('fr'));
$this->assertEquals('répertoire', $translator->trans('folder'));
}

View File

@ -82,7 +82,13 @@ class Translator extends BaseTranslator implements WarmableInterface
return;
}
foreach ($this->resourceLocales as $locale) {
$locales = array_merge($this->getFallbackLocales(), array($this->getLocale()), $this->resourceLocales);
foreach (array_unique($locales) as $locale) {
// reset catalogue in case it's already loaded during the dump of the other locales.
if (isset($this->catalogues[$locale])) {
unset($this->catalogues[$locale]);
}
$this->loadCatalogue($locale);
}
}

View File

@ -52,6 +52,7 @@
"symfony/console": "For using the console commands",
"symfony/finder": "For using the translation loader and cache warmer",
"symfony/form": "For using forms",
"symfony/serializer": "For using the serializer service",
"symfony/validator": "For using validation",
"symfony/yaml": "For using the debug:config and lint:yaml commands",
"doctrine/cache": "For using alternative cache drivers"

View File

@ -1,7 +1,7 @@
<!-- START of Symfony Web Debug Toolbar -->
{% if 'normal' != position %}
<div id="sfMiniToolbar-{{ token }}" class="sf-minitoolbar" data-no-turbolink>
<a href="javascript:void(0);" title="Show Symfony toolbar" onclick="
<a href="javascript:void(0);" title="Show Symfony toolbar" tabindex="-1" accesskey="D" onclick="
var elem = this.parentNode;
if (elem.style.display == 'none') {
document.getElementById('sfToolbarMainContent-{{ token }}').style.display = 'none';
@ -37,7 +37,7 @@
{% endfor %}
{% if 'normal' != position %}
<a class="hide-button" title="Close Toolbar" onclick="
<a class="hide-button" title="Close Toolbar" tabindex="-1" accesskey="D" onclick="
var p = this.parentNode;
p.style.display = 'none';
(p.previousElementSibling || p.previousSibling).style.display = 'none';

View File

@ -38,7 +38,7 @@ class DirectoryResource implements ResourceInterface, \Serializable
*/
public function __toString()
{
return (string) $this->resource;
return md5(serialize(array($this->resource, $this->pattern)));
}
/**

View File

@ -54,7 +54,6 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
{
$resource = new DirectoryResource($this->directory);
$this->assertSame($this->directory, $resource->getResource(), '->getResource() returns the path to the resource');
$this->assertSame($this->directory, (string) $resource, '->__toString() returns the path to the resource');
}
public function testGetPattern()
@ -87,6 +86,13 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if a new file is added');
}
public function testIsFreshNewFileWithDifferentPattern()
{
$resource = new DirectoryResource($this->directory, '/.xml$/');
touch($this->directory.'/new.yaml', time() + 20);
$this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if a new file with a non-matching pattern is added');
}
public function testIsFreshDeleteFile()
{
$resource = new DirectoryResource($this->directory);
@ -149,4 +155,12 @@ class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
$this->assertSame($this->directory, $resource->getResource());
$this->assertSame('/\.(foo|xml)$/', $resource->getPattern());
}
public function testResourcesWithDifferentPatternsAreDifferent()
{
$resourceA = new DirectoryResource($this->directory, '/.xml$/');
$resourceB = new DirectoryResource($this->directory, '/.yaml$/');
$this->assertEquals(2, count(array_unique(array($resourceA, $resourceB))));
}
}

View File

@ -48,7 +48,12 @@ class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface
{
parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter);
$actualDecorated = $this->isDecorated();
$this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter());
if (null === $decorated) {
$this->setDecorated($actualDecorated && $this->stderr->isDecorated());
}
}
/**

View File

@ -35,7 +35,7 @@ class StreamOutput extends Output
/**
* Constructor.
*
* @param mixed $stream A stream resource
* @param resource $stream A stream resource
* @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface)
* @param bool|null $decorated Whether to decorate messages (null for auto-guessing)
* @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter)

View File

@ -221,8 +221,22 @@ class DebugClassLoader
throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
}
if (self::$caseCheck && preg_match('#(?:[/\\\\][a-zA-Z_\x7F-\xFF][a-zA-Z0-9_\x7F-\xFF]*+)++\.(?:php|hh)$#D', $file, $tail)) {
$tail = $tail[0];
if (self::$caseCheck) {
$real = explode('\\', $class.strrchr($file, '.'));
$tail = explode(DIRECTORY_SEPARATOR, str_replace('/', DIRECTORY_SEPARATOR, $file));
$i = count($tail) - 1;
$j = count($real) - 1;
while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) {
--$i;
--$j;
}
array_splice($tail, 0, $i + 1);
}
if (self::$caseCheck && $tail) {
$tail = DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $tail);
$tailLen = strlen($tail);
$real = $refl->getFileName();
@ -289,7 +303,7 @@ class DebugClassLoader
if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true)
&& 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false)
) {
throw new \RuntimeException(sprintf('Case mismatch between class and source file names: %s vs %s', $class, $real));
throw new \RuntimeException(sprintf('Case mismatch between class and real file names: %s vs %s in %s', substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)));
}
}

View File

@ -136,7 +136,7 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Case mismatch between class and source file names
* @expectedExceptionMessage Case mismatch between class and real file names
*/
public function testFileCaseMismatch()
{

View File

@ -328,7 +328,7 @@ class YamlFileLoader extends FileLoader
try {
$configuration = $this->yamlParser->parse(file_get_contents($file));
} catch (ParseException $e) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $file), 0, $e);
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $file), 0, $e);
}
return $this->validate($configuration, $file);

View File

@ -0,0 +1,2 @@
parameters:
FOO: bar

View File

@ -88,6 +88,7 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
array('bad_services'),
array('bad_service'),
array('bad_calls'),
array('bad_format'),
);
}

View File

@ -790,7 +790,7 @@ class Crawler extends \SplObjectStorage
throw new \InvalidArgumentException('The current node list is empty.');
}
$form = new Form($this->getNode(0), $this->uri, $method);
$form = new Form($this->getNode(0), $this->uri, $method, $this->baseHref);
if (null !== $values) {
$form->setValues($values);

View File

@ -33,20 +33,27 @@ class Form extends Link implements \ArrayAccess
*/
private $fields;
/**
* @var string
*/
private $baseHref;
/**
* Constructor.
*
* @param \DOMElement $node A \DOMElement instance
* @param string $currentUri The URI of the page where the form is embedded
* @param string $method The method to use for the link (if null, it defaults to the method defined by the form)
* @param string $baseHref The URI of the <base> used for relative links, but not for empty action
*
* @throws \LogicException if the node is not a button inside a form tag
*
* @api
*/
public function __construct(\DOMElement $node, $currentUri, $method = null)
public function __construct(\DOMElement $node, $currentUri, $method = null, $baseHref = null)
{
parent::__construct($node, $currentUri, $method);
$this->baseHref = $baseHref;
$this->initialize();
}
@ -458,6 +465,10 @@ class Form extends Link implements \ArrayAccess
$this->addField($node);
}
}
if ($this->baseHref && '' !== $this->node->getAttribute('action')) {
$this->currentUri = $this->baseHref;
}
}
private function addField(\DOMElement $node)

View File

@ -982,9 +982,12 @@ HTML;
public function getBaseTagWithFormData()
{
return array(
array('https://base.com/', 'link/', 'https://base.com/link/', 'https://base.com/link/', '<base> tag does work with a path and relative form action'),
array('/basepath', '/registration', 'http://domain.com/registration', 'http://domain.com/registration', '<base> tag does work with a path and form action'),
array('/basepath', '', 'http://domain.com/registration', 'http://domain.com/registration', '<base> tag does work with a path and empty form action'),
array('http://base.com/', '/registration', 'http://base.com/registration', 'http://domain.com/registration', '<base> tag does work with a URL and form action'),
array('http://base.com', '', 'http://domain.com/path/form', 'http://domain.com/path/form', '<base> tag does work with a URL and an empty form action'),
array('http://base.com/path', '/registration', 'http://base.com/registration', 'http://domain.com/path/form', '<base> tag does work with a URL and form action'),
);
}

View File

@ -18,7 +18,22 @@ function time($asFloat = false)
namespace Symfony\Component\HttpFoundation\Tests;
function with_clock_mock($enable = null)
{
static $enabled;
if (null === $enable) {
return $enabled;
}
$enabled = $enable;
}
function time()
{
if (!with_clock_mock()) {
return \time();
}
return $_SERVER['REQUEST_TIME'];
}

View File

@ -23,6 +23,18 @@ require_once __DIR__.'/ClockMock.php';
*/
class CookieTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
with_clock_mock(true);
parent::setUp();
}
public function tearDown()
{
with_clock_mock(false);
parent::tearDown();
}
public function invalidNames()
{
return array(

View File

@ -18,6 +18,18 @@ require_once __DIR__.'/ClockMock.php';
class ResponseHeaderBagTest extends \PHPUnit_Framework_TestCase
{
public function setUp()
{
with_clock_mock(true);
parent::setUp();
}
public function tearDown()
{
with_clock_mock(false);
parent::tearDown();
}
/**
* @covers Symfony\Component\HttpFoundation\ResponseHeaderBag::allPreserveCase
* @dataProvider provideAllPreserveCase

View File

@ -98,9 +98,9 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
} elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof \Twig_Template) {
$info = $trace[$i]['object'];
$name = $info->getTemplateName();
$src = $info->getEnvironment()->getLoader()->getSource($name);
$src = method_exists($info, 'getSource') ? $info->getSource() : $info->getEnvironment()->getLoader()->getSource($name);
$info = $info->getDebugInfo();
if (isset($info[$trace[$i - 1]['line']])) {
if (null !== $src && isset($info[$trace[$i - 1]['line']])) {
$file = false;
$line = $info[$trace[$i - 1]['line']];
$src = explode("\n", $src);

View File

@ -213,8 +213,8 @@ class Esi implements SurrogateInterface
// we don't use a proper XML parser here as we can have ESI tags in a plain text response
$content = $response->getContent();
$content = preg_replace('#<esi\:remove>.*?</esi\:remove>#', '', $content);
$content = preg_replace('#<esi\:comment[^>]*(?:/|</esi\:comment)>#', '', $content);
$content = preg_replace('#<esi\:remove>.*?</esi\:remove>#s', '', $content);
$content = preg_replace('#<esi\:comment[^>]+>#s', '', $content);
$chunks = preg_split('#<esi\:include\s+(.*?)\s*(?:/|</esi\:include)>#', $content, -1, PREG_SPLIT_DELIM_CAPTURE);
$chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]);

View File

@ -92,6 +92,28 @@ class EsiTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($response->headers->has('x-body-eval'));
}
public function testMultilineEsiRemoveTagsAreRemoved()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response('<esi:remove> <a href="http://www.example.com">www.example.com</a> </esi:remove> Keep this'."<esi:remove>\n <a>www.example.com</a> </esi:remove> And this");
$esi->process($request, $response);
$this->assertEquals(' Keep this And this', $response->getContent());
}
public function testCommentTagsAreRemoved()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response('<esi:comment text="some comment &gt;" /> Keep this');
$esi->process($request, $response);
$this->assertEquals(' Keep this', $response->getContent());
}
public function testProcess()
{
$esi = new Esi();

View File

@ -0,0 +1,3 @@
blog_show:
path: /blog/{slug}
defaults: { _controller: "MyBundle:Blog:show" }

View File

@ -51,7 +51,15 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
public function getPathsToInvalidFiles()
{
return array(array('nonvalid.yml'), array('nonvalid2.yml'), array('incomplete.yml'), array('nonvalidkeys.yml'), array('nonesense_resource_plus_path.yml'), array('nonesense_type_without_resource.yml'));
return array(
array('nonvalid.yml'),
array('nonvalid2.yml'),
array('incomplete.yml'),
array('nonvalidkeys.yml'),
array('nonesense_resource_plus_path.yml'),
array('nonesense_type_without_resource.yml'),
array('bad_format.yml'),
);
}
public function testLoadSpecialRouteName()

View File

@ -18,10 +18,27 @@ function microtime($asFloat = false)
namespace Symfony\Component\Stopwatch\Tests;
function with_clock_mock($enable = null)
{
static $enabled;
if (null === $enable) {
return $enabled;
}
$enabled = $enable;
}
function usleep($us)
{
static $now;
if (!with_clock_mock()) {
\usleep($us);
return;
}
if (null === $now) {
$now = \microtime(true);
}
@ -31,6 +48,10 @@ function usleep($us)
function microtime($asFloat = false)
{
if (!with_clock_mock()) {
return \microtime($asFloat);
}
if (!$asFloat) {
return \microtime(false);
}

View File

@ -24,6 +24,18 @@ class StopwatchEventTest extends \PHPUnit_Framework_TestCase
{
const DELTA = 37;
public function setUp()
{
with_clock_mock(true);
parent::setUp();
}
public function tearDown()
{
with_clock_mock(false);
parent::tearDown();
}
public function testGetOrigin()
{
$event = new StopwatchEvent(12);

View File

@ -24,6 +24,18 @@ class StopwatchTest extends \PHPUnit_Framework_TestCase
{
const DELTA = 20;
public function setUp()
{
with_clock_mock(true);
parent::setUp();
}
public function tearDown()
{
with_clock_mock(false);
parent::tearDown();
}
public function testStart()
{
$stopwatch = new Stopwatch();

View File

@ -121,7 +121,7 @@ class YamlFileLoader extends FileLoader
try {
$classes = $this->yamlParser->parse(file_get_contents($path));
} catch (ParseException $e) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid.', $path), 0, $e);
throw new \InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $path), 0, $e);
}
// empty file

View File

@ -33,15 +33,26 @@ class YamlFileLoaderTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($loader->loadClassMetadata($metadata));
}
public function testLoadClassMetadataThrowsExceptionIfNotAnArray()
/**
* @dataProvider provideInvalidYamlFiles
* @expectedException \InvalidArgumentException
*/
public function testInvalidYamlFiles($path)
{
$loader = new YamlFileLoader(__DIR__.'/nonvalid-mapping.yml');
$loader = new YamlFileLoader(__DIR__.'/'.$path);
$metadata = new ClassMetadata('Symfony\Component\Validator\Tests\Fixtures\Entity');
$this->setExpectedException('\InvalidArgumentException');
$loader->loadClassMetadata($metadata);
}
public function provideInvalidYamlFiles()
{
return array(
array('nonvalid-mapping.yml'),
array('bad-format.yml'),
);
}
/**
* @see https://github.com/symfony/symfony/pull/12158
*/

View File

@ -0,0 +1,9 @@
namespaces:
custom: Symfony\Component\Validator\Tests\Fixtures\
Symfony\Component\Validator\Tests\Fixtures\Entity:
constraints:
# Custom constraint
- Symfony\Component\Validator\Tests\Fixtures\ConstraintA: ~
# Custom constraint with namespaces prefix
- "custom:ConstraintB": ~

View File

@ -135,6 +135,11 @@ class Parser
throw $e;
}
// Convert float keys to strings, to avoid being converted to integers by PHP
if (is_float($key)) {
$key = (string) $key;
}
if ('<<' === $key) {
$mergeNode = true;
$allowOverwrite = true;

View File

@ -747,6 +747,24 @@ bar: 2
EOF;
$this->assertEquals(array('foo' => 1, 'bar' => 2), $this->parser->parse($yaml));
}
public function testFloatKeys()
{
$yaml = <<<EOF
foo:
1.2: "bar"
1.3: "baz"
EOF;
$expected = array(
'foo' => array(
'1.2' => 'bar',
'1.3' => 'baz',
),
);
$this->assertEquals($expected, $this->parser->parse($yaml));
}
}
class B