Fix an error message to be more accurate

This commit is contained in:
Yonel Ceruto 2019-10-28 15:33:22 -04:00
parent 0c772969b4
commit 1be68a752a
2 changed files with 29 additions and 22 deletions

View File

@ -917,7 +917,7 @@ class OptionsResolver implements Options
// Validate the type of the resolved option // Validate the type of the resolved option
if (isset($this->allowedTypes[$option])) { if (isset($this->allowedTypes[$option])) {
$valid = false; $valid = true;
$invalidTypes = []; $invalidTypes = [];
foreach ($this->allowedTypes[$option] as $type) { foreach ($this->allowedTypes[$option] as $type) {
@ -929,13 +929,18 @@ class OptionsResolver implements Options
} }
if (!$valid) { if (!$valid) {
$keys = array_keys($invalidTypes); $fmtActualValue = $this->formatValue($value);
$fmtAllowedTypes = implode('" or "', $this->allowedTypes[$option]);
$fmtProvidedTypes = implode('|', array_keys($invalidTypes));
$allowedContainsArrayType = \count(array_filter($this->allowedTypes[$option], static function ($item) {
return '[]' === substr(self::$typeAliases[$item] ?? $item, -2);
})) > 0;
if (1 === \count($keys) && '[]' === substr($keys[0], -2)) { if (\is_array($value) && $allowedContainsArrayType) {
throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), $keys[0])); throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $option, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
} }
throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), implode('|', array_keys($invalidTypes)))); throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
} }
} }
@ -1040,26 +1045,23 @@ class OptionsResolver implements Options
{ {
if (\is_array($value) && '[]' === substr($type, -2)) { if (\is_array($value) && '[]' === substr($type, -2)) {
$type = substr($type, 0, -2); $type = substr($type, 0, -2);
$valid = true;
foreach ($value as $val) { foreach ($value as $val) {
if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) { if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) {
return false; $valid = false;
} }
} }
return true; return $valid;
} }
if (('null' === $type && null === $value) || (\function_exists($func = 'is_'.$type) && $func($value)) || $value instanceof $type) { if (('null' === $type && null === $value) || (\function_exists($func = 'is_'.$type) && $func($value)) || $value instanceof $type) {
return true; return true;
} }
if (!$invalidTypes) { if (!$invalidTypes || $level > 0) {
$suffix = ''; $invalidTypes[$this->formatTypeOf($value)] = true;
while (\strlen($suffix) < $level * 2) {
$suffix .= '[]';
}
$invalidTypes[$this->formatTypeOf($value).$suffix] = true;
} }
return false; return false;

View File

@ -776,7 +776,7 @@ class OptionsResolverTest extends TestCase
public function testResolveFailsIfInvalidTypedArray() public function testResolveFailsIfInvalidTypedArray()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime[]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[]'); $this->resolver->setAllowedTypes('foo', 'int[]');
@ -796,7 +796,7 @@ class OptionsResolverTest extends TestCase
public function testResolveFailsIfTypedArrayContainsInvalidTypes() public function testResolveFailsIfTypedArrayContainsInvalidTypes()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass[]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass|array|DateTime".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[]'); $this->resolver->setAllowedTypes('foo', 'int[]');
$values = range(1, 5); $values = range(1, 5);
@ -811,7 +811,7 @@ class OptionsResolverTest extends TestCase
public function testResolveFailsWithCorrectLevelsButWrongScalar() public function testResolveFailsWithCorrectLevelsButWrongScalar()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double[][]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[][]'); $this->resolver->setAllowedTypes('foo', 'int[][]');
@ -847,6 +847,11 @@ class OptionsResolverTest extends TestCase
[42, 'string', 'The option "option" with value 42 is expected to be of type "string", but is of type "integer".'], [42, 'string', 'The option "option" with value 42 is expected to be of type "string", but is of type "integer".'],
[null, 'string', 'The option "option" with value null is expected to be of type "string", but is of type "NULL".'], [null, 'string', 'The option "option" with value null is expected to be of type "string", but is of type "NULL".'],
['bar', '\stdClass', 'The option "option" with value "bar" is expected to be of type "\stdClass", but is of type "string".'], ['bar', '\stdClass', 'The option "option" with value "bar" is expected to be of type "\stdClass", but is of type "string".'],
[['foo', 12], 'string[]', 'The option "option" with value array is expected to be of type "string[]", but one of the elements is of type "integer".'],
[123, ['string[]', 'string'], 'The option "option" with value 123 is expected to be of type "string[]" or "string", but is of type "integer".'],
[[null], ['string[]', 'string'], 'The option "option" with value array is expected to be of type "string[]" or "string", but one of the elements is of type "NULL".'],
[['string', null], ['string[]', 'string'], 'The option "option" with value array is expected to be of type "string[]" or "string", but one of the elements is of type "NULL".'],
[[\stdClass::class], ['string'], 'The option "option" with value array is expected to be of type "string", but is of type "array".'],
]; ];
} }
@ -1898,7 +1903,7 @@ class OptionsResolverTest extends TestCase
public function testNestedArraysException() public function testNestedArraysException()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer[][][][]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'float[][][][]'); $this->resolver->setAllowedTypes('foo', 'float[][][][]');
@ -1916,7 +1921,7 @@ class OptionsResolverTest extends TestCase
public function testNestedArrayException1() public function testNestedArrayException1()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean|string|array".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[][]'); $this->resolver->setAllowedTypes('foo', 'int[][]');
$this->resolver->resolve([ $this->resolver->resolve([
@ -1929,7 +1934,7 @@ class OptionsResolverTest extends TestCase
public function testNestedArrayException2() public function testNestedArrayException2()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean|string|array".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[][]'); $this->resolver->setAllowedTypes('foo', 'int[][]');
$this->resolver->resolve([ $this->resolver->resolve([
@ -1942,7 +1947,7 @@ class OptionsResolverTest extends TestCase
public function testNestedArrayException3() public function testNestedArrayException3()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string[][]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string|integer".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'string[][][]'); $this->resolver->setAllowedTypes('foo', 'string[][][]');
$this->resolver->resolve([ $this->resolver->resolve([
@ -1955,7 +1960,7 @@ class OptionsResolverTest extends TestCase
public function testNestedArrayException4() public function testNestedArrayException4()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer[][][]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'string[][][]'); $this->resolver->setAllowedTypes('foo', 'string[][][]');
$this->resolver->resolve([ $this->resolver->resolve([
@ -1969,7 +1974,7 @@ class OptionsResolverTest extends TestCase
public function testNestedArrayException5() public function testNestedArrayException5()
{ {
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException'); $this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
$this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array[]".'); $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array".');
$this->resolver->setDefined('foo'); $this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'string[]'); $this->resolver->setAllowedTypes('foo', 'string[]');
$this->resolver->resolve([ $this->resolver->resolve([