Merge branch '4.4' into 5.1

* 4.4:
  add mising sr (latn & cyrl) translations
  [Cache] fix ProxyAdapter not persisting items with infinite expiration
  [HttpClient] fail properly when the server replies with HTTP/0.9
  Fix CS
  [Cache] Limit cache version character range
  [DI] dump OS-indepent paths in the compiled container
  allow consumers to mock all methods
This commit is contained in:
Nicolas Grekas 2020-09-11 13:43:06 +02:00
commit da71a5d933
15 changed files with 163 additions and 24 deletions

View File

@ -88,7 +88,7 @@ class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterfa
$item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]];
}
$innerItem->set($item["\0*\0value"]);
$innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', $item["\0*\0expiry"])) : null);
$innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', 0 === $item["\0*\0expiry"] ? \PHP_INT_MAX : $item["\0*\0expiry"])) : null);
},
null,
CacheItem::class

View File

@ -24,6 +24,29 @@ class TagAwareAndProxyAdapterIntegrationTest extends TestCase
$cache->save($item);
$this->assertSame('bar', $cache->getItem('foo')->get());
$cache->invalidateTags(['tag2']);
$this->assertFalse($cache->getItem('foo')->isHit());
}
public function testIntegrationUsingProxiedAdapterForTagsPool()
{
$arrayAdapter = new ArrayAdapter();
$cache = new TagAwareAdapter($arrayAdapter, new ProxyAdapter($arrayAdapter));
$item = $cache->getItem('foo');
$item->expiresAfter(600);
$item->tag(['baz']);
$item->set('bar');
$cache->save($item);
$this->assertSame('bar', $cache->getItem('foo')->get());
$this->assertTrue($cache->getItem('foo')->isHit());
$cache->invalidateTags(['baz']);
$this->assertFalse($cache->getItem('foo')->isHit());
}
public function dataProvider(): array

View File

@ -128,7 +128,7 @@ trait AbstractAdapterTrait
}
}
$namespaceToClear = $this->namespace.$namespaceVersionToClear;
$namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5);
$namespaceVersion = strtr(substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5), '/', '_');
try {
$cleared = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0);
} catch (\Exception $e) {
@ -340,7 +340,7 @@ trait AbstractAdapterTrait
try {
foreach ($items as $id => $value) {
if (!isset($keys[$id])) {
$id = key($keys);
throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys)));
}
$key = $keys[$id];
unset($keys[$id]);
@ -365,7 +365,7 @@ trait AbstractAdapterTrait
$this->namespaceVersion = $v;
}
if ('1'.static::NS_SEPARATOR === $this->namespaceVersion) {
$this->namespaceVersion = substr_replace(base64_encode(pack('V', time())), static::NS_SEPARATOR, 5);
$this->namespaceVersion = strtr(substr_replace(base64_encode(pack('V', time())), static::NS_SEPARATOR, 5), '/', '_');
$this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0);
}
} catch (\Exception $e) {

View File

@ -2056,7 +2056,15 @@ EOF;
$suffix = $matches[0][1] + \strlen($matches[0][0]);
$matches[0][1] += \strlen($matches[1][0]);
$prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : '';
$suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : '';
if ('\\' === \DIRECTORY_SEPARATOR && isset($value[$suffix])) {
$cookie = '\\'.random_int(100000, \PHP_INT_MAX);
$suffix = '.'.$this->doExport(str_replace('\\', $cookie, substr($value, $suffix)), true);
$suffix = str_replace('\\'.$cookie, "'.\\DIRECTORY_SEPARATOR.'", $suffix);
} else {
$suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : '';
}
$dirname = $this->asFiles ? '$this->containerDir' : '__DIR__';
$offset = 2 + $this->targetDirMaxMatches - \count($matches);

View File

@ -239,7 +239,7 @@ class PhpDumperTest extends TestCase
$dumper = new PhpDumper($container);
$dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true);
if ('\\' === \DIRECTORY_SEPARATOR) {
$dump = str_replace('\\\\Fixtures\\\\includes\\\\foo.php', '/Fixtures/includes/foo.php', $dump);
$dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump);
}
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_as_files.txt', $dump);
}
@ -266,7 +266,7 @@ class PhpDumperTest extends TestCase
$dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'build_time' => 1563381341]), true);
if ('\\' === \DIRECTORY_SEPARATOR) {
$dump = str_replace('\\\\Fixtures\\\\includes\\\\', '/Fixtures/includes/', $dump);
$dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump);
}
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_inlined_factories.txt', $dump);
}
@ -292,7 +292,7 @@ class PhpDumperTest extends TestCase
$dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot', 'build_time' => 1563381341]), true);
if ('\\' === \DIRECTORY_SEPARATOR) {
$dump = str_replace('\\\\Fixtures\\\\includes\\\\', '/Fixtures/includes/', $dump);
$dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump);
}
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_lazy_inlined_factories.txt', $dump);
}
@ -310,7 +310,7 @@ class PhpDumperTest extends TestCase
$dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false]), true);
if ('\\' === \DIRECTORY_SEPARATOR) {
$dump = str_replace('\\\\Fixtures\\\\includes\\\\foo_lazy.php', '/Fixtures/includes/foo_lazy.php', $dump);
$dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump);
}
$this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services_non_shared_lazy_as_files.txt', $dump);
}
@ -986,7 +986,7 @@ class PhpDumperTest extends TestCase
$dumper = new PhpDumper($container);
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_array_params.php', str_replace('\\\\Dumper', '/Dumper', $dumper->dump(['file' => self::$fixturesPath.'/php/services_array_params.php', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false])));
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_array_params.php', str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dumper->dump(['file' => self::$fixturesPath.'/php/services_array_params.php', 'inline_factories_parameter' => false, 'inline_class_loader_parameter' => false])));
}
public function testExpressionReferencingPrivateService()
@ -1149,7 +1149,7 @@ class PhpDumperTest extends TestCase
$dump = $dumper->dump(['hot_path_tag' => 'container.hot_path', 'inline_class_loader_parameter' => 'inline_requires', 'file' => self::$fixturesPath.'/php/services_inline_requires.php']);
if ('\\' === \DIRECTORY_SEPARATOR) {
$dump = str_replace("'\\\\includes\\\\HotPath\\\\", "'/includes/HotPath/", $dump);
$dump = str_replace("'.\\DIRECTORY_SEPARATOR.'", '/', $dump);
}
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_inline_requires.php', $dump);

View File

@ -237,7 +237,7 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface
{
if (null !== $this->scale && null !== $this->roundingMode) {
// shift number to maintain the correct scale during rounding
$roundingCoef = pow(10, $this->scale);
$roundingCoef = 10 ** $this->scale;
// string representation to avoid rounding errors, similar to bcmul()
$number = (string) ($number * $roundingCoef);

View File

@ -338,10 +338,10 @@ abstract class AbstractRequestHandlerTest extends TestCase
public function getPostMaxSizeFixtures()
{
return [
[pow(1024, 3) + 1, '1G', true, ['{{ max }}' => '1G']],
[pow(1024, 3), '1G', false],
[pow(1024, 2) + 1, '1M', true, ['{{ max }}' => '1M']],
[pow(1024, 2), '1M', false],
[1024 ** 3 + 1, '1G', true, ['{{ max }}' => '1G']],
[1024 ** 3, '1G', false],
[1024 ** 2 + 1, '1M', true, ['{{ max }}' => '1M']],
[1024 ** 2, '1M', false],
[1024 + 1, '1K', true, ['{{ max }}' => '1K']],
[1024, '1K', false],
[null, '1K', false],

View File

@ -123,6 +123,19 @@ final class CurlResponse implements ResponseInterface
}
curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int {
if ('H' === (curl_getinfo($ch, \CURLINFO_PRIVATE)[0] ?? null)) {
$multi->handlesActivity[$id][] = null;
$multi->handlesActivity[$id][] = new TransportException(sprintf('Unsupported protocol for "%s"', curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL)));
return 0;
}
curl_setopt($ch, \CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int {
$multi->handlesActivity[$id][] = $data;
return \strlen($data);
});
$multi->handlesActivity[$id][] = $data;
return \strlen($data);

View File

@ -270,7 +270,7 @@ trait ResponseTrait
$debug .= "< \r\n";
if (!$info['http_code']) {
throw new TransportException('Invalid or missing HTTP status line.');
throw new TransportException(sprintf('Invalid or missing HTTP status line for "%s".', implode('', $info['url'])));
}
}
@ -350,7 +350,7 @@ trait ResponseTrait
if (\is_string($chunk = array_shift($multi->handlesActivity[$j]))) {
if (null !== $response->inflate && false === $chunk = @inflate_add($response->inflate, $chunk)) {
$multi->handlesActivity[$j] = [null, new TransportException('Error while processing content unencoding.')];
$multi->handlesActivity[$j] = [null, new TransportException(sprintf('Error while processing content unencoding for "%s".', $response->getInfo('url')))];
continue;
}

View File

@ -89,7 +89,7 @@ class CachingHttpClientTest extends TestCase
'test', [
'response_headers' => [
'X-Content-Digest' => 'some-hash',
]
],
]));
$headers = $response->getHeaders();
@ -100,7 +100,7 @@ class CachingHttpClientTest extends TestCase
{
$mockClient = new MockHttpClient($mockResponse);
$store = new Store(sys_get_temp_dir() . '/sf_http_cache');
$store = new Store(sys_get_temp_dir().'/sf_http_cache');
$client = new CachingHttpClient($mockClient, $store);
$response = $client->request('GET', 'http://test');

View File

@ -691,7 +691,7 @@ abstract class NumberFormatter
// Swiss rounding
if (0 < $roundingIncrement && 0 < $fractionDigits) {
$roundingFactor = $roundingIncrement / pow(10, $fractionDigits);
$roundingFactor = $roundingIncrement / 10 ** $fractionDigits;
$value = round($value / $roundingFactor) * $roundingFactor;
}
@ -713,7 +713,7 @@ abstract class NumberFormatter
if (isset(self::$phpRoundingMap[$roundingModeAttribute])) {
$value = round($value, $precision, self::$phpRoundingMap[$roundingModeAttribute]);
} elseif (isset(self::$customRoundingList[$roundingModeAttribute])) {
$roundingCoef = pow(10, $precision);
$roundingCoef = 10 ** $precision;
$value *= $roundingCoef;
$value = (float) (string) $value;

View File

@ -80,7 +80,7 @@ class MultiplierRetryStrategy implements RetryStrategyInterface
{
$retries = RedeliveryStamp::getRetryCountFromEnvelope($message);
$delay = $this->delayMilliseconds * pow($this->multiplier, $retries);
$delay = $this->delayMilliseconds * $this->multiplier ** $retries;
if ($delay > $this->maxDelayMilliseconds && 0 !== $this->maxDelayMilliseconds) {
return $this->maxDelayMilliseconds;

View File

@ -366,6 +366,26 @@
<source>This value should be between {{ min }} and {{ max }}.</source>
<target>Ова вредност треба да буде између {{ min }} и {{ max }}.</target>
</trans-unit>
<trans-unit id="95">
<source>This value is not a valid hostname.</source>
<target>Ова вредност није исправно име послужитеља (hostname).</target>
</trans-unit>
<trans-unit id="96">
<source>The number of elements in this collection should be a multiple of {{ compared_value }}.</source>
<target>Број елемената у овој колекцији би требало да буде дељив са {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="97">
<source>This value should satisfy at least one of the following constraints:</source>
<target>Ова вредност би требало да задовољава најмање једно од наредних ограничења:</target>
</trans-unit>
<trans-unit id="98">
<source>Each element of this collection should satisfy its own set of constraints.</source>
<target>Сваки елемент ове колекције би требало да задовољи сопствени скуп ограничења.</target>
</trans-unit>
<trans-unit id="99">
<source>This value is not a valid International Securities Identification Number (ISIN).</source>
<target>Ова вредност није исправна међународна идентификациона ознака хартија од вредности (ISIN).</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -366,6 +366,26 @@
<source>This value should be between {{ min }} and {{ max }}.</source>
<target>Ova vrednost treba da bude između {{ min }} i {{ max }}.</target>
</trans-unit>
<trans-unit id="95">
<source>This value is not a valid hostname.</source>
<target>Ova vrednost nije ispravno ime poslužitelja (hostname).</target>
</trans-unit>
<trans-unit id="96">
<source>The number of elements in this collection should be a multiple of {{ compared_value }}.</source>
<target>Broj elemenata u ovoj kolekciji bi trebalo da bude deljiv sa {{ compared_value }}.</target>
</trans-unit>
<trans-unit id="97">
<source>This value should satisfy at least one of the following constraints:</source>
<target>Ova vrednost bi trebalo da zadovoljava namjanje jedno od narednih ograničenja:</target>
</trans-unit>
<trans-unit id="98">
<source>Each element of this collection should satisfy its own set of constraints.</source>
<target>Svaki element ove kolekcije bi trebalo da zadovolji sopstveni skup ograničenja.</target>
</trans-unit>
<trans-unit id="99">
<source>This value is not a valid International Securities Identification Number (ISIN).</source>
<target>Ova vrednost nije ispravna međunarodna identifikaciona oznaka hartija od vrednosti (ISIN).</target>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -113,10 +113,45 @@ abstract class ConstraintValidatorTestCase extends TestCase
$context->setNode($this->value, $this->object, $this->metadata, $this->propertyPath);
$context->setConstraint($this->constraint);
$contextualValidator = $this->getMockBuilder(AssertingContextualValidator::class)
->setConstructorArgs([$context])
->setMethods([
'atPath',
'validate',
'validateProperty',
'validatePropertyValue',
'getViolations',
])
->getMock();
$contextualValidator->expects($this->any())
->method('atPath')
->willReturnCallback(function ($path) use ($contextualValidator) {
return $contextualValidator->doAtPath($path);
});
$contextualValidator->expects($this->any())
->method('validate')
->willReturnCallback(function ($value, $constraints = null, $groups = null) use ($contextualValidator) {
return $contextualValidator->doValidate($value, $constraints, $groups);
});
$contextualValidator->expects($this->any())
->method('validateProperty')
->willReturnCallback(function ($object, $propertyName, $groups = null) use ($contextualValidator) {
return $contextualValidator->validateProperty($object, $propertyName, $groups);
});
$contextualValidator->expects($this->any())
->method('validatePropertyValue')
->willReturnCallback(function ($objectOrClass, $propertyName, $value, $groups = null) use ($contextualValidator) {
return $contextualValidator->doValidatePropertyValue($objectOrClass, $propertyName, $value, $groups);
});
$contextualValidator->expects($this->any())
->method('getViolations')
->willReturnCallback(function () use ($contextualValidator) {
return $contextualValidator->doGetViolations();
});
$validator->expects($this->any())
->method('inContext')
->with($context)
->willReturn($this->getMockBuilder(AssertingContextualValidator::class)->setConstructorArgs([$context])->setMethods(null)->getMock());
->willReturn($contextualValidator);
return $context;
}
@ -403,6 +438,10 @@ class AssertingContextualValidator implements ContextualValidatorInterface
}
public function atPath($path)
{
}
public function doAtPath($path)
{
Assert::assertFalse($this->expectNoValidate, 'No validation calls have been expected.');
@ -416,6 +455,10 @@ class AssertingContextualValidator implements ContextualValidatorInterface
}
public function validate($value, $constraints = null, $groups = null)
{
}
public function doValidate($value, $constraints = null, $groups = null)
{
Assert::assertFalse($this->expectNoValidate, 'No validation calls have been expected.');
@ -437,11 +480,19 @@ class AssertingContextualValidator implements ContextualValidatorInterface
}
public function validateProperty($object, $propertyName, $groups = null)
{
}
public function doValidateProperty($object, $propertyName, $groups = null)
{
return $this;
}
public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null)
{
}
public function doValidatePropertyValue($objectOrClass, $propertyName, $value, $groups = null)
{
return $this;
}
@ -451,6 +502,10 @@ class AssertingContextualValidator implements ContextualValidatorInterface
return $this->context->getViolations();
}
public function doGetViolations()
{
}
public function expectNoValidate()
{
$this->expectNoValidate = true;