Skip to content

Commit

Permalink
fix: correctly handler iterable classes
Browse files Browse the repository at this point in the history
  • Loading branch information
romm committed Aug 30, 2023
1 parent 710af87 commit 2d00ffa
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 22 deletions.
9 changes: 5 additions & 4 deletions src/Normalizer/RecursiveNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use CuyZ\Valinor\Definition\FunctionsContainer;
use CuyZ\Valinor\Type\Types\NativeClassType;
use DateTimeInterface;
use Generator;
use RuntimeException;
use stdClass;
use UnitEnum;
Expand Down Expand Up @@ -38,6 +39,10 @@ public function normalize(mixed $value): mixed
return $value;
}

if (is_object($value) && ! $value instanceof Generator) {
return $this->normalize($this->normalizeObject($value));
}

if (is_iterable($value)) {
if (! is_array($value)) {
$value = iterator_to_array($value);
Expand All @@ -47,10 +52,6 @@ public function normalize(mixed $value): mixed
return array_map([$this, 'normalize'], $value);
}

if (is_object($value)) {
return $this->normalize($this->normalizeObject($value));
}

throw new RuntimeException('@todo unhandled type'); // @todo
}

Expand Down
70 changes: 52 additions & 18 deletions tests/Integration/Normalizer/NormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,24 @@
use CuyZ\Valinor\Tests\Fixture\Enum\PureEnum;
use DateTimeImmutable;
use DateTimeInterface;
use IteratorAggregate;
use PHPUnit\Framework\TestCase;
use stdClass;
use Traversable;

final class NormalizerTest extends TestCase
{
/**
* @dataProvider normalize_basic_values_yields_expected_output_data_provider
*
* @param array<int, callable> $callbacks
* @param array<int, callable> $handlers
*/
public function test_normalize_basic_values_yields_expected_output(mixed $input, mixed $expected, array $callbacks = []): void
public function test_normalize_basic_values_yields_expected_output(mixed $input, mixed $expected, array $handlers = []): void
{
$builder = new NormalizerBuilder();

foreach ($callbacks as $priority => $callback) {
$builder = $builder->addHandler($callback, $priority);
foreach ($handlers as $priority => $handler) {
$builder = $builder->addHandler($handler, $priority);
}

$result = $builder->normalizer()->normalize($input);
Expand Down Expand Up @@ -175,58 +177,90 @@ public function normalize_basic_values_yields_expected_output_data_provider(): i
],
];

yield 'class with child properties' => [
yield 'class with inherited properties' => [
'input' => new SomeChildClass(),
'output' => [
'stringFromParentClass' => 'foo',
'stringFromChildClass' => 'bar',
],
];

yield 'date with default normalizer' => [
yield 'iterable class' => [
'input' => new class () implements IteratorAggregate {
public string $foo = 'foo';
public string $bar = 'bar';

public function getIterator(): Traversable
{
yield 'baz' => 'baz';
}
},
'output' => [
'foo' => 'foo',
'bar' => 'bar',
],
];

yield 'date with default handler' => [
'input' => new DateTimeImmutable('1971-11-08'),
'expected' => '1971-11-08T00:00:00.000000+00:00',
];

yield 'date with custom normalizer' => [
yield 'date with handler' => [
'input' => new DateTimeImmutable('1971-11-08'),
'expected' => '1971-11-08',
'callbacks' => [
'handlers' => [
fn (DateTimeInterface $object) => $object->format('Y-m-d')
],
];

yield 'object with custom normalizer' => [
yield 'object with handler' => [
'input' => new BasicObject('foo'),
'expected' => 'foo!',
'callbacks' => [
'handlers' => [
fn (BasicObject $object) => $object->value . '!',
],
];

yield 'object with custom undefined object normalizer' => [
yield 'object with undefined object handler' => [
'input' => new BasicObject('foo'),
'expected' => 'foo!',
'callbacks' => [
'handlers' => [
fn (object $object) => $object->value . '!', // @phpstan-ignore-line
],
];

yield 'object with custom union object normalizer' => [
yield 'iterable class with handler' => [
'input' => new class () implements IteratorAggregate {
public string $foo = 'foo';
public string $bar = 'bar';

public function getIterator(): Traversable
{
yield 'baz' => 'baz';
}
},
'output' => 'value',
'handlers' => [
fn (object $object) => 'value',
],
];

yield 'object with union object handler' => [
'input' => new BasicObject('foo'),
'expected' => 'foo!',
'callbacks' => [
'handlers' => [
fn (stdClass|BasicObject $object) => $object->value . '!',
],
];

yield 'object with custom normalizer calling next' => [
yield 'object with handler calling next' => [
'input' => new BasicObject('foo'),
'expected' => [
'value' => 'foo',
'bar' => 'bar',
],
'callbacks' => [
'handlers' => [
function (object $object, callable $next) {
$result = $next();
$result['bar'] = 'bar';
Expand All @@ -236,10 +270,10 @@ function (object $object, callable $next) {
],
];

yield 'object with several prioritized normalizers' => [
yield 'object with several prioritized handlers' => [
'input' => new BasicObject('foo'),
'expected' => 'foo*!?',
'callbacks' => [
'handlers' => [
-20 => fn (BasicObject $object, callable $next) => $object->value,
-15 => fn (stdClass $object) => 'bar', // Should be ignored by the normalizer
-10 => fn (BasicObject $object, callable $next) => $next() . '*',
Expand Down

0 comments on commit 2d00ffa

Please sign in to comment.