Valinor/tests/Integration/Mapping/Attribute/ObjectBuilderStrategyMappingTest.php

131 lines
3.6 KiB
PHP
Raw Normal View History

2021-11-28 17:43:02 +01:00
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Integration\Mapping\Attribute;
use Attribute;
use CuyZ\Valinor\Attribute\StaticMethodConstructor;
use CuyZ\Valinor\Definition\ClassDefinition;
use CuyZ\Valinor\Mapper\MappingError;
use CuyZ\Valinor\Mapper\Object\Exception\TooManyObjectBuilderFactoryAttributes;
use CuyZ\Valinor\Mapper\Object\Factory\ObjectBuilderFactory;
use CuyZ\Valinor\Mapper\Object\ObjectBuilder;
use CuyZ\Valinor\MapperBuilder;
use CuyZ\Valinor\Tests\Fake\Mapper\Object\FakeObjectBuilder;
2021-11-28 17:43:02 +01:00
use CuyZ\Valinor\Tests\Integration\IntegrationTest;
use RuntimeException;
2021-11-28 17:43:02 +01:00
final class ObjectBuilderStrategyMappingTest extends IntegrationTest
{
public function test_object_builder_attribute_is_used(): void
{
try {
$result = (new MapperBuilder())->mapper()->map(ObjectWithBuilderStrategyAttribute::class, [
'foo' => 'foo',
'bar' => 'bar',
]);
2021-11-28 17:43:02 +01:00
} catch (MappingError $error) {
$this->mappingFail($error);
}
self::assertSame('foo', $result->foo);
self::assertSame('bar', $result->bar);
2021-11-28 17:43:02 +01:00
self::assertTrue($result->staticConstructorCalled);
}
public function test_named_constructor_throwing_exception_is_caught_by_mapper(): void
{
try {
(new MapperBuilder())->mapper()->map(ObjectWithFailingBuilderStrategyAttribute::class, []);
} catch (MappingError $exception) {
$error = $exception->node()->messages()[0];
self::assertSame('some exception', (string)$error);
}
}
2021-11-28 17:43:02 +01:00
public function test_repeated_object_builder_factory_attributes_throws_exception(): void
{
$factoryClass = ObjectBuilderFactory::class;
$objectClass = ObjectWithSeveralBuilderStrategyAttributes::class;
$this->expectException(TooManyObjectBuilderFactoryAttributes::class);
$this->expectExceptionCode(1634044714);
$this->expectExceptionMessage("Only one attribute of type `$factoryClass` is allowed, class `$objectClass` contains 2.");
(new MapperBuilder())->mapper()->map($objectClass, 'foo');
2021-11-28 17:43:02 +01:00
}
}
/**
* @Annotation
*/
#[Attribute(Attribute::TARGET_CLASS)]
final class ForeignAttribute
{
}
2021-11-28 17:43:02 +01:00
/**
* @Annotation
*/
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final class ObjectBuilderStrategyAttribute implements ObjectBuilderFactory
{
public function for(ClassDefinition $class, $source): ObjectBuilder
2021-11-28 17:43:02 +01:00
{
return new FakeObjectBuilder();
2021-11-28 17:43:02 +01:00
}
}
/**
* @ForeignAttribute
2021-11-28 17:43:02 +01:00
* @StaticMethodConstructor("create")
*/
#[ForeignAttribute]
2021-11-28 17:43:02 +01:00
#[StaticMethodConstructor('create')]
final class ObjectWithBuilderStrategyAttribute
{
public bool $staticConstructorCalled = false;
public string $foo;
public string $bar;
private function __construct(string $foo, string $bar)
2021-11-28 17:43:02 +01:00
{
$this->foo = $foo;
$this->bar = $bar;
2021-11-28 17:43:02 +01:00
}
public static function create(string $foo, string $bar = 'optional value'): self
2021-11-28 17:43:02 +01:00
{
$instance = new self($foo, $bar);
2021-11-28 17:43:02 +01:00
$instance->staticConstructorCalled = true;
return $instance;
}
}
/**
* @StaticMethodConstructor("failingConstructor")
*/
#[StaticMethodConstructor('failingConstructor')]
final class ObjectWithFailingBuilderStrategyAttribute
{
public static function failingConstructor(): self
{
throw new RuntimeException('some exception');
}
}
2021-11-28 17:43:02 +01:00
/**
* @ObjectBuilderStrategyAttribute
* @ObjectBuilderStrategyAttribute
*/
#[ObjectBuilderStrategyAttribute]
#[ObjectBuilderStrategyAttribute]
final class ObjectWithSeveralBuilderStrategyAttributes
{
}