2020-05-13 17:15:21 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Amp\Test;
|
|
|
|
|
|
|
|
use Amp\DisposedException;
|
2020-05-21 17:11:22 +02:00
|
|
|
use Amp\PHPUnit\AsyncTestCase;
|
2020-08-23 16:18:28 +02:00
|
|
|
use Amp\PipelineSource;
|
2021-04-04 20:10:23 +02:00
|
|
|
use Revolt\Future\Deferred;
|
|
|
|
use Revolt\Future\Future;
|
2021-03-26 22:34:32 +01:00
|
|
|
use function Revolt\EventLoop\defer;
|
|
|
|
use function Revolt\EventLoop\delay;
|
2021-04-04 20:10:23 +02:00
|
|
|
use function Revolt\Future\spawn;
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
class PipelineSourceTest extends AsyncTestCase
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-08-23 16:18:28 +02:00
|
|
|
/** @var PipelineSource */
|
2020-09-28 05:19:52 +02:00
|
|
|
private PipelineSource $source;
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function setUp(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
parent::setUp();
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->source = new PipelineSource;
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testEmit(): void
|
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
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = $this->source->emit($value);
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertSame($value, $pipeline->continue());
|
2020-05-19 00:01:14 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$continue = spawn(fn (
|
2021-03-26 22:34:32 +01:00
|
|
|
) => $pipeline->continue()); // Promise will not resolve until another value is emitted or pipeline completed.
|
2020-05-19 00:01:14 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertInstanceOf(Future::class, $future);
|
|
|
|
self::assertNull($future->join());
|
2020-05-21 17:11:22 +02:00
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertFalse($this->source->isComplete());
|
2020-07-16 20:50:38 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->source->complete();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isComplete());
|
2020-07-16 20:50:38 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertNull($continue->join());
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testFail(): void
|
2020-07-16 20:50:38 +02:00
|
|
|
{
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertFalse($this->source->isComplete());
|
2021-04-04 20:31:08 +02:00
|
|
|
$this->source->error($exception = new \Exception);
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isComplete());
|
2020-07-16 20:50:38 +02:00
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-07-16 20:50:38 +02:00
|
|
|
|
|
|
|
try {
|
2020-09-28 05:19:52 +02:00
|
|
|
$pipeline->continue();
|
2020-07-16 20:50:38 +02:00
|
|
|
} catch (\Exception $caught) {
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertSame($exception, $caught);
|
2020-07-16 20:50:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-09-28 05:19:52 +02:00
|
|
|
public function testEmitAfterComplete(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
|
|
|
$this->expectException(\Error::class);
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->expectExceptionMessage('Pipelines 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-09-28 05:19:52 +02:00
|
|
|
public function testEmittingNull(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->expectException(\TypeError::class);
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->expectExceptionMessage('Pipelines 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
|
|
|
*/
|
2021-04-04 20:10:23 +02:00
|
|
|
public function testEmittingFuture(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->expectException(\TypeError::class);
|
2021-04-04 20:10:23 +02:00
|
|
|
$this->expectExceptionMessage('Pipelines cannot emit futures');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$this->source->emit(Future::complete(null));
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testDoubleComplete(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
|
|
|
$this->expectException(\Error::class);
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->expectExceptionMessage('Pipeline has already been completed');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$this->source->complete();
|
|
|
|
$this->source->complete();
|
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testDoubleFail(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
|
|
|
$this->expectException(\Error::class);
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->expectExceptionMessage('Pipeline has already been completed');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-04-04 20:31:08 +02:00
|
|
|
$this->source->error(new \Exception);
|
|
|
|
$this->source->error(new \Exception);
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testDoubleStart(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$this->expectException(\Error::class);
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->expectExceptionMessage('A pipeline may be started only once');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testEmitAfterContinue(): void
|
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
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = spawn(fn () => $pipeline->continue());
|
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
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertSame($value, $future->join());
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = spawn(fn () => $pipeline->continue());
|
2020-05-21 17:11:22 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertNull($backPressure->join());
|
2020-09-28 05:19:52 +02:00
|
|
|
|
|
|
|
$this->source->complete();
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testContinueAfterComplete(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
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
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertNull($pipeline->continue());
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testContinueAfterFail(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-04-04 20:31:08 +02:00
|
|
|
$this->source->error(new \Exception('Pipeline failed'));
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-05-21 17:11:22 +02:00
|
|
|
$this->expectException(\Exception::class);
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->expectExceptionMessage('Pipeline failed');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
$pipeline->continue();
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testCompleteAfterContinue(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = spawn(fn () => $pipeline->continue());
|
|
|
|
self::assertInstanceOf(Future::class, $future);
|
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
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertNull($future->join());
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testDestroyingPipelineRelievesBackPressure(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$invoked = 0;
|
|
|
|
foreach (\range(1, 5) as $value) {
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = $this->source->emit($value);
|
|
|
|
defer(function () use (&$invoked, $future): void {
|
|
|
|
try {
|
|
|
|
$future->join();
|
|
|
|
} catch (DisposedException $exception) {
|
|
|
|
// Ignore disposal.
|
|
|
|
} finally {
|
|
|
|
$invoked++;
|
|
|
|
}
|
|
|
|
});
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertSame(0, $invoked);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
unset($pipeline); // Should relieve all back-pressure.
|
2020-05-13 17:15:21 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
delay(5); // Tick event loop to invoke future callbacks.
|
2020-09-28 05:19:52 +02:00
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertSame(5, $invoked);
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$this->source->complete(); // Should not throw.
|
|
|
|
|
|
|
|
$this->expectException(\Error::class);
|
2020-08-23 16:18:28 +02:00
|
|
|
$this->expectExceptionMessage('Pipeline has already been completed');
|
2020-05-13 17:15:21 +02:00
|
|
|
|
|
|
|
$this->source->complete(); // Should throw.
|
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testOnDisposal(): void
|
2020-07-30 21:33:39 +02:00
|
|
|
{
|
|
|
|
$invoked = false;
|
|
|
|
$this->source->onDisposal(function () use (&$invoked) {
|
|
|
|
$invoked = true;
|
|
|
|
});
|
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertFalse($invoked);
|
2020-07-30 21:33:39 +02:00
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
|
|
|
$pipeline->dispose();
|
2020-07-30 21:33:39 +02:00
|
|
|
|
2020-11-03 23:55:29 +01:00
|
|
|
delay(0);
|
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($invoked);
|
2020-07-30 21:33:39 +02:00
|
|
|
|
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testOnDisposalAfterCompletion(): void
|
2020-07-30 21:33:39 +02:00
|
|
|
{
|
|
|
|
$invoked = false;
|
|
|
|
$this->source->onDisposal(function () use (&$invoked) {
|
|
|
|
$invoked = true;
|
|
|
|
});
|
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertFalse($invoked);
|
2020-07-30 21:33:39 +02:00
|
|
|
|
|
|
|
$this->source->complete();
|
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
|
|
|
$pipeline->dispose();
|
2020-07-30 21:33:39 +02:00
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertFalse($invoked);
|
2020-07-30 21:33:39 +02:00
|
|
|
|
|
|
|
$this->source->onDisposal($this->createCallback(0));
|
2020-11-03 23:55:29 +01:00
|
|
|
|
|
|
|
delay(0);
|
2020-07-30 21:33:39 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testEmitAfterDisposal(): void
|
2020-05-13 17:15:21 +02:00
|
|
|
{
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2020-07-29 17:29:57 +02:00
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline->dispose();
|
2020-07-29 17:29:57 +02:00
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isDisposed());
|
2020-11-17 00:20:13 +01:00
|
|
|
|
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$this->source->emit(1)->join();
|
2020-05-13 21:59:31 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testEmitAfterAutomaticDisposal(): void
|
2020-08-27 19:45:48 +02:00
|
|
|
{
|
2020-11-17 00:20:13 +01:00
|
|
|
$pipeline = $this->source->pipe();
|
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
|
|
|
unset($pipeline); // Trigger automatic disposal.
|
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isDisposed());
|
2020-11-17 00:20:13 +01:00
|
|
|
|
2020-08-27 19:45:48 +02:00
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$this->source->emit(1)->join();
|
2020-11-17 00:20:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testEmitAfterAutomaticDisposalAfterDelay(): void
|
|
|
|
{
|
2020-08-27 19:45:48 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
|
|
|
unset($pipeline); // Trigger automatic disposal.
|
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isDisposed());
|
2020-11-17 00:20:13 +01:00
|
|
|
|
|
|
|
delay(10);
|
|
|
|
|
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$this->source->emit(1)->join();
|
2020-08-27 19:45:48 +02:00
|
|
|
}
|
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
public function testEmitAfterAutomaticDisposalWithPendingContinueFuture(): void
|
2020-08-24 23:28:08 +02:00
|
|
|
{
|
|
|
|
$pipeline = $this->source->pipe();
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = spawn(fn () => $pipeline->continue());
|
2020-08-24 23:28:08 +02:00
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2020-08-27 19:45:48 +02:00
|
|
|
unset($pipeline); // Trigger automatic disposal.
|
2020-08-24 23:28:08 +02:00
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertFalse($this->source->isDisposed());
|
2020-09-28 05:19:52 +02:00
|
|
|
$this->source->emit(1);
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertSame(1, $future->join());
|
2020-09-28 05:19:52 +02:00
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isDisposed());
|
2020-08-24 23:28:08 +02:00
|
|
|
|
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
$this->source->emit(2)->join();
|
2020-08-24 23:28:08 +02:00
|
|
|
}
|
2020-05-13 21:59:31 +02:00
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
public function testEmitAfterExplicitDisposalWithPendingContinueFuture(): void
|
2020-08-27 19:45:48 +02:00
|
|
|
{
|
|
|
|
$pipeline = $this->source->pipe();
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = spawn(fn () => $pipeline->continue());
|
2020-08-27 19:45:48 +02:00
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
|
|
|
$pipeline->dispose();
|
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isDisposed());
|
2020-08-27 19:45:48 +02:00
|
|
|
|
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertSame(1, $future->join());
|
2020-08-27 19:45:48 +02:00
|
|
|
}
|
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testEmitAfterDestruct(): void
|
2020-05-13 21:59:31 +02:00
|
|
|
{
|
|
|
|
$this->expectException(DisposedException::class);
|
|
|
|
|
2020-08-23 16:18:28 +02:00
|
|
|
$pipeline = $this->source->pipe();
|
2021-04-04 20:10:23 +02:00
|
|
|
$future = $this->source->emit(1);
|
2020-07-29 17:29:57 +02:00
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2020-08-23 16:18:28 +02:00
|
|
|
unset($pipeline);
|
2020-07-29 17:29:57 +02:00
|
|
|
$this->source->onDisposal($this->createCallback(1));
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertTrue($this->source->isDisposed());
|
2021-04-04 20:10:23 +02:00
|
|
|
self::assertNull($future->join());
|
|
|
|
$this->source->emit(1)->join();
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|
2020-07-30 21:33:39 +02:00
|
|
|
|
2020-09-28 05:19:52 +02:00
|
|
|
public function testFailWithDisposedException(): void
|
2020-07-30 21:33:39 +02:00
|
|
|
{
|
2020-11-04 00:02:56 +01:00
|
|
|
// Using DisposedException, but should be treated as fail, not disposal.
|
2021-04-04 20:31:08 +02:00
|
|
|
$this->source->error(new DisposedException);
|
2020-11-04 00:02:56 +01:00
|
|
|
|
2020-07-30 21:33:39 +02:00
|
|
|
$this->expectException(\Error::class);
|
2020-11-04 00:02:56 +01:00
|
|
|
$this->expectExceptionMessage('Pipeline has already been completed');
|
2020-07-30 21:33:39 +02:00
|
|
|
|
2020-11-04 00:02:56 +01:00
|
|
|
$this->source->complete();
|
2020-07-30 21:33:39 +02:00
|
|
|
}
|
2020-11-10 19:05:47 +01:00
|
|
|
|
|
|
|
public function testTraversable(): void
|
|
|
|
{
|
|
|
|
defer(function (): void {
|
|
|
|
try {
|
|
|
|
$this->source->yield(1);
|
|
|
|
$this->source->yield(2);
|
|
|
|
$this->source->yield(3);
|
|
|
|
$this->source->complete();
|
|
|
|
} catch (\Throwable $exception) {
|
2021-04-04 20:31:08 +02:00
|
|
|
$this->source->error($exception);
|
2020-11-10 19:05:47 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$values = [];
|
|
|
|
|
|
|
|
foreach ($this->source->pipe() as $value) {
|
|
|
|
$values[] = $value;
|
|
|
|
}
|
|
|
|
|
2021-03-26 22:34:32 +01:00
|
|
|
self::assertSame([1, 2, 3], $values);
|
2020-11-10 19:05:47 +01:00
|
|
|
}
|
2020-05-13 17:15:21 +02:00
|
|
|
}
|