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:
Fabien Potencier 2014-05-22 15:47:45 +02:00
commit c296c9ca19
10 changed files with 183 additions and 13 deletions

View File

@ -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.');
}
}

View File

@ -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)),
);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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];

View File

@ -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
{
}

View File

@ -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());
}
}

View File

@ -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

View 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>

View File

@ -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 {