workbench, tests
This commit is contained in:
parent
d83a324eb0
commit
367858c97c
27 changed files with 568 additions and 410 deletions
|
|
@ -17,8 +17,8 @@ describe('caster priority', function () {
|
|||
});
|
||||
|
||||
it('uses CastWith attribute over global config caster', function () {
|
||||
$globalCaster = function (mixed $value): SimpleValue {
|
||||
return new SimpleValue($value['value'] * 3);
|
||||
$globalCaster = function (mixed $data): SimpleValue {
|
||||
return new SimpleValue($data * 3);
|
||||
};
|
||||
config(['dto.cast.' . SimpleValue::class => $globalCaster]);
|
||||
|
||||
|
|
@ -30,16 +30,16 @@ describe('caster priority', function () {
|
|||
});
|
||||
|
||||
it('falls back to global config caster when no CastWith attribute', function () {
|
||||
$globalCaster = function (mixed $value): SimpleValue {
|
||||
return new SimpleValue($value['value'] * 3);
|
||||
$globalCaster = function (mixed $data): SimpleValue {
|
||||
return new SimpleValue($data['value'] * 3);
|
||||
};
|
||||
config(['dto.cast.' . SimpleValue::class => $globalCaster]);
|
||||
|
||||
$object = WithGlobalCaster::fromArray([
|
||||
'value' => ['value' => 5],
|
||||
'simple' => ['value' => 5],
|
||||
]);
|
||||
|
||||
expect($object->value->value)->toBe(15); // 5 * 3
|
||||
expect($object->simple->value)->toBe(15); // 5 * 3
|
||||
});
|
||||
|
||||
it('falls back to default construction when no caster exists', function () {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ namespace Tests\Casters;
|
|||
|
||||
class SimpleValueCaster
|
||||
{
|
||||
public function cast(mixed $value): SimpleValue
|
||||
public function cast(mixed $data): SimpleValue
|
||||
{
|
||||
return new SimpleValue($value['value'] * 2);
|
||||
return new SimpleValue($data['value'] * 2);
|
||||
}
|
||||
|
||||
public static function rules(): array
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@ readonly class WithGlobalCaster
|
|||
use DataObject;
|
||||
|
||||
public function __construct(
|
||||
public SimpleValue $value,
|
||||
public SimpleValue $simple,
|
||||
) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ use Illuminate\Support\Carbon;
|
|||
|
||||
class CarbonPeriodMapper
|
||||
{
|
||||
public function cast(mixed $value): CarbonPeriodImmutable
|
||||
public function cast(mixed $data): CarbonPeriodImmutable
|
||||
{
|
||||
return new CarbonPeriodImmutable(Carbon::parse($value['start']), Carbon::parse($value['end']));
|
||||
return new CarbonPeriodImmutable(Carbon::parse($data['start']), Carbon::parse($data['end']));
|
||||
}
|
||||
|
||||
public static function rules(): array
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Flattening\Classes;
|
||||
|
||||
use Icefox\DTO\Attributes\Flat;
|
||||
use Icefox\DTO\DataObject;
|
||||
|
||||
class BasicRoot
|
||||
{
|
||||
use DataObject;
|
||||
public function __construct(public string $text, #[Flat] public RequiredLeaf $leaf) {}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Flattening\Classes;
|
||||
|
||||
use Icefox\DTO\DataObject;
|
||||
|
||||
class RequiredLeaf
|
||||
{
|
||||
use DataObject;
|
||||
|
||||
public function __construct(public int $value) {}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Flattening;
|
||||
|
||||
use Icefox\DTO\Log;
|
||||
use Icefox\DTO\Support\RuleFactory;
|
||||
use Tests\Flattening\Classes\BasicRoot;
|
||||
|
||||
describe('flattens required parameters', function () {
|
||||
it('generates correct rules', function () {
|
||||
|
||||
$rules = (new RuleFactory(new Log()))->make(BasicRoot::class);
|
||||
expect($rules)->toMatchArray([
|
||||
'text' => ['required'],
|
||||
'value' => ['required', 'numeric'],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
@ -15,7 +15,7 @@ use Tests\Rules\WithOverwriteRules;
|
|||
describe('rules array shape', function () {
|
||||
it('returns inferred rules shape from RuleFactory::infer (inferred only)', function () {
|
||||
$parameters = ReflectionHelper::getParametersMeta(WithMergedRules::class);
|
||||
$rules = RuleFactory::infer($parameters, '', '');
|
||||
$rules = RuleFactory::infer($parameters, '');
|
||||
|
||||
expect($rules)->toBe([
|
||||
'value' => ['required', 'numeric'],
|
||||
|
|
@ -24,7 +24,7 @@ describe('rules array shape', function () {
|
|||
|
||||
it('returns inferred rules shape regardless of OverwriteRules attribute', function () {
|
||||
$parameters = ReflectionHelper::getParametersMeta(WithOverwriteRules::class);
|
||||
$rules = RuleFactory::infer($parameters, '', '');
|
||||
$rules = RuleFactory::infer($parameters, '');
|
||||
|
||||
expect($rules)->toBe([
|
||||
'value' => ['required', 'numeric'],
|
||||
|
|
@ -93,30 +93,8 @@ describe('rules overwrite', function () {
|
|||
});
|
||||
|
||||
it('does not enforce inferred required rule when overwritten', function () {
|
||||
$object = WithOverwriteRules::fromArray([]);
|
||||
|
||||
expect($object)->toBeInstanceOf(WithOverwriteRules::class);
|
||||
});
|
||||
|
||||
it('does not enforce inferred numeric rule when overwritten', function () {
|
||||
$rules = WithOverwriteRules::rules();
|
||||
expect($rules)->toHaveKey('value');
|
||||
expect($rules['value'])->toBe(['numeric', 'max:20']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('empty rules overwrite', function () {
|
||||
it('allows any value when rules are empty with OverwriteRules', function () {
|
||||
$object = WithEmptyOverwriteRules::fromArray([
|
||||
'value' => 999,
|
||||
]);
|
||||
|
||||
expect($object->value)->toBe(999);
|
||||
});
|
||||
|
||||
it('allows missing value when rules are empty with OverwriteRules', function () {
|
||||
$object = WithEmptyOverwriteRules::fromArray([]);
|
||||
|
||||
expect($object)->toBeInstanceOf(WithEmptyOverwriteRules::class);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
161
tests/RulesTest.php
Normal file
161
tests/RulesTest.php
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use Icefox\DTO\Attributes\Flat;
|
||||
use Icefox\DTO\Support\RuleFactory;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
readonly class BasicPrimitives
|
||||
{
|
||||
public function __construct(
|
||||
public string $text,
|
||||
public int $number,
|
||||
public bool $flag,
|
||||
public ?array $items,
|
||||
public float $floating = 0.0,
|
||||
) {}
|
||||
}
|
||||
|
||||
test('required rules', function () {
|
||||
expect(RuleFactory::instance()->make(BasicPrimitives::class))->toBe([
|
||||
'text' => ['required'],
|
||||
'number' => ['required', 'numeric'],
|
||||
'flag' => ['required', 'boolean'],
|
||||
'items' => ['nullable', 'array'],
|
||||
'floating' => ['sometimes', 'numeric'],
|
||||
]);
|
||||
});
|
||||
|
||||
readonly class AnnotatedArray
|
||||
{
|
||||
/**
|
||||
* @param array<int,float> $items
|
||||
*/
|
||||
public function __construct(public array $items) {}
|
||||
}
|
||||
test('annotated array', function () {
|
||||
expect(RuleFactory::instance()->make(AnnotatedArray::class))->toBe([
|
||||
'items' => ['required', 'array'],
|
||||
'items.*' => ['required', 'numeric'],
|
||||
]);
|
||||
});
|
||||
|
||||
readonly class AnnotatedArrayNullableValue
|
||||
{
|
||||
/**
|
||||
* @param array<?float> $items
|
||||
*/
|
||||
public function __construct(public array $items) {}
|
||||
}
|
||||
test('annotated array with nullable items', function () {
|
||||
expect(RuleFactory::instance()->make(AnnotatedArrayNullableValue::class))->toBe([
|
||||
'items' => ['required', 'array'],
|
||||
'items.*' => ['nullable', 'numeric'],
|
||||
]);
|
||||
});
|
||||
|
||||
readonly class PlainLeaf
|
||||
{
|
||||
public function __construct(public string $name) {}
|
||||
}
|
||||
readonly class PlainRoot
|
||||
{
|
||||
public function __construct(public int $value, public PlainLeaf $leaf) {}
|
||||
}
|
||||
|
||||
test('plain nesting', function () {
|
||||
expect(RuleFactory::instance()->make(PlainRoot::class))->toBe([
|
||||
'value' => ['required', 'numeric'],
|
||||
'leaf' => ['required'],
|
||||
'leaf.name' => ['required'],
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
readonly class AnnotatedArrayItem
|
||||
{
|
||||
public function __construct(public int $value) {}
|
||||
}
|
||||
|
||||
readonly class AnnotatedArrayObject
|
||||
{
|
||||
/**
|
||||
* @param ?array<AnnotatedArrayItem> $items
|
||||
*/
|
||||
public function __construct(public ?array $items) {}
|
||||
}
|
||||
|
||||
test('annotated array with object', function () {
|
||||
expect(RuleFactory::instance()->make(AnnotatedArrayObject::class))->toBe([
|
||||
'items' => ['nullable', 'array'],
|
||||
'items.*' => ['required'],
|
||||
'items.*.value' => ['required', 'numeric'],
|
||||
]);
|
||||
});
|
||||
|
||||
readonly class FlattenedLeaf
|
||||
{
|
||||
public function __construct(public ?bool $flag) {}
|
||||
}
|
||||
|
||||
readonly class NotFlattenedLeaf
|
||||
{
|
||||
public function __construct(public string $description) {}
|
||||
}
|
||||
|
||||
readonly class FlattenedNode
|
||||
{
|
||||
public function __construct(
|
||||
public string $id,
|
||||
public NotFlattenedLeaf $leaf,
|
||||
#[Flat]
|
||||
public FlattenedLeaf $squish,
|
||||
public int $level = 1,
|
||||
) {}
|
||||
}
|
||||
|
||||
readonly class FlattenedRoot
|
||||
{
|
||||
public function __construct(
|
||||
public int $value,
|
||||
#[Flat]
|
||||
public FlattenedNode $node,
|
||||
) {}
|
||||
}
|
||||
|
||||
test('flattened basic', function () {
|
||||
expect(RuleFactory::instance()->make(FlattenedRoot::class))->toBe([
|
||||
'value' => ['required', 'numeric'],
|
||||
'id' => ['required' ],
|
||||
'leaf' => ['required'],
|
||||
'leaf.description' => ['required'],
|
||||
'flag' => ['nullable', 'boolean'],
|
||||
'level' => ['sometimes', 'numeric'],
|
||||
]);
|
||||
});
|
||||
|
||||
readonly class AnnotatedCollectionItem
|
||||
{
|
||||
public function __construct(public int $value) {}
|
||||
}
|
||||
|
||||
readonly class AnnotatedCollection
|
||||
{
|
||||
/**
|
||||
* @param Collection<AnnotatedCollectionItem> $group
|
||||
*/
|
||||
public function __construct(public Collection $group) {}
|
||||
}
|
||||
|
||||
test('annotated collection', function () {
|
||||
expect(RuleFactory::instance()->make(AnnotatedCollection::class))->toBe([
|
||||
'group' => ['required', 'array'],
|
||||
'group.*' => ['required'],
|
||||
'group.*.value' => ['required', 'numeric'],
|
||||
]);
|
||||
});
|
||||
|
|
@ -2,15 +2,11 @@
|
|||
|
||||
namespace Tests;
|
||||
|
||||
use Icefox\DTO\DataObjectServiceProvider;
|
||||
use Orchestra\Testbench\TestCase as BaseTestCase;
|
||||
use Illuminate\Contracts\Config\Repository;
|
||||
use Monolog\Formatter\JsonFormatter;
|
||||
use Orchestra\Testbench\Concerns\WithWorkbench;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
abstract class TestCase extends \Orchestra\Testbench\TestCase
|
||||
{
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
DataObjectServiceProvider::class,
|
||||
];
|
||||
}
|
||||
use WithWorkbench;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue