with cast tests
This commit is contained in:
parent
afb47c1977
commit
3a26a2e0c2
8 changed files with 154 additions and 3 deletions
|
|
@ -78,9 +78,9 @@ trait DataObject
|
||||||
foreach ($parameters as $parameter) {
|
foreach ($parameters as $parameter) {
|
||||||
$parameterName = $parameter->reflection->getName();
|
$parameterName = $parameter->reflection->getName();
|
||||||
|
|
||||||
if ($mapper = array_first($parameter->reflection->getAttributes(CastWith::class))) {
|
if ($castWith = array_first($parameter->reflection->getAttributes(CastWith::class))) {
|
||||||
$value = App::call(
|
$value = App::call(
|
||||||
[App::make($mapper->newInstance()->class), 'map'],
|
[App::make($castWith->newInstance()->class), 'cast'],
|
||||||
['value' => $validator->getValue($parameterName)],
|
['value' => $validator->getValue($parameterName)],
|
||||||
);
|
);
|
||||||
$mappedInput[$parameterName] = $value;
|
$mappedInput[$parameterName] = $value;
|
||||||
|
|
|
||||||
71
tests/Casters/CasterTest.php
Normal file
71
tests/Casters/CasterTest.php
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests;
|
||||||
|
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Tests\Casters\SimpleValue;
|
||||||
|
use Tests\Casters\SimpleValueCaster;
|
||||||
|
use Tests\Casters\WithGlobalCaster;
|
||||||
|
use Tests\Casters\WithSpecificCaster;
|
||||||
|
use Tests\Casters\WithoutCaster;
|
||||||
|
|
||||||
|
describe('caster priority', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
config(['dto.cast' => []]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses CastWith attribute over global config caster', function () {
|
||||||
|
$globalCaster = function (mixed $value): SimpleValue {
|
||||||
|
return new SimpleValue($value['value'] * 3);
|
||||||
|
};
|
||||||
|
config(['dto.cast.' . SimpleValue::class => $globalCaster]);
|
||||||
|
|
||||||
|
$object = WithSpecificCaster::fromArray([
|
||||||
|
'value' => ['value' => 5],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect($object->value->value)->toBe(10); // 5 * 2
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back to global config caster when no CastWith attribute', function () {
|
||||||
|
$globalCaster = function (mixed $value): SimpleValue {
|
||||||
|
return new SimpleValue($value['value'] * 3);
|
||||||
|
};
|
||||||
|
config(['dto.cast.' . SimpleValue::class => $globalCaster]);
|
||||||
|
|
||||||
|
$object = WithGlobalCaster::fromArray([
|
||||||
|
'value' => ['value' => 5],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect($object->value->value)->toBe(15); // 5 * 3
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back to default construction when no caster exists', function () {
|
||||||
|
$object = WithoutCaster::fromArray([
|
||||||
|
'value' => ['value' => 5],
|
||||||
|
]);
|
||||||
|
expect($object)->toBeInstanceOf(WithoutCaster::class);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('caster with rules', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
config(['dto.cast' => []]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('validates input using caster rules before casting', function () {
|
||||||
|
expect(fn() => WithSpecificCaster::fromArray([
|
||||||
|
'value' => [],
|
||||||
|
]))->toThrow(ValidationException::class);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts valid input and casts correctly', function () {
|
||||||
|
$object = WithSpecificCaster::fromArray([
|
||||||
|
'value' => ['value' => 10],
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect($object->value->value)->toBe(20); // 10 * 2
|
||||||
|
});
|
||||||
|
});
|
||||||
10
tests/Casters/SimpleValue.php
Normal file
10
tests/Casters/SimpleValue.php
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Casters;
|
||||||
|
|
||||||
|
class SimpleValue
|
||||||
|
{
|
||||||
|
public function __construct(public readonly int $value) {}
|
||||||
|
}
|
||||||
20
tests/Casters/SimpleValueCaster.php
Normal file
20
tests/Casters/SimpleValueCaster.php
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Casters;
|
||||||
|
|
||||||
|
class SimpleValueCaster
|
||||||
|
{
|
||||||
|
public function cast(mixed $value): SimpleValue
|
||||||
|
{
|
||||||
|
return new SimpleValue($value['value'] * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'value' => ['required', 'numeric'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
16
tests/Casters/WithGlobalCaster.php
Normal file
16
tests/Casters/WithGlobalCaster.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Casters;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class WithGlobalCaster
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public SimpleValue $value,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
18
tests/Casters/WithSpecificCaster.php
Normal file
18
tests/Casters/WithSpecificCaster.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Casters;
|
||||||
|
|
||||||
|
use Icefox\DTO\Attributes\CastWith;
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class WithSpecificCaster
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
#[CastWith(SimpleValueCaster::class)]
|
||||||
|
public SimpleValue $value,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
16
tests/Casters/WithoutCaster.php
Normal file
16
tests/Casters/WithoutCaster.php
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Casters;
|
||||||
|
|
||||||
|
use Icefox\DTO\DataObject;
|
||||||
|
|
||||||
|
readonly class WithoutCaster
|
||||||
|
{
|
||||||
|
use DataObject;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
public SimpleValue $value,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
class CarbonPeriodMapper
|
class CarbonPeriodMapper
|
||||||
{
|
{
|
||||||
public function map(mixed $value): CarbonPeriodImmutable
|
public function cast(mixed $value): CarbonPeriodImmutable
|
||||||
{
|
{
|
||||||
return new CarbonPeriodImmutable(Carbon::parse($value['start']), Carbon::parse($value['end']));
|
return new CarbonPeriodImmutable(Carbon::parse($value['start']), Carbon::parse($value['end']));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue