2020-05-13 17:15:21 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Amp\Test;
|
|
|
|
|
|
|
|
use Amp\DisposedException;
|
2020-05-28 19:59:55 +02:00
|
|
|
use Amp\Internal\EmitSource;
|
2020-05-21 17:11:22 +02:00
|
|
|
use Amp\PHPUnit\AsyncTestCase;
|
2020-05-13 17:15:21 +02:00
|
|
|
use Amp\Promise;
|
|
|
|
use Amp\Success;
|
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
class EmitSourceTest extends AsyncTestCase
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-28 19:59:55 +02:00
|
|
|
/** @var EmitSource */
|
2020-05-13 17:15:21 +02:00
|
|
|
private $source;
|
|
|
|
|
|
|
|
public function setUp()
|
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
parent::setUp();
|
2020-05-28 19:59:55 +02:00
|
|
|
$this->source = new EmitSource;
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
public function testEmit()
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-28 19:59:55 +02:00
|
|
|
$value = 'Emited Value';
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
$promise = $this->source->emit($value);
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->assertSame($value, yield $stream->continue());
|
2020-05-19 00:01:14 +02:00
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
$continue = $stream->continue(); // Promise will not resolve until another value is emitted or stream completed.
|
2020-05-19 00:01:14 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->assertInstanceOf(Promise::class, $promise);
|
|
|
|
$this->assertNull(yield $promise);
|
|
|
|
|
|
|
|
$this->source->complete();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->assertNull(yield $continue);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-05-28 19:59:55 +02:00
|
|
|
* @depends testEmit
|
2020-05-13 17:15:21 +02:00
|
|
|
*/
|
2020-05-28 19:59:55 +02:00
|
|
|
public function testEmitAfterComplete()
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
|
|
|
$this->expectException(\Error::class);
|
2020-05-28 19:59:55 +02:00
|
|
|
$this->expectExceptionMessage('Streams cannot emit values after calling complete');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$this->source->complete();
|
2020-05-28 19:59:55 +02:00
|
|
|
$this->source->emit(1);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-05-28 19:59:55 +02:00
|
|
|
* @depends testEmit
|
2020-05-13 17:15:21 +02:00
|
|
|
*/
|
2020-05-28 19:59:55 +02:00
|
|
|
public function testEmitingNull()
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->expectException(\TypeError::class);
|
2020-05-28 19:59:55 +02:00
|
|
|
$this->expectExceptionMessage('Streams cannot emit NULL');
|
2020-05-21 17:11:22 +02:00
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
$this->source->emit(null);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-05-28 19:59:55 +02:00
|
|
|
* @depends testEmit
|
2020-05-13 17:15:21 +02:00
|
|
|
*/
|
2020-05-28 19:59:55 +02:00
|
|
|
public function testEmitingPromise()
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->expectException(\TypeError::class);
|
2020-05-28 19:59:55 +02:00
|
|
|
$this->expectExceptionMessage('Streams cannot emit promises');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
$this->source->emit(new Success);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testDoubleComplete()
|
|
|
|
{
|
|
|
|
$this->expectException(\Error::class);
|
|
|
|
$this->expectExceptionMessage('Stream has already been completed');
|
|
|
|
|
|
|
|
$this->source->complete();
|
|
|
|
$this->source->complete();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testDoubleFail()
|
|
|
|
{
|
|
|
|
$this->expectException(\Error::class);
|
|
|
|
$this->expectExceptionMessage('Stream has already been completed');
|
|
|
|
|
|
|
|
$this->source->fail(new \Exception);
|
|
|
|
$this->source->fail(new \Exception);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testDoubleStart()
|
|
|
|
{
|
2020-05-19 17:49:40 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$this->expectException(\Error::class);
|
|
|
|
$this->expectExceptionMessage('A stream may be started only once');
|
|
|
|
|
2020-05-19 17:49:40 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
public function testEmitAfterContinue()
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-28 19:59:55 +02:00
|
|
|
$value = 'Emited Value';
|
2020-05-21 17:11:22 +02:00
|
|
|
|
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$promise = $stream->continue();
|
|
|
|
$this->assertInstanceOf(Promise::class, $promise);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
$backPressure = $this->source->emit($value);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->assertSame($value, yield $promise);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream->continue();
|
|
|
|
|
|
|
|
$this->assertNull(yield $backPressure);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testContinueAfterComplete()
|
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->source->complete();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$promise = $stream->continue();
|
|
|
|
$this->assertInstanceOf(Promise::class, $promise);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->assertNull(yield $promise);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testContinueAfterFail()
|
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->source->fail(new \Exception('Stream failed'));
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$promise = $stream->continue();
|
|
|
|
$this->assertInstanceOf(Promise::class, $promise);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->expectException(\Exception::class);
|
|
|
|
$this->expectExceptionMessage('Stream failed');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
yield $promise;
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public function testCompleteAfterContinue()
|
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$promise = $stream->continue();
|
|
|
|
$this->assertInstanceOf(Promise::class, $promise);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->source->complete();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->assertNull(yield $promise);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testDestroyingStreamRelievesBackPressure()
|
|
|
|
{
|
2020-05-19 17:49:40 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$invoked = 0;
|
|
|
|
$onResolved = function () use (&$invoked) {
|
|
|
|
$invoked++;
|
|
|
|
};
|
|
|
|
|
|
|
|
foreach (\range(1, 5) as $value) {
|
2020-05-28 19:59:55 +02:00
|
|
|
$promise = $this->source->emit($value);
|
2020-05-13 17:15:21 +02:00
|
|
|
$promise->onResolve($onResolved);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->assertSame(0, $invoked);
|
|
|
|
|
|
|
|
unset($stream); // Should relieve all back-pressure.
|
|
|
|
|
|
|
|
$this->assertSame(5, $invoked);
|
|
|
|
|
|
|
|
$this->source->complete(); // Should not throw.
|
|
|
|
|
|
|
|
$this->expectException(\Error::class);
|
|
|
|
$this->expectExceptionMessage('Stream has already been completed');
|
|
|
|
|
|
|
|
$this->source->complete(); // Should throw.
|
|
|
|
}
|
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
public function testEmitAfterDisposal()
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
$this->expectExceptionMessage('The stream has been disposed');
|
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-28 19:59:55 +02:00
|
|
|
$promise = $this->source->emit(1);
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream->dispose();
|
|
|
|
$this->assertNull(yield $promise);
|
2020-05-28 19:59:55 +02:00
|
|
|
yield $this->source->emit(1);
|
2020-05-13 21:59:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-28 19:59:55 +02:00
|
|
|
public function testEmitAfterDestruct()
|
2020-05-13 21:59:31 +02:00
|
|
|
{
|
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
$this->expectExceptionMessage('The stream has been disposed');
|
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$stream = $this->source->stream();
|
2020-05-28 19:59:55 +02:00
|
|
|
$promise = $this->source->emit(1);
|
2020-05-21 17:11:22 +02:00
|
|
|
unset($stream);
|
|
|
|
$this->assertNull(yield $promise);
|
2020-05-28 19:59:55 +02:00
|
|
|
yield $this->source->emit(1);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
}
|