Skip to content

Commit

Permalink
fix: do not accept shaped array with excessive key(s)
Browse files Browse the repository at this point in the history
The mapper will now delete the excessive keys given as input to a shaped
 array.
  • Loading branch information
romm committed Dec 2, 2021
1 parent 710c7a9 commit 5a578ea
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/Type/Types/ShapedArrayType.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
use CuyZ\Valinor\Type\TraversableType;
use CuyZ\Valinor\Type\Type;

use function array_diff;
use function array_key_exists;
use function array_keys;
use function count;
use function implode;
use function in_array;
use function is_array;
Expand Down Expand Up @@ -45,9 +48,11 @@ public function accepts($value): bool
return false;
}

$keys = [];

foreach ($this->elements as $shape) {
$type = $shape->type();
$key = $shape->key()->value();
$keys[] = $key = $shape->key()->value();
$valueExists = array_key_exists($key, $value);

if (! $valueExists && ! $shape->isOptional()) {
Expand All @@ -59,7 +64,9 @@ public function accepts($value): bool
}
}

return true;
$excess = array_diff(array_keys($value), $keys);

return count($excess) === 0;
}

public function matches(Type $other): bool
Expand Down
11 changes: 11 additions & 0 deletions tests/Integration/Mapping/Type/ShapedArrayValuesMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ final class ShapedArrayValuesMappingTest extends IntegrationTest
public function test_values_are_mapped_properly(): void
{
$source = [
'basicShapedArrayWithExcessiveKey' => [
'foo' => 'foo',
'bar' => 42,
],
'basicShapedArrayWithStringKeys' => [
'foo' => 'fiz',
'bar' => 42,
Expand Down Expand Up @@ -47,6 +51,7 @@ public function test_values_are_mapped_properly(): void
$this->mappingFail($error);
}

self::assertSame(['foo' => 'foo'], $result->basicShapedArrayWithExcessiveKey);
self::assertSame($source['basicShapedArrayWithStringKeys'], $result->basicShapedArrayWithStringKeys);
self::assertSame($source['basicShapedArrayWithIntegerKeys'], $result->basicShapedArrayWithIntegerKeys);
self::assertInstanceOf(SimpleObject::class, $result->shapedArrayWithObject['foo']);
Expand Down Expand Up @@ -79,6 +84,9 @@ public function test_value_that_cannot_be_casted_throws_exception(): void

class ShapedArrayValues
{
/** @var array{foo: string} */
public array $basicShapedArrayWithExcessiveKey;

/** @var array{foo: string, bar: int} */
public array $basicShapedArrayWithStringKeys;

Expand Down Expand Up @@ -106,6 +114,7 @@ class ShapedArrayValues
class ShapedArrayValuesWithConstructor extends ShapedArrayValues
{
/**
* @param array{foo: string} $basicShapedArrayWithExcessiveKey
* @param array{foo: string, bar: int} $basicShapedArrayWithStringKeys
* @param array{0: string, 1: float} $basicShapedArrayWithIntegerKeys
* @param array{foo: SimpleObject} $shapedArrayWithObject
Expand All @@ -117,13 +126,15 @@ class ShapedArrayValuesWithConstructor extends ShapedArrayValues
* @param array{0: int, float, optionalString?: string, mandatoryString: string} $advancedShapedArray
*/
public function __construct(
array $basicShapedArrayWithExcessiveKey,
array $basicShapedArrayWithStringKeys,
array $basicShapedArrayWithIntegerKeys,
array $shapedArrayWithObject,
array $shapedArrayWithOptionalValue,
array $shapedArrayOnSeveralLines,
array $advancedShapedArray
) {
$this->basicShapedArrayWithExcessiveKey = $basicShapedArrayWithExcessiveKey;
$this->basicShapedArrayWithStringKeys = $basicShapedArrayWithStringKeys;
$this->basicShapedArrayWithIntegerKeys = $basicShapedArrayWithIntegerKeys;
$this->shapedArrayWithObject = $shapedArrayWithObject;
Expand Down
6 changes: 6 additions & 0 deletions tests/Unit/Type/Types/ShapedArrayTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public function test_accepts_correct_values(): void

public function test_does_not_accept_incorrect_values(): void
{
self::assertFalse($this->type->accepts(['foo' => 42]));
self::assertFalse($this->type->accepts(['foo' => new stdClass()]));
self::assertFalse($this->type->accepts(['bar' => 'foo']));

Expand All @@ -80,6 +81,11 @@ public function test_does_not_accept_incorrect_values(): void
self::assertFalse($this->type->accepts(new stdClass()));
}

public function test_does_not_accept_array_with_excessive_keys(): void
{
self::assertFalse($this->type->accepts(['foo' => 'foo', 'fiz' => 42]));
}

public function test_matches_valid_array_shaped_type(): void
{
$otherA = new ShapedArrayType(
Expand Down

0 comments on commit 5a578ea

Please sign in to comment.