This repository has been archived on 2025-01-19. You can view files and clone it, but cannot push or open issues or pull requests.
drupalcampbristol/vendor/guzzlehttp/promises/tests/EachPromiseTest.php

289 lines
9.9 KiB
PHP

<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Promise as P;
/**
* @covers GuzzleHttp\Promise\EachPromise
*/
class EachPromiseTest extends \PHPUnit_Framework_TestCase
{
public function testReturnsSameInstance()
{
$each = new EachPromise([], ['concurrency' => 100]);
$this->assertSame($each->promise(), $each->promise());
}
public function testInvokesAllPromises()
{
$promises = [new Promise(), new Promise(), new Promise()];
$called = [];
$each = new EachPromise($promises, [
'fulfilled' => function ($value) use (&$called) {
$called[] = $value;
}
]);
$p = $each->promise();
$promises[0]->resolve('a');
$promises[1]->resolve('c');
$promises[2]->resolve('b');
P\queue()->run();
$this->assertEquals(['a', 'c', 'b'], $called);
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
}
public function testIsWaitable()
{
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
$b = new Promise(function () use (&$b) { $b->resolve('b'); });
$called = [];
$each = new EachPromise([$a, $b], [
'fulfilled' => function ($value) use (&$called) { $called[] = $value; }
]);
$p = $each->promise();
$this->assertNull($p->wait());
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
$this->assertEquals(['a', 'b'], $called);
}
public function testCanResolveBeforeConsumingAll()
{
$called = 0;
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
$b = new Promise(function () { $this->fail(); });
$each = new EachPromise([$a, $b], [
'fulfilled' => function ($value, $idx, Promise $aggregate) use (&$called) {
$this->assertSame($idx, 0);
$this->assertEquals('a', $value);
$aggregate->resolve(null);
$called++;
},
'rejected' => function (\Exception $reason) {
$this->fail($reason->getMessage());
}
]);
$p = $each->promise();
$p->wait();
$this->assertNull($p->wait());
$this->assertEquals(1, $called);
$this->assertEquals(PromiseInterface::FULFILLED, $a->getState());
$this->assertEquals(PromiseInterface::PENDING, $b->getState());
// Resolving $b has no effect on the aggregate promise.
$b->resolve('foo');
$this->assertEquals(1, $called);
}
public function testLimitsPendingPromises()
{
$pending = [new Promise(), new Promise(), new Promise(), new Promise()];
$promises = new \ArrayIterator($pending);
$each = new EachPromise($promises, ['concurrency' => 2]);
$p = $each->promise();
$this->assertCount(2, $this->readAttribute($each, 'pending'));
$pending[0]->resolve('a');
$this->assertCount(2, $this->readAttribute($each, 'pending'));
$this->assertTrue($promises->valid());
$pending[1]->resolve('b');
P\queue()->run();
$this->assertCount(2, $this->readAttribute($each, 'pending'));
$this->assertTrue($promises->valid());
$promises[2]->resolve('c');
P\queue()->run();
$this->assertCount(1, $this->readAttribute($each, 'pending'));
$this->assertEquals(PromiseInterface::PENDING, $p->getState());
$promises[3]->resolve('d');
P\queue()->run();
$this->assertNull($this->readAttribute($each, 'pending'));
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
$this->assertFalse($promises->valid());
}
public function testDynamicallyLimitsPendingPromises()
{
$calls = [];
$pendingFn = function ($count) use (&$calls) {
$calls[] = $count;
return 2;
};
$pending = [new Promise(), new Promise(), new Promise(), new Promise()];
$promises = new \ArrayIterator($pending);
$each = new EachPromise($promises, ['concurrency' => $pendingFn]);
$p = $each->promise();
$this->assertCount(2, $this->readAttribute($each, 'pending'));
$pending[0]->resolve('a');
$this->assertCount(2, $this->readAttribute($each, 'pending'));
$this->assertTrue($promises->valid());
$pending[1]->resolve('b');
$this->assertCount(2, $this->readAttribute($each, 'pending'));
P\queue()->run();
$this->assertTrue($promises->valid());
$promises[2]->resolve('c');
P\queue()->run();
$this->assertCount(1, $this->readAttribute($each, 'pending'));
$this->assertEquals(PromiseInterface::PENDING, $p->getState());
$promises[3]->resolve('d');
P\queue()->run();
$this->assertNull($this->readAttribute($each, 'pending'));
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
$this->assertEquals([0, 1, 1, 1], $calls);
$this->assertFalse($promises->valid());
}
public function testClearsReferencesWhenResolved()
{
$called = false;
$a = new Promise(function () use (&$a, &$called) {
$a->resolve('a');
$called = true;
});
$each = new EachPromise([$a], [
'concurrency' => function () { return 1; },
'fulfilled' => function () {},
'rejected' => function () {}
]);
$each->promise()->wait();
$this->assertNull($this->readAttribute($each, 'onFulfilled'));
$this->assertNull($this->readAttribute($each, 'onRejected'));
$this->assertNull($this->readAttribute($each, 'iterable'));
$this->assertNull($this->readAttribute($each, 'pending'));
$this->assertNull($this->readAttribute($each, 'concurrency'));
$this->assertTrue($called);
}
public function testCanBeCancelled()
{
$this->markTestIncomplete();
}
public function testDoesNotBlowStackWithFulfilledPromises()
{
$pending = [];
for ($i = 0; $i < 100; $i++) {
$pending[] = new FulfilledPromise($i);
}
$values = [];
$each = new EachPromise($pending, [
'fulfilled' => function ($value) use (&$values) {
$values[] = $value;
}
]);
$called = false;
$each->promise()->then(function () use (&$called) {
$called = true;
});
$this->assertFalse($called);
P\queue()->run();
$this->assertTrue($called);
$this->assertEquals(range(0, 99), $values);
}
public function testDoesNotBlowStackWithRejectedPromises()
{
$pending = [];
for ($i = 0; $i < 100; $i++) {
$pending[] = new RejectedPromise($i);
}
$values = [];
$each = new EachPromise($pending, [
'rejected' => function ($value) use (&$values) {
$values[] = $value;
}
]);
$called = false;
$each->promise()->then(
function () use (&$called) { $called = true; },
function () { $this->fail('Should not have rejected.'); }
);
$this->assertFalse($called);
P\queue()->run();
$this->assertTrue($called);
$this->assertEquals(range(0, 99), $values);
}
public function testReturnsPromiseForWhatever()
{
$called = [];
$arr = ['a', 'b'];
$each = new EachPromise($arr, [
'fulfilled' => function ($v) use (&$called) { $called[] = $v; }
]);
$p = $each->promise();
$this->assertNull($p->wait());
$this->assertEquals(['a', 'b'], $called);
}
public function testRejectsAggregateWhenNextThrows()
{
$iter = function () {
yield 'a';
throw new \Exception('Failure');
};
$each = new EachPromise($iter());
$p = $each->promise();
$e = null;
$received = null;
$p->then(null, function ($reason) use (&$e) { $e = $reason; });
P\queue()->run();
$this->assertInstanceOf('Exception', $e);
$this->assertEquals('Failure', $e->getMessage());
}
public function testDoesNotCallNextOnIteratorUntilNeededWhenWaiting()
{
$results = [];
$values = [10];
$remaining = 9;
$iter = function () use (&$values) {
while ($value = array_pop($values)) {
yield $value;
}
};
$each = new EachPromise($iter(), [
'concurrency' => 1,
'fulfilled' => function ($r) use (&$results, &$values, &$remaining) {
$results[] = $r;
if ($remaining > 0) {
$values[] = $remaining--;
}
}
]);
$each->promise()->wait();
$this->assertEquals(range(10, 1), $results);
}
public function testDoesNotCallNextOnIteratorUntilNeededWhenAsync()
{
$firstPromise = new Promise();
$pending = [$firstPromise];
$values = [$firstPromise];
$results = [];
$remaining = 9;
$iter = function () use (&$values) {
while ($value = array_pop($values)) {
yield $value;
}
};
$each = new EachPromise($iter(), [
'concurrency' => 1,
'fulfilled' => function ($r) use (&$results, &$values, &$remaining, &$pending) {
$results[] = $r;
if ($remaining-- > 0) {
$pending[] = $values[] = new Promise();
}
}
]);
$i = 0;
$each->promise();
while ($promise = array_pop($pending)) {
$promise->resolve($i++);
P\queue()->run();
}
$this->assertEquals(range(0, 9), $results);
}
}