2016-12-29 21:09:49 +01:00
|
|
|
<?php
|
2016-12-13 22:25:52 +01:00
|
|
|
|
|
|
|
namespace Amp\Test;
|
|
|
|
|
|
|
|
use Amp;
|
2017-03-10 21:31:57 +01:00
|
|
|
use Amp\Producer;
|
2017-04-13 18:20:46 +02:00
|
|
|
use Amp\StreamIterator;
|
2017-03-10 21:31:57 +01:00
|
|
|
use Amp\Pause;
|
|
|
|
use Amp\Emitter;
|
|
|
|
use Amp\Loop;
|
2017-04-13 18:20:46 +02:00
|
|
|
use PHPUnit\Framework\TestCase;
|
2016-12-13 22:25:52 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
class StreamIteratorTest extends TestCase {
|
2016-12-13 22:25:52 +01:00
|
|
|
const TIMEOUT = 10;
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
public function testSingleEmittingStream() {
|
2017-03-10 21:31:57 +01:00
|
|
|
Loop::run(function () {
|
2016-12-13 22:25:52 +01:00
|
|
|
$value = 1;
|
2017-01-04 02:10:27 +01:00
|
|
|
$stream = new Producer(function (callable $emit) use ($value) {
|
2016-12-13 22:25:52 +01:00
|
|
|
yield $emit($value);
|
|
|
|
return $value;
|
|
|
|
});
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($stream);
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
while (yield $streamIterator->advance()) {
|
|
|
|
$this->assertSame($streamIterator->getCurrent(), $value);
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$this->assertSame($streamIterator->getResult(), $value);
|
2017-03-10 21:31:57 +01:00
|
|
|
});
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
/**
|
2017-01-04 02:10:27 +01:00
|
|
|
* @depends testSingleEmittingStream
|
2016-12-13 22:25:52 +01:00
|
|
|
*/
|
2017-01-04 02:10:27 +01:00
|
|
|
public function testFastEmittingStream() {
|
2017-03-10 21:31:57 +01:00
|
|
|
Loop::run(function () {
|
2016-12-13 22:25:52 +01:00
|
|
|
$count = 10;
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter = new Emitter;
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
for ($i = 0; $i < $count; ++$i) {
|
2017-01-04 02:10:27 +01:00
|
|
|
$promises[] = $emitter->emit($i);
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter->resolve($i);
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
for ($i = 0; yield $streamIterator->advance(); ++$i) {
|
|
|
|
$this->assertSame($streamIterator->getCurrent(), $i);
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
$this->assertSame($count, $i);
|
2017-04-13 18:20:46 +02:00
|
|
|
$this->assertSame($streamIterator->getResult(), $i);
|
2017-03-10 21:31:57 +01:00
|
|
|
});
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
/**
|
2017-01-04 02:10:27 +01:00
|
|
|
* @depends testSingleEmittingStream
|
2016-12-13 22:25:52 +01:00
|
|
|
*/
|
2017-01-04 02:10:27 +01:00
|
|
|
public function testSlowEmittingStream() {
|
2017-03-10 21:31:57 +01:00
|
|
|
Loop::run(function () {
|
2016-12-13 22:25:52 +01:00
|
|
|
$count = 10;
|
2017-01-04 02:10:27 +01:00
|
|
|
$stream = new Producer(function (callable $emit) use ($count) {
|
2016-12-13 22:25:52 +01:00
|
|
|
for ($i = 0; $i < $count; ++$i) {
|
|
|
|
yield new Pause(self::TIMEOUT);
|
|
|
|
yield $emit($i);
|
|
|
|
}
|
|
|
|
return $i;
|
|
|
|
});
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($stream);
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
for ($i = 0; yield $streamIterator->advance(); ++$i) {
|
|
|
|
$this->assertSame($streamIterator->getCurrent(), $i);
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
$this->assertSame($count, $i);
|
2017-04-13 18:20:46 +02:00
|
|
|
$this->assertSame($streamIterator->getResult(), $i);
|
2017-03-10 21:31:57 +01:00
|
|
|
});
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
/**
|
2017-01-04 02:10:27 +01:00
|
|
|
* @depends testFastEmittingStream
|
2016-12-13 22:25:52 +01:00
|
|
|
*/
|
|
|
|
public function testDrain() {
|
2017-03-10 21:31:57 +01:00
|
|
|
Loop::run(function () {
|
2016-12-13 22:25:52 +01:00
|
|
|
$count = 10;
|
2017-01-12 03:13:12 +01:00
|
|
|
$expected = \range(0, $count - 1);
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter = new Emitter;
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
for ($i = 0; $i < $count; ++$i) {
|
2017-01-04 02:10:27 +01:00
|
|
|
$promises[] = $emitter->emit($i);
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-12 03:13:12 +01:00
|
|
|
$value = null;
|
2017-04-13 18:20:46 +02:00
|
|
|
if (yield $streamIterator->advance()) {
|
|
|
|
$value = $streamIterator->getCurrent();
|
2017-01-12 03:13:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$this->assertSame(reset($expected), $value);
|
|
|
|
unset($expected[0]);
|
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter->resolve($i);
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$values = $streamIterator->drain();
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-12 03:13:12 +01:00
|
|
|
$this->assertSame($expected, $values);
|
2017-03-10 21:31:57 +01:00
|
|
|
});
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
/**
|
|
|
|
* @expectedException \Error
|
2017-01-04 02:10:27 +01:00
|
|
|
* @expectedExceptionMessage The stream has not resolved
|
2016-12-13 22:25:52 +01:00
|
|
|
*/
|
|
|
|
public function testDrainBeforeResolution() {
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter = new Emitter;
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator->drain();
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
public function testFailingStream() {
|
2017-03-10 21:31:57 +01:00
|
|
|
Loop::run(function () {
|
2016-12-13 22:25:52 +01:00
|
|
|
$exception = new \Exception;
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter = new Emitter;
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter->fail($exception);
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
try {
|
2017-04-13 18:20:46 +02:00
|
|
|
while (yield $streamIterator->advance());
|
|
|
|
$this->fail("StreamIterator::advance() should throw stream failure reason");
|
2016-12-13 22:25:52 +01:00
|
|
|
} catch (\Exception $reason) {
|
|
|
|
$this->assertSame($exception, $reason);
|
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
try {
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator->getResult();
|
|
|
|
$this->fail("StreamIterator::getResult() should throw stream failure reason");
|
2016-12-13 22:25:52 +01:00
|
|
|
} catch (\Exception $reason) {
|
|
|
|
$this->assertSame($exception, $reason);
|
|
|
|
}
|
2017-03-10 21:31:57 +01:00
|
|
|
});
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
/**
|
|
|
|
* @expectedException \Error
|
|
|
|
* @expectedExceptionMessage Promise returned from advance() must resolve before calling this method
|
|
|
|
*/
|
|
|
|
public function testGetCurrentBeforeAdvanceResolves() {
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator((new Emitter)->stream());
|
|
|
|
$streamIterator->advance();
|
|
|
|
$streamIterator->getCurrent();
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
/**
|
|
|
|
* @expectedException \Error
|
2017-01-04 02:10:27 +01:00
|
|
|
* @expectedExceptionMessage The stream has resolved
|
2016-12-13 22:25:52 +01:00
|
|
|
*/
|
|
|
|
public function testGetCurrentAfterResolution() {
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter = new Emitter;
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2017-01-04 02:10:27 +01:00
|
|
|
$emitter->resolve();
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator->getCurrent();
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 13:47:45 +01:00
|
|
|
|
2016-12-13 22:25:52 +01:00
|
|
|
/**
|
|
|
|
* @expectedException \Error
|
2017-01-04 02:10:27 +01:00
|
|
|
* @expectedExceptionMessage The stream has not resolved
|
2016-12-13 22:25:52 +01:00
|
|
|
*/
|
|
|
|
public function testGetResultBeforeResolution() {
|
2017-03-10 21:31:57 +01:00
|
|
|
Loop::run(Amp\wrap(function () {
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator((new Emitter)->stream());
|
|
|
|
$streamIterator->getResult();
|
2016-12-29 23:57:08 +01:00
|
|
|
}));
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|
2017-01-07 19:25:54 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @expectedException \Error
|
|
|
|
* @expectedExceptionMessage The prior promise returned must resolve before invoking this method again
|
|
|
|
*/
|
|
|
|
public function testConsecutiveAdvanceCalls() {
|
|
|
|
$emitter = new Emitter;
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
|
|
|
$streamIterator->advance();
|
|
|
|
$streamIterator->advance();
|
2017-01-07 19:25:54 +01:00
|
|
|
}
|
2017-01-08 07:22:07 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
public function testStreamIteratorDestroyedAfterEmits() {
|
2017-01-08 07:22:07 +01:00
|
|
|
$emitter = new Emitter;
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-08 07:22:07 +01:00
|
|
|
|
|
|
|
$promise = $emitter->emit(1);
|
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
unset($streamIterator);
|
2017-01-08 07:22:07 +01:00
|
|
|
|
|
|
|
$invoked = false;
|
2017-03-21 17:23:37 +01:00
|
|
|
$promise->onResolve(function () use (&$invoked) {
|
2017-01-08 07:22:07 +01:00
|
|
|
$invoked = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
$this->assertTrue($invoked);
|
|
|
|
}
|
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
public function testStreamIteratorDestroyedThenStreamEmits() {
|
2017-01-08 07:22:07 +01:00
|
|
|
$emitter = new Emitter;
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-08 07:22:07 +01:00
|
|
|
|
|
|
|
$emitter->emit(1);
|
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
unset($streamIterator);
|
2017-01-08 07:22:07 +01:00
|
|
|
|
|
|
|
$promise = $emitter->emit(2);
|
|
|
|
|
|
|
|
$invoked = false;
|
2017-03-21 17:23:37 +01:00
|
|
|
$promise->onResolve(function () use (&$invoked) {
|
2017-01-08 07:22:07 +01:00
|
|
|
$invoked = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
$this->assertTrue($invoked);
|
|
|
|
}
|
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
public function testStreamFailsWhenStreamIteratorWaiting() {
|
2017-01-08 07:22:07 +01:00
|
|
|
$exception = new \Exception;
|
|
|
|
$emitter = new Emitter;
|
2017-04-13 18:20:46 +02:00
|
|
|
$streamIterator = new StreamIterator($emitter->stream());
|
2017-01-08 07:22:07 +01:00
|
|
|
|
2017-04-13 18:20:46 +02:00
|
|
|
$promise = $streamIterator->advance();
|
2017-03-21 17:23:37 +01:00
|
|
|
$promise->onResolve(function ($exception, $value) use (&$reason) {
|
2017-01-08 07:22:07 +01:00
|
|
|
$reason = $exception;
|
|
|
|
});
|
|
|
|
|
|
|
|
$emitter->fail($exception);
|
|
|
|
|
|
|
|
$this->assertSame($exception, $reason);
|
|
|
|
}
|
2016-12-13 22:25:52 +01:00
|
|
|
}
|