1
0
mirror of https://github.com/danog/amp.git synced 2024-12-02 17:37:50 +01:00
amp/test/WeakClosureTest.php
2022-12-16 16:23:48 -06:00

172 lines
5.2 KiB
PHP

<?php declare(strict_types=1);
namespace Amp;
use Revolt\EventLoop;
class WeakClosureTest extends TestCase
{
public function provideObjectFactories(): iterable
{
yield 'binding' => [
fn (&$count, &$id) => new class($count, $id) {
private string $callbackId;
public function __construct(int &$count, &$id)
{
$this->callbackId = $id = EventLoop::repeat(
0.001,
weakClosure(function (string $callbackId) use (&$count): void {
TestCase::assertNotNull($this);
TestCase::assertStringContainsString('anonymous', static::class);
TestCase::assertSame($callbackId, $this->callbackId);
++$count;
})
);
}
public function __destruct()
{
EventLoop::cancel($this->callbackId);
}
},
];
yield 'static' => [
fn (&$count, &$id) => new class($count, $id) {
private string $callbackId = '';
public function __construct(int &$count, &$id)
{
$callbackIdRef = &$this->callbackId;
$this->callbackId = $id = EventLoop::repeat(0.001, weakClosure(static function (string $callbackId) use (
&$count,
&$callbackIdRef
): void {
TestCase::assertSame($callbackId, $callbackIdRef);
++$count;
}));
}
public function __destruct()
{
EventLoop::cancel($this->callbackId);
}
},
];
yield 'fromCallable' => [
fn (&$count, &$id) => new class($count, $id) {
private string $callbackId = '';
private int $count;
public function __construct(int &$count, &$id)
{
$this->count = &$count;
$this->callbackId = $id = EventLoop::repeat(
0.001,
weakClosure(\Closure::fromCallable([$this, 'callback']))
);
}
private function callback(string $callbackId): void
{
TestCase::assertNotNull($this);
TestCase::assertStringContainsString('anonymous', static::class);
TestCase::assertSame($callbackId, $this->callbackId);
++$this->count;
}
public function __destruct()
{
EventLoop::cancel($this->callbackId);
}
},
];
yield '__invoke' => [
fn (&$count, &$id) => new class($count, $id) {
private string $callbackId = '';
private int $count;
public function __construct(int &$count, &$id)
{
$this->count = &$count;
$this->callbackId = $id = EventLoop::repeat(0.001, weakClosure(\Closure::fromCallable($this)));
}
public function __invoke(string $callbackId): void
{
TestCase::assertNotNull($this);
TestCase::assertStringContainsString('anonymous', static::class);
TestCase::assertSame($callbackId, $this->callbackId);
++$this->count;
}
public function __destruct()
{
EventLoop::cancel($this->callbackId);
}
},
];
}
/**
* @dataProvider provideObjectFactories
*/
public function test(callable $factory): void
{
$count = 0;
$id = null;
$object = $factory($count, $id);
delay(0.05);
self::assertGreaterThan(1, $count);
// Ensure the callback isn't cancelled, yet
EventLoop::enable($id);
unset($object); // Should destroy object and cancel loop watcher.
// Ensure the callback is already cancelled
$this->expectException(EventLoop\InvalidCallbackError::class);
$this->expectExceptionCode(EventLoop\InvalidCallbackError::E_INVALID_IDENTIFIER);
EventLoop::enable($id);
}
public function testInheritance(): void
{
$object = new WeakClosureTestChild();
$this->assertSame(WeakClosureTestParent::class, weakClosure($object->getClosure())());
$this->assertSame(WeakClosureTestParent::class, weakClosure($object->getFirstClassClosure())());
}
}
class WeakClosureTestParent
{
private function privateScoped(): string
{
return __CLASS__;
}
public function getFirstClassClosure(): \Closure
{
return $this->privateScoped(...);
}
public function getClosure(): \Closure
{
return fn () => $this->privateScoped();
}
}
class WeakClosureTestChild extends WeakClosureTestParent
{
private function privateScoped(): string
{
return __CLASS__;
}
}