Merge branch '2.4'
* 2.4: [WIP][Finder] Fix wrong implementation on sortable callback comparator ommited space [Validator] Fixed StaticMethodLoader on systems that don't have E_STRICT enabled by default Include file path in exception [Process] Add validation on Process input Conflicts: src/Symfony/Component/Process/Process.php src/Symfony/Component/Process/ProcessBuilder.php src/Symfony/Component/Process/Tests/ProcessBuilderTest.php
This commit is contained in:
commit
c296c9ca19
@ -30,8 +30,8 @@ class SortableIterator implements \IteratorAggregate
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Traversable $iterator The Iterator to filter
|
||||
* @param int|callback $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
|
||||
* @param \Traversable $iterator The Iterator to filter
|
||||
* @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback)
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
@ -55,20 +55,20 @@ class SortableIterator implements \IteratorAggregate
|
||||
};
|
||||
} elseif (self::SORT_BY_ACCESSED_TIME === $sort) {
|
||||
$this->sort = function ($a, $b) {
|
||||
return ($a->getATime() > $b->getATime());
|
||||
return ($a->getATime() - $b->getATime());
|
||||
};
|
||||
} elseif (self::SORT_BY_CHANGED_TIME === $sort) {
|
||||
$this->sort = function ($a, $b) {
|
||||
return ($a->getCTime() > $b->getCTime());
|
||||
return ($a->getCTime() - $b->getCTime());
|
||||
};
|
||||
} elseif (self::SORT_BY_MODIFIED_TIME === $sort) {
|
||||
$this->sort = function ($a, $b) {
|
||||
return ($a->getMTime() > $b->getMTime());
|
||||
return ($a->getMTime() - $b->getMTime());
|
||||
};
|
||||
} elseif (is_callable($sort)) {
|
||||
$this->sort = $sort;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('The SortableIterator takes a PHP callback or a valid built-in sort algorithm as an argument.');
|
||||
throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,26 @@ class SortableIteratorTest extends RealIteratorTestCase
|
||||
*/
|
||||
public function testAccept($mode, $expected)
|
||||
{
|
||||
if (!is_callable($mode)) {
|
||||
switch ($mode) {
|
||||
case SortableIterator::SORT_BY_ACCESSED_TIME :
|
||||
file_get_contents(self::toAbsolute('.git'));
|
||||
sleep(1);
|
||||
file_get_contents(self::toAbsolute('.bar'));
|
||||
break;
|
||||
case SortableIterator::SORT_BY_CHANGED_TIME :
|
||||
file_put_contents(self::toAbsolute('test.php'), 'foo');
|
||||
sleep(1);
|
||||
file_put_contents(self::toAbsolute('test.py'), 'foo');
|
||||
break;
|
||||
case SortableIterator::SORT_BY_MODIFIED_TIME :
|
||||
file_put_contents(self::toAbsolute('test.php'), 'foo');
|
||||
sleep(1);
|
||||
file_put_contents(self::toAbsolute('test.py'), 'foo');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$inner = new Iterator(self::$files);
|
||||
|
||||
$iterator = new SortableIterator($inner, $mode);
|
||||
@ -82,9 +102,54 @@ class SortableIteratorTest extends RealIteratorTestCase
|
||||
'toto',
|
||||
);
|
||||
|
||||
$sortByAccessedTime = array(
|
||||
'foo/bar.tmp',
|
||||
'test.php',
|
||||
'toto',
|
||||
'foo bar',
|
||||
'foo',
|
||||
'test.py',
|
||||
'.foo',
|
||||
'.foo/.bar',
|
||||
'.foo/bar',
|
||||
'.git',
|
||||
'.bar'
|
||||
);
|
||||
|
||||
$sortByChangedTime = array(
|
||||
'foo',
|
||||
'foo/bar.tmp',
|
||||
'toto',
|
||||
'.git',
|
||||
'.bar',
|
||||
'.foo',
|
||||
'foo bar',
|
||||
'.foo/.bar',
|
||||
'.foo/bar',
|
||||
'test.php',
|
||||
'test.py'
|
||||
);
|
||||
|
||||
$sortByModifiedTime = array(
|
||||
'foo/bar.tmp',
|
||||
'foo',
|
||||
'toto',
|
||||
'.git',
|
||||
'.bar',
|
||||
'.foo',
|
||||
'foo bar',
|
||||
'.foo/.bar',
|
||||
'.foo/bar',
|
||||
'test.php',
|
||||
'test.py'
|
||||
);
|
||||
|
||||
return array(
|
||||
array(SortableIterator::SORT_BY_NAME, $this->toAbsolute($sortByName)),
|
||||
array(SortableIterator::SORT_BY_TYPE, $this->toAbsolute($sortByType)),
|
||||
array(SortableIterator::SORT_BY_ACCESSED_TIME, $this->toAbsolute($sortByAccessedTime)),
|
||||
array(SortableIterator::SORT_BY_CHANGED_TIME, $this->toAbsolute($sortByChangedTime)),
|
||||
array(SortableIterator::SORT_BY_MODIFIED_TIME, $this->toAbsolute($sortByModifiedTime)),
|
||||
array(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealpath(), $b->getRealpath()); }, $this->toAbsolute($customComparison)),
|
||||
);
|
||||
}
|
||||
|
@ -1064,10 +1064,11 @@ class Process
|
||||
*
|
||||
* @return self The current Process instance
|
||||
*
|
||||
* @throws LogicException In case the process is running
|
||||
*
|
||||
* @deprecated Deprecated since version 2.5, to be removed in 3.0.
|
||||
* This method is deprecated in favor of setInput.
|
||||
*
|
||||
* @throws LogicException In case the process is running
|
||||
* @throws InvalidArgumentException In case the argument is invalid
|
||||
*/
|
||||
public function setStdin($stdin)
|
||||
{
|
||||
@ -1091,7 +1092,7 @@ class Process
|
||||
throw new LogicException('Input can not be set while the process is running.');
|
||||
}
|
||||
|
||||
$this->input = $input;
|
||||
$this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -156,13 +156,15 @@ class ProcessBuilder
|
||||
/**
|
||||
* Sets the input of the process.
|
||||
*
|
||||
* @param string $input The input as a string
|
||||
* @param string|null $input The input as a string
|
||||
*
|
||||
* @return ProcessBuilder
|
||||
*
|
||||
* @throws InvalidArgumentException In case the argument is invalid
|
||||
*/
|
||||
public function setInput($input)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->input = ProcessUtils::validateInput(sprintf('%s::%s', __CLASS__, __FUNCTION__), $input);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
namespace Symfony\Component\Process;
|
||||
|
||||
use Symfony\Component\Process\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* ProcessUtils is a bunch of utility methods.
|
||||
*
|
||||
@ -72,6 +74,29 @@ class ProcessUtils
|
||||
return escapeshellarg($argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and normalized a Process input
|
||||
*
|
||||
* @param string $caller The name of method call that validates the input
|
||||
* @param mixed $input The input to validate
|
||||
*
|
||||
* @return string The validated input
|
||||
*
|
||||
* @throws InvalidArgumentException In case the input is not valid
|
||||
*/
|
||||
public static function validateInput($caller, $input)
|
||||
{
|
||||
if (null !== $input) {
|
||||
if (is_scalar($input) || (is_object($input) && method_exists($input, '__toString'))) {
|
||||
return (string) $input;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('%s only accepts strings.', $caller));
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
private static function isSurroundedBy($arg, $char)
|
||||
{
|
||||
return 2 < strlen($arg) && $char === $arg[0] && $char === $arg[strlen($arg) - 1];
|
||||
|
@ -172,6 +172,47 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
||||
$process->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidStdinValues
|
||||
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage Symfony\Component\Process\Process::setStdin only accepts strings.
|
||||
*/
|
||||
public function testInvalidStdin($value)
|
||||
{
|
||||
$process = $this->getProcess('php -v');
|
||||
$process->setStdin($value);
|
||||
}
|
||||
|
||||
public function provideInvalidStdinValues()
|
||||
{
|
||||
return array(
|
||||
array(array()),
|
||||
array(new NonStringifiable()),
|
||||
array(fopen('php://temporary', 'w')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideStdinValues
|
||||
*/
|
||||
public function testValidStdin($expected, $value)
|
||||
{
|
||||
$process = $this->getProcess('php -v');
|
||||
$process->setStdin($value);
|
||||
$this->assertSame($expected, $process->getStdin());
|
||||
}
|
||||
|
||||
public function provideStdinValues()
|
||||
{
|
||||
return array(
|
||||
array(null, null),
|
||||
array('24.5', 24.5),
|
||||
array('input data', 'input data'),
|
||||
// to maintain BC, supposed to be removed in 3.0
|
||||
array('stringifiable', new Stringifiable()),
|
||||
);
|
||||
}
|
||||
|
||||
public function chainedCommandsOutputProvider()
|
||||
{
|
||||
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
|
||||
@ -1012,3 +1053,15 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
abstract protected function getProcess($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60, array $options = array());
|
||||
}
|
||||
|
||||
class Stringifiable
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return 'stringifiable';
|
||||
}
|
||||
}
|
||||
|
||||
class NonStringifiable
|
||||
{
|
||||
}
|
||||
|
@ -212,4 +212,14 @@ class ProcessBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertFalse($process->isOutputDisabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage Symfony\Component\Process\ProcessBuilder::setInput only accepts strings.
|
||||
*/
|
||||
public function testInvalidInput()
|
||||
{
|
||||
$builder = ProcessBuilder::create();
|
||||
$builder->setInput(array());
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class YamlFileLoader extends ArrayLoader implements LoaderInterface
|
||||
try {
|
||||
$messages = $this->yamlParser->parse(file_get_contents($resource));
|
||||
} catch (ParseException $e) {
|
||||
throw new InvalidResourceException('Error parsing YAML.', 0, $e);
|
||||
throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $resource), 0, $e);
|
||||
}
|
||||
|
||||
// empty file
|
||||
|
@ -164,7 +164,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="44">
|
||||
<source>The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.</source>
|
||||
<target>Lebar gambar terlalu kecil ({{ width}}px). Ukuran lebar minimum yang diharapkan adalah {{ min_width }}px.</target>
|
||||
<target>Lebar gambar terlalu kecil ({{ width }}px). Ukuran lebar minimum yang diharapkan adalah {{ min_width }}px.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="45">
|
||||
<source>The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.</source>
|
||||
|
@ -17,6 +17,18 @@ use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
|
||||
|
||||
class StaticMethodLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $errorLevel;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->errorLevel = error_reporting();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
error_reporting($this->errorLevel);
|
||||
}
|
||||
|
||||
public function testLoadClassMetadataReturnsTrueIfSuccessful()
|
||||
{
|
||||
$loader = new StaticMethodLoader('loadMetadata');
|
||||
@ -78,6 +90,8 @@ class StaticMethodLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testLoadClassMetadataIgnoresAbstractMethods()
|
||||
{
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
$loader = new StaticMethodLoader('loadMetadata');
|
||||
$caught = false;
|
||||
try {
|
||||
|
Reference in New Issue
Block a user