toBe([ 'value' => ['required', 'numeric'], ]); }); it('returns inferred rules shape regardless of OverwriteRules attribute', function () { $parameters = ReflectionHelper::getParametersMeta(WithOverwriteRules::class); $rules = RuleFactory::infer($parameters, ''); expect($rules)->toBe([ 'value' => ['required', 'numeric'], ]); }); }); describe('getRules method', function () { it('returns merged rules from DataObject::getRules()', function () { $rules = (new RuleFactory(new Log()))->make(WithMergedRules::class); expect($rules)->toBe([ 'value' => ['required', 'numeric', 'max:20'], ]); }); it('returns only custom rules from DataObject::getRules() with OverwriteRules', function () { $rules = (new RuleFactory(new Log()))->make(WithOverwriteRules::class); expect($rules)->toBe([ 'value' => ['numeric', 'max:20'], ]); }); it('returns empty rules from DataObject::getRules() with OverwriteRules and no custom rules', function () { $rules = (new RuleFactory(new Log()))->make(WithEmptyOverwriteRules::class); expect($rules)->toBe([]); }); }); describe('rules merging', function () { it('merges custom rules with inferred rules by default', function () { $object = WithMergedRules::fromArray([ 'value' => 10, ]); expect($object->value)->toBe(10); }); it('fails validation when merged rule is violated', function () { expect(fn() => WithMergedRules::fromArray([ 'value' => 25, ]))->toThrow(ValidationException::class); }); it('fails validation when required rule is violated (inferred)', function () { expect(fn() => WithMergedRules::fromArray([ ]))->toThrow(ValidationException::class); }); }); describe('rules overwrite', function () { it('uses only custom rules when OverwriteRules attribute is present', function () { $object = WithOverwriteRules::fromArray([ 'value' => 10, ]); expect($object->value)->toBe(10); }); it('fails validation when custom rule is violated', function () { expect(fn() => WithOverwriteRules::fromArray([ 'value' => 25, ]))->toThrow(ValidationException::class); }); 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); }); });