Repository: symfony/symfony
File: src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php (PHP)

Code before:
                return true;
            }
        };
        $serializer = new Serializer([new ArrayDenormalizer(), $normalizer]);
        $normalizer->setSerializer($serializer);

        $denormalizedData = $normalizer->denormalize(['value' => ['type' => 'dummy'], 'values' => [['type' => 'dummy']]], DummyGenericsValueWrapper::class);

        $this->assertInstanceOf(DummyGenericsValueWrapper::class, $denormalizedData);
        $this->assertInstanceOf(DummyGenericsValue::class, $denormalizedData->value);
        $this->assertContainsOnlyInstancesOf(DummyGenericsValue::class, $denormalizedData->values);
        $this->assertCount(1, $denormalizedData->values);
        $this->assertSame('dummy', $denormalizedData->value->type);
        $this->assertSame('dummy', $denormalizedData->values[0]->type);
    }
}

class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
{
    public function getSupportedTypes(?string $format): array
    {
        return ['*' => false];
    }

    protected function extractAttributes(object $object, ?string $format = null, array $context = []): array
    {
        return [];
    }

    protected function getAttributeValue(object $object, string $attribute, ?string $format = null, array $context = []): mixed
    {
    }

    protected function setAttributeValue(object $object, string $attribute, $value, ?string $format = null, array $context = []): void
    {
        $object->$attribute = $value;
    }

    protected function isAllowedAttribute($classOrObject, string $attribute, ?string $format = null, array $context = []): bool
    {
        return \in_array($attribute, ['foo', 'baz', 'quux', 'value'], true);
    }

    public function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, ?string $format = null): object
    {
        return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes, $format);
    }
}

class Dummy
{

Review comment (suggestion):
Because of both `['field' => ['value']]` and `['value']` are arrays this test would pass even without the change in the PR 🙂 

Code after:
            {
                return true;
            }
        };
        $serializer = new Serializer([new ArrayDenormalizer(), $normalizer]);
        $normalizer->setSerializer($serializer);

        $denormalizedData = $normalizer->denormalize(['value' => ['type' => 'dummy'], 'values' => [['type' => 'dummy']]], DummyGenericsValueWrapper::class);

        $this->assertInstanceOf(DummyGenericsValueWrapper::class, $denormalizedData);
        $this->assertInstanceOf(DummyGenericsValue::class, $denormalizedData->value);
        $this->assertContainsOnlyInstancesOf(DummyGenericsValue::class, $denormalizedData->values);
        $this->assertCount(1, $denormalizedData->values);
        $this->assertSame('dummy', $denormalizedData->value->type);
        $this->assertSame('dummy', $denormalizedData->values[0]->type);
    }

    public function testNotNormalizableValueExceptionCurrentTypeUsesAttributeValue()
    {
        $serializer = new Serializer([new ObjectNormalizer(propertyAccessor: PropertyAccess::createPropertyAccessor())]);

        $this->expectException(NotNormalizableValueException::class);
        $this->expectExceptionMessage('bool');

        try {
            $serializer->denormalize(['field' => ['value']], DummyBoolField::class);
        } catch (NotNormalizableValueException $e) {
            $this->assertSame('array', $e->getCurrentType());

            throw $e;
        }
    }

    public function testNotNormalizableValueExceptionCurrentTypeUsesSetterValueAfterCallbacks()
    {
        $serializer = new Serializer([new ObjectNormalizer(propertyAccessor: PropertyAccess::createPropertyAccessor())]);

        $this->expectException(NotNormalizableValueException::class);

        try {
            $serializer->denormalize(['field' => '123'], DummyIntField::class, null, [
                AbstractNormalizer::CALLBACKS => [
                    'field' => static fn () => null,
                ],
            ]);
        } catch (NotNormalizableValueException $e) {
            $this->assertSame('null', $e->getCurrentType());

            throw $e;
        }
    }