| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- <?php
- use Carbon\Carbon;
- use Carbon\CarbonImmutable;
- use Laravel\SerializableClosure\SerializableClosure;
- use Laravel\SerializableClosure\Serializers\Signed;
- use Laravel\SerializableClosure\Support\ReflectionClosure;
- use Laravel\SerializableClosure\UnsignedSerializableClosure;
- use Tests\Fixtures\Model;
- test('closure with simple const', function () {
- $c = function () {
- return ObjWithConst::FOO;
- };
- $u = s($c)();
- expect($u)->toBe('bar');
- })->with('serializers');
- test('closure use return value', function () {
- $a = 100;
- $c = function () use ($a) {
- return $a;
- };
- $u = s($c);
- expect($a)->toEqual($u());
- })->with('serializers');
- test('closure use transformation with Native', function () {
- $a = 100;
- SerializableClosure::transformUseVariablesUsing(function ($data) {
- foreach ($data as $key => $value) {
- $data[$key] = $value * 2;
- }
- return $data;
- });
- SerializableClosure::resolveUseVariablesUsing(function ($data) {
- foreach ($data as $key => $value) {
- $data[$key] = $value / 4;
- }
- return $data;
- });
- if ($this->serializer == UnsignedSerializableClosure::class) {
- $c = unserialize(serialize(SerializableClosure::unsigned(function () use ($a) {
- return $a;
- })));
- } else {
- $c = unserialize(serialize(new SerializableClosure(function () use ($a) {
- return $a;
- })));
- }
- expect($c())->toEqual(50);
- })->with('serializers')->skip((float) phpversion() < '7.4');
- test('closure use transformation with Signed', function () {
- $a = 100;
- SerializableClosure::setSecretKey('secret');
- SerializableClosure::transformUseVariablesUsing(function ($data) {
- foreach ($data as $key => $value) {
- $data[$key] = $value * 2;
- }
- return $data;
- });
- SerializableClosure::resolveUseVariablesUsing(function ($data) {
- foreach ($data as $key => $value) {
- $data[$key] = $value / 4;
- }
- return $data;
- });
- if ($this->serializer == UnsignedSerializableClosure::class) {
- $c = unserialize(serialize(SerializableClosure::unsigned(function () use ($a) {
- return $a;
- })));
- } else {
- $c = unserialize(serialize(new SerializableClosure(function () use ($a) {
- return $a;
- })));
- }
- expect($c())->toEqual(50);
- })->with('serializers')->skip((float) phpversion() < '7.4');
- test('closure use return closure', function () {
- $a = function ($p) {
- return $p + 1;
- };
- $b = function ($p) use ($a) {
- return $a($p);
- };
- $v = 1;
- $u = s($b);
- expect($u(1))->toEqual($v + 1);
- })->with('serializers');
- test('closure use return closure by ref', function () {
- $a = function ($p) {
- return $p + 1;
- };
- $b = function ($p) use (&$a) {
- return $a($p);
- };
- $v = 1;
- $u = s($b);
- expect($u(1))->toEqual($v + 1);
- })->with('serializers');
- test('closure use self', function () {
- $a = function () use (&$a) {
- return $a;
- };
- $u = s($a);
- expect($u())->toEqual($u);
- })->with('serializers');
- test('closure use self in array', function () {
- $a = [];
- $b = function () use (&$a) {
- return $a[0];
- };
- $a[] = $b;
- $u = s($b);
- expect($u())->toEqual($u);
- })->with('serializers');
- test('closure use self in object', function () {
- $a = new stdClass();
- $b = function () use (&$a) {
- return $a->me;
- };
- $a->me = $b;
- $u = s($b);
- expect($u())->toEqual($u);
- })->with('serializers');
- test('closure use self in multi array', function () {
- $a = [];
- $x = null;
- $b = function () use (&$x) {
- return $x;
- };
- $c = function ($i) use (&$a) {
- $f = $a[$i];
- return $f();
- };
- $a[] = $b;
- $a[] = $c;
- $x = $c;
- $u = s($c);
- expect($u(0))->toEqual($u);
- })->with('serializers');
- test('closure use self in instance', function () {
- $i = new ObjSelf();
- $c = function ($c) use ($i) {
- return $c === $i->o;
- };
- $i->o = $c;
- $u = s($c);
- expect($u($u))->toBeTrue();
- })->with('serializers');
- test('closure use self in instance2', function () {
- $i = new ObjSelf();
- $c = function () use (&$c, $i) {
- return $c == $i->o;
- };
- $i->o = &$c;
- $u = s($c);
- expect($u())->toBeTrue();
- })->with('serializers');
- test('closure serialization twice', function () {
- $a = function ($p) {
- return $p;
- };
- $b = function ($p) use ($a) {
- return $a($p);
- };
- $u = s(s($b));
- expect($u('ok'))->toEqual('ok');
- })->with('serializers');
- test('closure real serialization', function () {
- $f = function ($a, $b) {
- return $a + $b;
- };
- $u = s(s($f));
- expect($u(2, 3))->toEqual(5);
- })->with('serializers');
- test('closure nested', function () {
- $o = function ($a) {
- // this should never happen
- if ($a === false) {
- return false;
- }
- $n = function ($b) {
- return ! $b;
- };
- $ns = s($n);
- return $ns(false);
- };
- $os = s($o);
- expect($os(true))->toEqual(true);
- })->with('serializers');
- test('closure curly syntax', function () {
- $f = function () {
- $x = (object) ['a' => 1, 'b' => 3];
- $b = 'b';
- return $x->{'a'} + $x->{$b};
- };
- $f = s($f);
- expect($f())->toEqual(4);
- })->with('serializers');
- test('closure bind to object', function () {
- $a = new A();
- $b = function () {
- return $this->aPublic();
- };
- $b = $b->bindTo($a, __NAMESPACE__.'\\A');
- $u = s($b);
- expect($u())->toEqual('public called');
- })->with('serializers');
- test('closure bind to object scope', function () {
- $a = new A();
- $b = function () {
- return $this->aProtected();
- };
- $b = $b->bindTo($a, __NAMESPACE__.'\\A');
- $u = s($b);
- expect($u())->toEqual('protected called');
- })->with('serializers');
- test('closure bind to object static scope', function () {
- $a = new A();
- $b = function () {
- return static::aStaticProtected();
- };
- $b = $b->bindTo(null, __NAMESPACE__.'\\A');
- $u = s($b);
- expect($u())->toEqual('static protected called');
- })->with('serializers');
- test('closure static', function () {
- $f = static function () {
- };
- $rc = new ReflectionClosure($f);
- expect($rc->isStatic())->toBeTrue();
- })->with('serializers');
- test('closure static fail', function () {
- $f = static // This will not work
- function () {
- };
- $rc = new ReflectionClosure($f);
- expect($rc->isStatic())->toBeFalse();
- })->with('serializers');
- test('closure scope remains the same', function () {
- $f = function () {
- static $i = 0;
- };
- $o = s($f);
- $rf = new ReflectionClosure($f);
- $ro = new ReflectionClosure($o);
- test()->assertNotNull($rf->getClosureScopeClass());
- test()->assertNotNull($ro->getClosureScopeClass());
- expect($ro->getClosureScopeClass()->name)->toEqual($rf->getClosureScopeClass()->name);
- expect($ro->getClosureScopeClass()->name)->toEqual($rf->getClosureScopeClass()->name);
- $f = $f->bindTo(null, null);
- $o = s($f);
- $rf = new ReflectionClosure($f);
- $ro = new ReflectionClosure($o);
- expect($rf->getClosureScopeClass())->toBeNull();
- expect($ro->getClosureScopeClass())->toBeNull();
- })->with('serializers');
- test('mixed encodings', function () {
- $a = iconv('utf-8', 'utf-16', 'Düsseldorf');
- $b = mb_convert_encoding('Düsseldorf', 'ISO-8859-1', 'UTF-8');
- $closure = function () use ($a, $b) {
- return [$a, $b];
- };
- $u = s($closure);
- $r = $u();
- expect($r[0])->toEqual($a);
- expect($r[1])->toEqual($b);
- })->with('serializers');
- test('serializable closure serialization string content dont change', function () {
- $a = 100;
- SerializableClosure::setSecretKey('foo');
- $c = new SerializableClosure(function () use ($a) {
- return $a;
- });
- $actual = explode('s:32:', serialize($c))[0];
- expect($actual)->toBe(<<<OEF
- O:47:"Laravel\SerializableClosure\SerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Signed":2:{s:12:"serializable";s:264:"O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:1:{s:1:"a";i:100;}s:8:"function";s:47:"function () use (\$a) {
- return \$a;
- }";s:5:"scope";s:22:"P\Tests\SerializerTest";s:4:"this";N;s:4:"self";
- OEF
- );
- });
- test('unsigned serializable closure serialization string content dont change', function () {
- $a = 100;
- SerializableClosure::setSecretKey('foo');
- $c = SerializableClosure::unsigned(function () use ($a) {
- return $a;
- });
- $actual = explode('s:32:', serialize($c))[0];
- expect($actual)->toBe(<<<OEF
- O:55:"Laravel\SerializableClosure\UnsignedSerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:1:{s:1:"a";i:100;}s:8:"function";s:47:"function () use (\$a) {
- return \$a;
- }";s:5:"scope";s:22:"P\Tests\SerializerTest";s:4:"this";N;s:4:"self";
- OEF
- );
- });
- test('use objects with serializable closures properties', function () {
- $a = new stdClass();
- if ($this->serializer == Signed::class) {
- SerializableClosure::setSecretKey('secret');
- }
- if ($this->serializer == UnsignedSerializableClosure::class) {
- $a->b = SerializableClosure::unsigned(function () {
- return 'Hi';
- });
- } else {
- $a->b = new SerializableClosure(function () {
- return 'Hi';
- });
- }
- $closure = function () use ($a) {
- return ($a->b)();
- };
- $u = s($closure);
- $r = $u();
- expect($r)->toEqual('Hi');
- })->with('serializers');
- test('rebound closure', function () {
- $closure = Closure::bind(
- function () {
- return $this->hello();
- },
- new A3(function () {
- return 'Hi';
- }),
- A3::class
- );
- $u = s($closure);
- $r = $u();
- expect($r)->toEqual('Hi');
- })->with('serializers');
- test('from callable namespaces', function () {
- $f = Closure::fromCallable([new Model, 'make']);
- $f = s($f);
- expect($f(new Model))->toBeInstanceOf(Model::class);
- })->with('serializers');
- test('from static callable namespaces', function () {
- $f = Closure::fromCallable([new Model, 'staticMake']);
- $f = s($f);
- expect($f(new Model))->toBeInstanceOf(Model::class);
- })->with('serializers');
- test('serializes used dates', function ($_, $date) {
- $closure = function () use ($date) {
- return $date;
- };
- $u = s($closure);
- $r = $u();
- expect($r)->toEqual($date);
- })->with('serializers')->with([
- new DateTime,
- new DateTimeImmutable,
- new Carbon,
- new CarbonImmutable,
- ]);
- test('serializes with used object date properties', function ($_, $date) {
- $obj = new ObjSelf;
- $obj->o = $date;
- $closure = function () use ($obj) {
- return $obj;
- };
- $u = s($closure);
- $r = $u();
- expect($r->o)->toEqual($date);
- })->with('serializers')->with([
- new DateTime,
- new DateTimeImmutable,
- new Carbon,
- new CarbonImmutable,
- ]);
- function serializer_php_74_switch_statement_test_is_two($a)
- {
- return $a === 2;
- }
- class SerializerPhp74SwitchStatementClass
- {
- public static function isThree($a)
- {
- return $a === 3;
- }
- public function isFour($a)
- {
- return $a === 4;
- }
- }
- class SerializerPhp74Class
- {
- }
- test('instanceof', function () {
- $closure = function ($a) {
- $b = $a instanceof DateTime || $a instanceof SerializerPhp74Class || $a instanceof Model;
- return [
- $b,
- $a instanceof DateTime || $a instanceof SerializerPhp74Class || $a instanceof Model,
- (function ($a) {
- return ($a instanceof DateTime || $a instanceof SerializerPhp74Class || $a instanceof Model) === true;
- })($a),
- ];
- };
- $u = s($closure);
- expect($u(new DateTime))->toEqual([true, true, true])
- ->and($u(new SerializerPhp74Class))->toEqual([true, true, true])
- ->and($u(new Model))->toEqual([true, true, true])
- ->and($u(new stdClass))->toEqual([false, false, false]);
- })->with('serializers');
- test('switch statement', function () {
- $closure = function ($a) {
- switch (true) {
- case $a === 1:
- return 'one';
- case serializer_php_74_switch_statement_test_is_two($a):
- return 'two';
- case SerializerPhp74SwitchStatementClass::isThree($a):
- return 'three';
- case (new SerializerPhp74SwitchStatementClass)->isFour($a):
- return 'four';
- case $a instanceof SerializerPhp74SwitchStatementClass:
- return 'five';
- case $a instanceof DateTime:
- return 'six';
- case $a instanceof Model:
- return 'seven';
- default:
- return 'other';
- }
- };
- $u = s($closure);
- expect($u(1))->toEqual('one')
- ->and($u(2))->toEqual('two')
- ->and($u(3))->toEqual('three')
- ->and($u(4))->toEqual('four')
- ->and($u(new SerializerPhp74SwitchStatementClass))->toEqual('five')
- ->and($u(new DateTime))->toEqual('six')
- ->and($u(new Model()))->toEqual('seven')
- ->and($u(999))->toEqual('other');
- })->with('serializers');
- class A
- {
- protected static function aStaticProtected()
- {
- return 'static protected called';
- }
- protected function aProtected()
- {
- return 'protected called';
- }
- public function aPublic()
- {
- return 'public called';
- }
- }
- class A2
- {
- private $phrase = 'Hello, World!';
- private $closure1;
- private $closure2;
- private $closure3;
- public function __construct()
- {
- $this->closure1 = function () {
- return $this->phrase;
- };
- $this->closure2 = function () {
- return $this;
- };
- $this->closure3 = function () {
- $c = $this->closure2;
- return $this === $c();
- };
- }
- public function getPhrase()
- {
- $c = $this->closure1;
- return $c();
- }
- public function getEquality()
- {
- $c = $this->closure3;
- return $c();
- }
- }
- class A3
- {
- private $closure;
- public function __construct($closure)
- {
- $this->closure = $closure;
- }
- public function hello()
- {
- return ($this->closure)();
- }
- }
- class ObjSelf
- {
- public $o;
- }
- class ObjWithConst
- {
- const FOO = 'bar';
- }
|