toMatchArray([ 'string' => ['required'], 'int' => ['required', 'numeric'], 'float' => ['required', 'numeric'], 'bool' => ['required', 'boolean'], ]); }); it('creates object with all required properties', function () { $object = PrimitiveData::fromArray([ 'string' => 'abc', 'int' => 0, 'float' => 3.14, 'bool' => true, ]); expect($object)->toBeInstanceOf(PrimitiveData::class); expect($object->string)->toBe('abc'); expect($object->int)->toBe(0); expect($object->float)->toEqualWithDelta(3.14, 0.0001); expect($object->bool)->toBeTrue(); }); }); describe('optional data', function () { it('creates optional rules', function () { $rules = RuleFactory::buildRules(RuleFactory::getParametersMeta(OptionalData::class), ''); expect($rules)->toMatchArray([ 'string' => ['sometimes'], 'int' => ['sometimes', 'numeric'], 'float' => ['sometimes', 'numeric'], 'bool' => ['sometimes', 'boolean'], ]); }); it('creates object with default values', function () { $object = OptionalData::fromArray([]); expect($object)->toBeInstanceOf(OptionalData::class); expect($object->string)->toBe('xyz'); expect($object->int)->toBe(3); expect($object->float)->toEqualWithDelta(0.777, 0.0001); expect($object->bool)->toBeFalse(); }); }); describe('nullable data', function () { it('creates nullable rules', function () { $rules = RuleFactory::buildRules(RuleFactory::getParametersMeta(OptionalNullableData::class), ''); expect($rules)->toMatchArray([ 'string' => ['required'], 'int' => ['nullable', 'numeric'], 'float' => ['sometimes', 'numeric'], 'bool' => ['sometimes', 'boolean'], ]); }); it('accepts explicit null', function () { $object = OptionalNullableData::fromArray([ 'string' => 'ijk', 'int' => null, ]); expect($object)->toBeInstanceOf(OptionalNullableData::class); expect($object->string)->toBe('ijk'); expect($object->int)->toBeNull(); }); it('accepts implicit null', function () { $object = OptionalNullableData::fromArray(['string' => 'dfg']); expect($object)->toBeInstanceOf(OptionalNullableData::class); expect($object->string)->toBe('dfg'); expect($object->int)->toBeNull(); }); }); describe('reference other DataObject', function () { it('creates recursive rules', function () { $rules = RuleFactory::buildRules( RuleFactory::getParametersMeta(RecursiveDataObject::class), '', ); expect($rules)->toMatchArray([ 'string' => ['required'], 'extra.string' => ['required'], 'extra.int' => ['required', 'numeric'], 'extra.float' => ['required', 'numeric'], 'extra.bool' => ['required', 'boolean'], ]); }); }); describe('primitive array', function () { it('creates array rules', function () { $rules = RuleFactory::buildRules(RuleFactory::getParametersMeta(ArrayDataObject::class), ''); expect($rules)->toMatchArray([ 'values' => ['required', 'array'], 'values.*' => ['required', 'numeric'], ]); }); }); describe('object array', function () { it('creates array rules', function () { $rules = RuleFactory::buildRules( RuleFactory::getParametersMeta(CollectionDataObject::class), '', ); expect($rules)->toMatchArray([ 'values' => ['required', 'array'], 'values.*' => ['required'], 'values.*.string' => ['required'], 'values.*.int' => ['nullable', 'numeric'], 'values.*.float' => ['sometimes', 'numeric'], 'values.*.bool' => ['sometimes', 'boolean'], ]); }); }); describe('can map input names', function () { it('creates rules with property names', function () { $rules = RuleFactory::buildRules(RuleFactory::getParametersMeta(FromInputObject::class), ''); expect($rules)->toMatchArray([ 'text' => ['required' ], 'standard' => ['required', 'numeric'], ]); }); it('maps input name', function () { $object = FromInputObject::fromArray([ 'other_name' => 'xyz', 'standard' => 1, ]); expect($object->text)->toBe('xyz'); expect($object->standard)->toBe(1); }); it('prioritizes the mapped input', function () { $object = FromInputObject::fromArray([ 'other_name' => 'xyz', 'text' => 'abc', 'standard' => 1, ]); expect($object->text)->toBe('xyz'); expect($object->standard)->toBe(1); }); }); describe('with mapper object', function () { it('uses mapper', function () { $object = WithMapperObject::fromArray([ 'period' => [ 'start' => '1980-01-01', 'end' => '1990-01-01', ], 'standard' => 1, ]); expect($object->period->startsAt('1980-01-01'))->toBeTrue(); expect($object->period->endsAt('1990-01-01'))->toBeTrue(); }); it('uses mapper as validator', function () { $object = WithMapperObject::fromArray([ 'period' => [ 'end' => '1990-01-01', ], 'standard' => 1, ]); })->throws(ValidationException::class); }); test('failed validation throws ValidationException', function () { $object = PrimitiveData::fromArray([ 'int' => 0, 'float' => 3.14, 'bool' => true, ]); })->throws(ValidationException::class); test('tries to resolve without mapper', function () { $object = ObjectWithoutMapper::fromArray(['date' => '1990-04-01']); expect($object->date->isSameDay('1990-04-01'))->toBeTrue(); })->group('object-without-mapper'); test('creates collection', function () { $object = CollectionDataObject::fromArray([ 'values' => [ [ 'string' => 'x', 'int' => 1, 'float' => 3.3, ], [ 'string' => 'y', 'int' => null, ], ], ]); expect($object->values->count())->toBe(2); expect($object->values[0]->string)->toBe('x'); expect($object->values[1]->int)->toBeNull(); });