Merge branch '3.3' into 3.4
* 3.3: [BrowserKit] Handle deprecations triggered in insulated requests [Bridge\PhpUnit] Handle deprecations triggered in separate processes [Validator] added magic method __isset() to File Constraint class [DI] Fix possible incorrect php-code when dumped strings contains newlines [Translation] minor: remove unused variable in test never match invalid IP addresses
This commit is contained in:
commit
2c18da709f
@ -238,6 +238,20 @@ class DeprecationErrorHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function collectDeprecations($outputFile)
|
||||||
|
{
|
||||||
|
$deprecations = array();
|
||||||
|
$previousErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, &$previousErrorHandler) {
|
||||||
|
if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) {
|
||||||
|
return $previousErrorHandler ? $previousErrorHandler($type, $msg, $file, $line, $context) : false;
|
||||||
|
}
|
||||||
|
$deprecations[] = array(error_reporting(), $msg);
|
||||||
|
});
|
||||||
|
register_shutdown_function(function () use ($outputFile, &$deprecations) {
|
||||||
|
file_put_contents($outputFile, serialize($deprecations));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static function hasColorSupport()
|
private static function hasColorSupport()
|
||||||
{
|
{
|
||||||
if ('\\' === DIRECTORY_SEPARATOR) {
|
if ('\\' === DIRECTORY_SEPARATOR) {
|
||||||
|
@ -39,6 +39,7 @@ class SymfonyTestsListenerTrait
|
|||||||
private $testsWithWarnings;
|
private $testsWithWarnings;
|
||||||
private $reportUselessTests;
|
private $reportUselessTests;
|
||||||
private $error;
|
private $error;
|
||||||
|
private $runsInSeparateProcess = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $mockedNamespaces List of namespaces, indexed by mocked features (time-sensitive or dns-sensitive)
|
* @param array $mockedNamespaces List of namespaces, indexed by mocked features (time-sensitive or dns-sensitive)
|
||||||
@ -183,6 +184,12 @@ class SymfonyTestsListenerTrait
|
|||||||
$this->reportUselessTests = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything();
|
$this->reportUselessTests = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This event is triggered before the test is re-run in isolation
|
||||||
|
if ($this->willBeIsolated($test)) {
|
||||||
|
$this->runsInSeparateProcess = tempnam(sys_get_temp_dir(), 'deprec');
|
||||||
|
putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$this->runsInSeparateProcess);
|
||||||
|
}
|
||||||
|
|
||||||
if (class_exists('PHPUnit_Util_Blacklist', false)) {
|
if (class_exists('PHPUnit_Util_Blacklist', false)) {
|
||||||
$Test = 'PHPUnit_Util_Test';
|
$Test = 'PHPUnit_Util_Test';
|
||||||
$AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError';
|
$AssertionFailedError = 'PHPUnit_Framework_AssertionFailedError';
|
||||||
@ -192,6 +199,7 @@ class SymfonyTestsListenerTrait
|
|||||||
}
|
}
|
||||||
$groups = $Test::getGroups(get_class($test), $test->getName(false));
|
$groups = $Test::getGroups(get_class($test), $test->getName(false));
|
||||||
|
|
||||||
|
if (!$this->runsInSeparateProcess) {
|
||||||
if (in_array('time-sensitive', $groups, true)) {
|
if (in_array('time-sensitive', $groups, true)) {
|
||||||
ClockMock::register(get_class($test));
|
ClockMock::register(get_class($test));
|
||||||
ClockMock::withClockMock(true);
|
ClockMock::withClockMock(true);
|
||||||
@ -199,6 +207,7 @@ class SymfonyTestsListenerTrait
|
|||||||
if (in_array('dns-sensitive', $groups, true)) {
|
if (in_array('dns-sensitive', $groups, true)) {
|
||||||
DnsMock::register(get_class($test));
|
DnsMock::register(get_class($test));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$annotations = $Test::parseTestMethodAnnotations(get_class($test), $test->getName(false));
|
$annotations = $Test::parseTestMethodAnnotations(get_class($test), $test->getName(false));
|
||||||
|
|
||||||
@ -245,15 +254,20 @@ class SymfonyTestsListenerTrait
|
|||||||
$this->reportUselessTests = null;
|
$this->reportUselessTests = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$errored = false;
|
if ($errored = null !== $this->error) {
|
||||||
|
|
||||||
if (null !== $this->error) {
|
|
||||||
if ($BaseTestRunner::STATUS_PASSED === $test->getStatus()) {
|
|
||||||
$test->getTestResultObject()->addError($test, $this->error, 0);
|
$test->getTestResultObject()->addError($test, $this->error, 0);
|
||||||
$errored = true;
|
$this->error = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->error = null;
|
if ($this->runsInSeparateProcess) {
|
||||||
|
foreach (unserialize(file_get_contents($this->runsInSeparateProcess)) as $deprecation) {
|
||||||
|
if ($deprecation[0]) {
|
||||||
|
trigger_error($deprecation[1], E_USER_DEPRECATED);
|
||||||
|
} else {
|
||||||
|
@trigger_error($deprecation[1], E_USER_DEPRECATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->runsInSeparateProcess = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->expectedDeprecations) {
|
if ($this->expectedDeprecations) {
|
||||||
@ -277,7 +291,7 @@ class SymfonyTestsListenerTrait
|
|||||||
$this->expectedDeprecations = $this->gatheredDeprecations = array();
|
$this->expectedDeprecations = $this->gatheredDeprecations = array();
|
||||||
$this->previousErrorHandler = null;
|
$this->previousErrorHandler = null;
|
||||||
}
|
}
|
||||||
if (-2 < $this->state && ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) {
|
if (!$this->runsInSeparateProcess && -2 < $this->state && ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase)) {
|
||||||
if (in_array('time-sensitive', $groups, true)) {
|
if (in_array('time-sensitive', $groups, true)) {
|
||||||
ClockMock::withClockMock(false);
|
ClockMock::withClockMock(false);
|
||||||
}
|
}
|
||||||
@ -315,4 +329,21 @@ class SymfonyTestsListenerTrait
|
|||||||
}
|
}
|
||||||
$this->gatheredDeprecations[] = $msg;
|
$this->gatheredDeprecations[] = $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Test $test
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function willBeIsolated($test)
|
||||||
|
{
|
||||||
|
if ($test->isInIsolation()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = new \ReflectionProperty($test, 'runTestInSeparateProcess');
|
||||||
|
$r->setAccessible(true);
|
||||||
|
|
||||||
|
return $r->getValue($test);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
23
src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php
Normal file
23
src/Symfony/Bridge/PhpUnit/Tests/ProcessIsolationTest.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Symfony\Bridge\PhpUnit\Tests;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't remove this test case, it tests the legacy group.
|
||||||
|
*
|
||||||
|
* @group legacy
|
||||||
|
*
|
||||||
|
* @runTestsInSeparateProcesses
|
||||||
|
*/
|
||||||
|
class ProcessIsolationTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @expectedDeprecation Test abc
|
||||||
|
*/
|
||||||
|
public function testIsolation()
|
||||||
|
{
|
||||||
|
@trigger_error('Test abc', E_USER_DEPRECATED);
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,10 @@ use Symfony\Bridge\PhpUnit\DeprecationErrorHandler;
|
|||||||
|
|
||||||
// Detect if we're loaded by an actual run of phpunit
|
// Detect if we're loaded by an actual run of phpunit
|
||||||
if (!defined('PHPUNIT_COMPOSER_INSTALL') && !class_exists('PHPUnit_TextUI_Command', false) && !class_exists('PHPUnit\TextUI\Command', false)) {
|
if (!defined('PHPUNIT_COMPOSER_INSTALL') && !class_exists('PHPUnit_TextUI_Command', false) && !class_exists('PHPUnit\TextUI\Command', false)) {
|
||||||
|
if ($ser = getenv('SYMFONY_DEPRECATIONS_SERIALIZE')) {
|
||||||
|
DeprecationErrorHandler::collectDeprecations($ser);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,9 +346,23 @@ abstract class Client
|
|||||||
*/
|
*/
|
||||||
protected function doRequestInProcess($request)
|
protected function doRequestInProcess($request)
|
||||||
{
|
{
|
||||||
|
$deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec');
|
||||||
|
putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$deprecationsFile);
|
||||||
$process = new PhpProcess($this->getScript($request), null, null);
|
$process = new PhpProcess($this->getScript($request), null, null);
|
||||||
$process->run();
|
$process->run();
|
||||||
|
|
||||||
|
if (file_exists($deprecationsFile)) {
|
||||||
|
$deprecations = file_get_contents($deprecationsFile);
|
||||||
|
unlink($deprecationsFile);
|
||||||
|
foreach ($deprecations ? unserialize($deprecations) : array() as $deprecation) {
|
||||||
|
if ($deprecation[0]) {
|
||||||
|
trigger_error($deprecation[1], E_USER_DEPRECATED);
|
||||||
|
} else {
|
||||||
|
@trigger_error($deprecation[1], E_USER_DEPRECATED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) {
|
if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) {
|
||||||
throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process->getOutput(), $process->getErrorOutput()));
|
throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process->getOutput(), $process->getErrorOutput()));
|
||||||
}
|
}
|
||||||
|
@ -1917,7 +1917,13 @@ EOF;
|
|||||||
|
|
||||||
private function doExport($value)
|
private function doExport($value)
|
||||||
{
|
{
|
||||||
|
if (is_string($value) && false !== strpos($value, "\n")) {
|
||||||
|
$cleanParts = explode("\n", $value);
|
||||||
|
$cleanParts = array_map(function ($part) { return var_export($part, true); }, $cleanParts);
|
||||||
|
$export = implode('."\n".', $cleanParts);
|
||||||
|
} else {
|
||||||
$export = var_export($value, true);
|
$export = var_export($value, true);
|
||||||
|
}
|
||||||
|
|
||||||
if ("'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('string:%s').'")) {
|
if ("'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('string:%s').'")) {
|
||||||
$export = $resolvedExport;
|
$export = $resolvedExport;
|
||||||
|
@ -71,6 +71,7 @@ class PhpDumperTest extends TestCase
|
|||||||
'optimize concatenation with empty string' => 'string1%empty_value%string2',
|
'optimize concatenation with empty string' => 'string1%empty_value%string2',
|
||||||
'optimize concatenation from the start' => '%empty_value%start',
|
'optimize concatenation from the start' => '%empty_value%start',
|
||||||
'optimize concatenation at the end' => 'end%empty_value%',
|
'optimize concatenation at the end' => 'end%empty_value%',
|
||||||
|
'new line' => "string with \nnew line",
|
||||||
));
|
));
|
||||||
$definition->setPublic(true);
|
$definition->setPublic(true);
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class ProjectServiceContainer extends Container
|
|||||||
*/
|
*/
|
||||||
protected function getTestService()
|
protected function getTestService()
|
||||||
{
|
{
|
||||||
return $this->services['test'] = new \stdClass(array('only dot' => '.', 'concatenation as value' => '.\'\'.', 'concatenation from the start value' => '\'\'.', '.' => 'dot as a key', '.\'\'.' => 'concatenation as a key', '\'\'.' => 'concatenation from the start key', 'optimize concatenation' => 'string1-string2', 'optimize concatenation with empty string' => 'string1string2', 'optimize concatenation from the start' => 'start', 'optimize concatenation at the end' => 'end'));
|
return $this->services['test'] = new \stdClass(array('only dot' => '.', 'concatenation as value' => '.\'\'.', 'concatenation from the start value' => '\'\'.', '.' => 'dot as a key', '.\'\'.' => 'concatenation as a key', '\'\'.' => 'concatenation from the start key', 'optimize concatenation' => 'string1-string2', 'optimize concatenation with empty string' => 'string1string2', 'optimize concatenation from the start' => 'start', 'optimize concatenation at the end' => 'end', 'new line' => 'string with '."\n".'new line'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getParameter($name)
|
public function getParameter($name)
|
||||||
|
@ -87,6 +87,10 @@ class IpUtils
|
|||||||
$netmask = 32;
|
$netmask = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (false === ip2long($address)) {
|
||||||
|
return self::$checkedIps[$cacheKey] = false;
|
||||||
|
}
|
||||||
|
|
||||||
return self::$checkedIps[$cacheKey] = 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
|
return self::$checkedIps[$cacheKey] = 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,4 +82,21 @@ class IpUtilsTest extends TestCase
|
|||||||
|
|
||||||
IpUtils::checkIp('2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65');
|
IpUtils::checkIp('2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider invalidIpAddressData
|
||||||
|
*/
|
||||||
|
public function testInvalidIpAddressesDoNotMatch($requestIp, $proxyIp)
|
||||||
|
{
|
||||||
|
$this->assertFalse(IpUtils::checkIp4($requestIp, $proxyIp));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invalidIpAddressData()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'invalid proxy wildcard' => array('192.168.20.13', '*'),
|
||||||
|
'invalid proxy missing netmask' => array('192.168.20.13', '0.0.0.0'),
|
||||||
|
'invalid request IP with invalid proxy wildcard' => array('0.0.0.0', '*'),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class TranslatorTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testConstructorInvalidLocale($locale)
|
public function testConstructorInvalidLocale($locale)
|
||||||
{
|
{
|
||||||
$translator = new Translator($locale);
|
new Translator($locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,6 +88,15 @@ class File extends Constraint
|
|||||||
return parent::__get($option);
|
return parent::__get($option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __isset($option)
|
||||||
|
{
|
||||||
|
if ('maxSize' === $option) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::__isset($option);
|
||||||
|
}
|
||||||
|
|
||||||
private function normalizeBinaryFormat($maxSize)
|
private function normalizeBinaryFormat($maxSize)
|
||||||
{
|
{
|
||||||
$factors = array(
|
$factors = array(
|
||||||
|
Reference in New Issue
Block a user