| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699 |
- <?php
- use Tests\Fixtures\Model;
- use Tests\Fixtures\ModelAttribute;
- use Tests\Fixtures\RegularClass;
- test('enums', function () {
- $f = function (SerializerGlobalEnum $role) {
- return $role;
- };
- $f = s($f);
- expect($f(SerializerGlobalEnum::Guest))->toBe(
- SerializerGlobalEnum::Guest
- );
- $role = SerializerGlobalEnum::Admin;
- $f = function () use ($role) {
- return $role;
- };
- $f = s($f);
- expect($f())->toBe(SerializerGlobalEnum::Admin);
- if (! enum_exists(SerializerScopedEnum::class)) {
- enum SerializerScopedEnum {
- case Admin;
- case Guest;
- case Moderator;
- }
- }
- $f = function () {
- return SerializerScopedEnum::Admin;
- };
- $f = s($f);
- expect($f()->name)->toBe('Admin');
- $role = SerializerScopedEnum::Admin;
- $f = function () use ($role) {
- return $role;
- };
- $f = s($f);
- expect($f())->toBe(SerializerScopedEnum::Admin);
- })->with('serializers');
- test('enums properties', function () {
- $object = new ClassWithEnumProperty();
- $f = $object->getClosure();
- $f = s($f);
- expect($f())
- ->name->toBe('Admin')
- ->value->toBeNull();
- })->with('serializers');
- test('backed enums', function () {
- $f = function (SerializerGlobalBackedEnum $role) {
- return $role;
- };
- $f = s($f);
- expect($f(SerializerGlobalBackedEnum::Guest))->toBe(
- SerializerGlobalBackedEnum::Guest
- );
- $role = SerializerGlobalBackedEnum::Admin;
- $f = function () use ($role) {
- return $role;
- };
- $f = s($f);
- expect($f())->toBe(SerializerGlobalBackedEnum::Admin);
- if (! enum_exists(SerializerScopedBackedEnum::class)) {
- enum SerializerScopedBackedEnum: string {
- case Admin = 'Administrator';
- case Guest = 'Guest';
- case Moderator = 'Moderator';
- }
- }
- $f = function () {
- return SerializerScopedBackedEnum::Admin;
- };
- $f = s($f);
- expect($f())->name->toBe('Admin')
- ->value->toBe('Administrator');
- $role = SerializerScopedBackedEnum::Admin;
- $f = function () use ($role) {
- return $role;
- };
- $f = s($f);
- expect($f())->toBe(SerializerScopedBackedEnum::Admin);
- })->with('serializers');
- test('backed enums properties', function () {
- $object = new ClassWithBackedEnumProperty();
- $f = $object->getClosure();
- $f = s($f);
- expect($f())
- ->name->toBe('Admin')
- ->value->toBe('Administrator');
- })->with('serializers');
- test('array unpacking', function () {
- $f = function () {
- $array1 = ['a' => 1];
- $array2 = ['b' => 2];
- return ['a' => 0, ...$array1, ...$array2];
- };
- $f = s($f);
- expect($f())->toBe([
- 'a' => 1,
- 'b' => 2,
- ]);
- })->with('serializers');
- test('new in initializers', function () {
- $f = function () {
- return new SerializerPhp81Controller();
- };
- $f = s($f);
- expect($f()->service)->toBeInstanceOf(
- SerializerPhp81Service::class,
- );
- })->with('serializers');
- test('readonly properties', function () {
- $f = function () {
- $controller = new SerializerPhp81Controller();
- $controller->service = 'foo';
- };
- $f = s($f);
- expect($f)->toThrow(function (Error $e) {
- expect($e->getMessage())->toBe(
- 'Cannot modify readonly property SerializerPhp81Controller::$service',
- );
- });
- })->with('serializers');
- test('first-class callable with closures', function () {
- $f = function ($value) {
- return $value;
- };
- $f = s($f);
- expect($f(...)('foo'))->toBe('foo');
- $f = function ($a) {
- $f = fn ($b) => $a + $b + 1;
- return $f(...);
- };
- $f = s($f);
- expect($f(1)(2))->toBe(4);
- })->with('serializers');
- test('first-class callable with methods', function () {
- $f = (new SerializerPhp81Controller())->publicGetter(...);
- $f = s($f);
- expect($f())->toBeInstanceOf(SerializerPhp81Service::class);
- $f = (new SerializerPhp81Controller())->publicGetterResolver(...);
- $f = s($f);
- expect($f()()())->toBeInstanceOf(SerializerPhp81Service::class);
- })->with('serializers');
- test('first-class callable with static methods', function () {
- $f = SerializerPhp81Controller::publicStaticGetter(...);
- $f = s($f);
- expect($f())->toBeInstanceOf(SerializerPhp81Service::class);
- $f = SerializerPhp81Controller::publicStaticGetterResolver(...);
- $f = s($f);
- expect($f()()())->toBeInstanceOf(SerializerPhp81Service::class);
- })->with('serializers');
- test('first-class callable final method', function () {
- $f = (new SerializerPhp81Controller())->finalPublicGetterResolver(...);
- $f = s($f);
- expect($f()()())->toBeInstanceOf(SerializerPhp81Service::class);
- $f = SerializerPhp81Controller::finalPublicStaticGetterResolver(...);
- $f = s($f);
- expect($f()()())->toBeInstanceOf(SerializerPhp81Service::class);
- })->with('serializers');
- test('first-class callable self return type', function () {
- $f = (new SerializerPhp81Controller())->getSelf(...);
- $f = s($f);
- $controller = new SerializerPhp81Controller();
- expect($f($controller))->toBeInstanceOf(SerializerPhp81Controller::class);
- })->with('serializers');
- test('intersection types', function () {
- $f = function (SerializerPhp81HasName&SerializerPhp81HasId $service): SerializerPhp81HasName&SerializerPhp81HasId {
- return $service;
- };
- $f = s($f);
- expect($f(new SerializerPhp81Service))->toBeInstanceOf(
- SerializerPhp81Service::class,
- );
- })->with('serializers');
- test('never type', function () {
- $f = function (): never {
- throw new RuntimeException('Something wrong happened.');
- };
- $f = s($f);
- expect($f)->toThrow(RuntimeException::class);
- })->with('serializers');
- test('array_is_list', function () {
- $f = function () {
- return array_is_list([]);
- };
- $f = s($f);
- expect($f())->toBeTrue();
- })->with('serializers');
- test('final class constants', function () {
- $f = function () {
- return SerializerPhp81Service::X;
- };
- $f = s($f);
- expect($f())->toBe('foo');
- })->with('serializers');
- test('constructor property promotion', function () {
- $class = new PropertyPromotion('public', 'protected', 'private');
- $f1 = fn () => $class;
- $object = s($f1)();
- expect($object->public)->toBe('public');
- expect($object->getProtected())->toBe('protected');
- expect($object->getPrivate())->toBe('private');
- })->with('serializers');
- test('first-class callable namespaces', function () {
- $model = new Model();
- $f = $model->make(...);
- $f = s($f);
- expect($f(new Model))->toBeInstanceOf(Model::class);
- })->with('serializers');
- test('static first-class callable namespaces', function () {
- $model = new Model();
- $f = $model->staticMake(...);
- $f = s($f);
- expect($f(new Model))->toBeInstanceOf(Model::class);
- })->with('serializers');
- test('function attributes without arguments', function () {
- $model = new Model();
- $f = #[MyAttribute] function () {
- return true;
- };
- $f = s($f);
- $reflector = new ReflectionFunction($f);
- expect($reflector->getAttributes())->sequence(
- fn ($attribute) => $attribute
- ->getName()->toBe(MyAttribute::class)
- ->getArguments()->toBeEmpty(),
- );
- expect($f())->toBeTrue();
- })->with('serializers');
- test('function attributes with arguments', function () {
- $model = new Model();
- $f = #[MyAttribute('My " \' Argument 1', Model::class)] function () {
- return false;
- };
- $f = s($f);
- $reflector = new ReflectionFunction($f);
- expect($reflector->getAttributes())->sequence(
- fn ($attribute) => $attribute
- ->getName()->toBe(MyAttribute::class)
- ->getArguments()->toBe([
- 'My " \' Argument 1', Model::class,
- ])
- );
- expect($f())->toBeFalse();
- })->with('serializers');
- test('named arguments', function () {
- $variable = 'variableValue';
- $f = function (string $a1) use ($variable) {
- return new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(),
- a11: RegularClass::C,
- a12: RegularClass::staticMethod(),
- a13: (new RegularClass())->instanceMethod(),
- a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()],
- ),
- a11: RegularClass::C,
- a12: [new RegularClass(), RegularClass::C],
- a13: RegularClass::staticMethod(),
- a14: (new RegularClass())->instanceMethod(),
- a15: fn () => new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(),
- a11: RegularClass::C,
- a12: RegularClass::staticMethod(),
- a13: (new RegularClass())->instanceMethod(),
- a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()],
- ),
- a11: RegularClass::C,
- a12: [new RegularClass(), RegularClass::C],
- a13: RegularClass::staticMethod(),
- a14: (new RegularClass())->instanceMethod(),
- ),
- a16: fn () => fn () => new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(),
- a11: RegularClass::C,
- a12: RegularClass::staticMethod(),
- a13: (new RegularClass())->instanceMethod(),
- a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()],
- ),
- a11: RegularClass::C,
- a12: [new RegularClass(), RegularClass::C],
- a13: RegularClass::staticMethod(),
- a14: (new RegularClass())->instanceMethod(),
- ),
- a17: function () use ($variable) {
- return new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(
- a1: $a1,
- a2: 'string',
- a3: 1,
- a4: 1.1,
- a5: true,
- a6: null,
- a7: ['string'],
- a8: ['string', $a1, 1, null, true],
- a9: [[[[['string', $a1, 1, null, true]]]]],
- a10: new RegularClass(),
- a11: RegularClass::C,
- a12: RegularClass::staticMethod(),
- a13: (new RegularClass())->instanceMethod(),
- a14: [new RegularClass(), RegularClass::C, RegularClass::staticMethod(), (new RegularClass())->instanceMethod()],
- ),
- a11: RegularClass::C,
- a12: [new RegularClass(), RegularClass::C],
- a13: RegularClass::staticMethod(),
- a14: (new RegularClass())->instanceMethod(),
- );
- },
- a18: serializer_my_function(),
- a19: serializer_my_function(SerializerGlobalEnum::Guest),
- a20: serializer_my_function(enum: SerializerGlobalEnum::Guest),
- );
- };
- $f = s($f);
- $instance = $f('a1');
- $expectedArray = [
- 'a1' => 'a1',
- 'a2' => 'string',
- 'a3' => 1,
- 'a4' => 1.1,
- 'a5' => true,
- 'a6' => null,
- 'a7' => ['string'],
- 'a8' => ['string', 'a1', 1, null, true],
- 'a9' => [[[[['string', 'a1', 1, null, true]]]]],
- ];
- expect($instance)
- ->toMatchArray($expectedArray)
- ->toMatchArray([
- 'a18' => SerializerGlobalEnum::Admin,
- 'a19' => SerializerGlobalEnum::Guest,
- 'a20' => SerializerGlobalEnum::Guest,
- ])
- ->and($instance->a15->__invoke())->toMatchArray($expectedArray);
- })->with('serializers');
- test('function attributes with named arguments', function () {
- $model = new Model();
- $f = #[MyAttribute(string: 'My " \' Argument 1', model:Model::class)] function () {
- return false;
- };
- $f = s($f);
- $reflector = new ReflectionFunction($f);
- expect($reflector->getAttributes())->sequence(function ($attribute) {
- $attribute
- ->getName()->toBe(MyAttribute::class)
- ->getArguments()->toBe([
- 'string' => 'My " \' Argument 1',
- 'model' => Model::class,
- ]);
- expect($attribute->value->newInstance())
- ->string->toBe('My " \' Argument 1')
- ->model->toBe(Model::class);
- });
- expect($f())->toBeFalse();
- })->with('serializers');
- test('function attributes with first-class callable with methods', function () {
- $f = (new SerializerPhp81Controller())->publicGetter(...);
- $f = s($f);
- $reflector = new ReflectionFunction($f);
- expect($reflector->getAttributes())->sequence(
- fn ($attribute) => $attribute
- ->getName()->toBe(ModelAttribute::class)
- ->getArguments()->toBe([]),
- fn ($attribute) => $attribute
- ->getName()->toBe(MyAttribute::class)
- ->getArguments()->toBe([
- 'My " \' Argument 1', Model::class,
- ])
- );
- expect($f())->toBeInstanceOf(SerializerPhp81Service::class);
- })->with('serializers');
- interface SerializerPhp81HasId {}
- interface SerializerPhp81HasName {}
- class SerializerPhp81Service implements SerializerPhp81HasId, SerializerPhp81HasName
- {
- final public const X = 'foo';
- }
- class SerializerPhp81Controller
- {
- public function __construct(
- public readonly SerializerPhp81Service $service = new SerializerPhp81Service(),
- ) {
- // ..
- }
- #[ModelAttribute]
- #[MyAttribute('My " \' Argument 1', Model::class)]
- public function publicGetter()
- {
- return $this->privateGetter();
- }
- private function privateGetter()
- {
- return $this->service;
- }
- public static function publicStaticGetter()
- {
- return static::privateStaticGetter();
- }
- public static function privateStaticGetter()
- {
- return (new SerializerPhp81Controller())->service;
- }
- public function publicGetterResolver()
- {
- return $this->privateGetterResolver(...);
- }
- private function privateGetterResolver()
- {
- return fn () => $this->service;
- }
- public static function publicStaticGetterResolver()
- {
- return static::privateStaticGetterResolver(...);
- }
- public static function privateStaticGetterResolver()
- {
- return fn () => (new SerializerPhp81Controller())->service;
- }
- final public function finalPublicGetterResolver()
- {
- return $this->privateGetterResolver(...);
- }
- final public static function finalPublicStaticGetterResolver()
- {
- return static::privateStaticGetterResolver(...);
- }
- public function getSelf(self $instance): self
- {
- return $instance;
- }
- }
- enum SerializerGlobalEnum {
- case Admin;
- case Guest;
- case Moderator;
- }
- enum SerializerGlobalBackedEnum: string {
- case Admin = 'Administrator';
- case Guest = 'Guest';
- case Moderator = 'Moderator';
- }
- #[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION)]
- class MyAttribute
- {
- public function __construct(public $string, public $model)
- {
- // ..
- }
- }
- class ClassWithEnumProperty
- {
- public SerializerGlobalEnum $enum = SerializerGlobalEnum::Admin;
- public function getClosure()
- {
- return function () {
- return $this->enum;
- };
- }
- }
- test('named arguments with namespaced enum parameter', function () {
- $f1 = function () {
- return new RegularClass(a2: RegularClass::C);
- };
- expect(s($f1)())->toBeInstanceOf(RegularClass::class);
- })->with('serializers');
- class ClassWithBackedEnumProperty
- {
- public SerializerGlobalBackedEnum $enum = SerializerGlobalBackedEnum::Admin;
- public function getClosure()
- {
- return function () {
- return $this->enum;
- };
- }
- }
- function serializer_my_function(SerializerGlobalEnum $enum = SerializerGlobalEnum::Admin)
- {
- return $enum;
- }
|