mirror of
https://github.com/danog/amp.git
synced 2024-12-11 17:09:40 +01:00
143 lines
3.3 KiB
PHP
143 lines
3.3 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Amp\Test\Future;
|
||
|
|
||
|
use Amp\Deferred;
|
||
|
use Amp\Future;
|
||
|
use PHPUnit\Framework\TestCase;
|
||
|
use Revolt\EventLoop\Loop;
|
||
|
use function Amp\Future\spawn;
|
||
|
use function Revolt\EventLoop\delay;
|
||
|
|
||
|
class FutureTest extends TestCase
|
||
|
{
|
||
|
public function testIterate(): void
|
||
|
{
|
||
|
$this->expectOutputString('a=1 b=0 c=2 ');
|
||
|
|
||
|
$a = $this->delay(0.1, 'a');
|
||
|
$b = $this->delay(0.2, 'b');
|
||
|
$c = $this->delay(0.3, 'c');
|
||
|
|
||
|
foreach (Future::iterate([$b, $a, $c]) as $index => $future) {
|
||
|
print $future->join() . '=' . $index . ' ';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function testIterateGenerator(): void
|
||
|
{
|
||
|
$this->expectOutputString('a=1 ');
|
||
|
|
||
|
/**
|
||
|
* @var \Generator<int, Future<string>, void, void>
|
||
|
*/
|
||
|
$iterator = (function () {
|
||
|
yield (new Deferred)->getFuture();
|
||
|
yield $this->delay(0.1, 'a');
|
||
|
|
||
|
// Never joins
|
||
|
(new Deferred)->getFuture()->join();
|
||
|
})();
|
||
|
|
||
|
foreach (Future::iterate($iterator) as $index => $future) {
|
||
|
print $future->join() . '=' . $index . ' ';
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function testComplete(): void
|
||
|
{
|
||
|
$deferred = new Deferred;
|
||
|
$future = $deferred->getFuture();
|
||
|
|
||
|
$deferred->complete('result');
|
||
|
|
||
|
self::assertSame('result', $future->join());
|
||
|
}
|
||
|
|
||
|
public function testCompleteAsync(): void
|
||
|
{
|
||
|
$deferred = new Deferred;
|
||
|
$future = $deferred->getFuture();
|
||
|
|
||
|
Loop::delay(0.01, fn() => $deferred->complete('result'));
|
||
|
|
||
|
self::assertSame('result', $future->join());
|
||
|
}
|
||
|
|
||
|
public function testCompleteImmediate(): void
|
||
|
{
|
||
|
$future = Future::complete('result');
|
||
|
|
||
|
self::assertSame('result', $future->join());
|
||
|
}
|
||
|
|
||
|
public function testError(): void
|
||
|
{
|
||
|
$deferred = new Deferred;
|
||
|
$future = $deferred->getFuture();
|
||
|
|
||
|
$deferred->error(new \Exception('foo'));
|
||
|
|
||
|
$this->expectException(\Exception::class);
|
||
|
$this->expectExceptionMessage('foo');
|
||
|
|
||
|
$future->join();
|
||
|
}
|
||
|
|
||
|
public function testErrorAsync(): void
|
||
|
{
|
||
|
$deferred = new Deferred;
|
||
|
$future = $deferred->getFuture();
|
||
|
|
||
|
Loop::delay(0.01, fn() => $deferred->error(new \Exception('foo')));
|
||
|
|
||
|
$this->expectException(\Exception::class);
|
||
|
$this->expectExceptionMessage('foo');
|
||
|
|
||
|
$future->join();
|
||
|
}
|
||
|
|
||
|
public function testErrorImmediate(): void
|
||
|
{
|
||
|
$future = Future::error(new \Exception('foo'));
|
||
|
|
||
|
$this->expectException(\Exception::class);
|
||
|
$this->expectExceptionMessage('foo');
|
||
|
|
||
|
$future->join();
|
||
|
}
|
||
|
|
||
|
public function testCompleteWithFuture(): void
|
||
|
{
|
||
|
$deferred = new Deferred;
|
||
|
|
||
|
$this->expectException(\Error::class);
|
||
|
$this->expectExceptionMessage('Cannot complete with an instance of');
|
||
|
|
||
|
$deferred->complete(Future::complete(null));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @template T
|
||
|
*
|
||
|
* @param float $seconds
|
||
|
* @param T $value
|
||
|
*
|
||
|
* @return Future<T>
|
||
|
*/
|
||
|
private function delay(float $seconds, mixed $value): Future
|
||
|
{
|
||
|
return spawn(
|
||
|
/**
|
||
|
* @return T
|
||
|
*/
|
||
|
static function () use ($seconds, $value) {
|
||
|
delay($seconds);
|
||
|
|
||
|
return $value;
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
}
|