Init Server Composer Components

This commit is contained in:
Eole 2016-01-21 10:29:26 +01:00
parent 35db27b0e6
commit a44cc1d2e3
177 changed files with 24745 additions and 0 deletions

View file

@ -0,0 +1,14 @@
<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise\AggregateException;
class AggregateExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testHasReason()
{
$e = new AggregateException('foo', ['baz', 'bar']);
$this->assertContains('foo', $e->getMessage());
$this->assertEquals(['baz', 'bar'], $e->getReason());
}
}

View file

@ -0,0 +1,294 @@
<?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 testFulfillsImmediatelyWhenGivenAnEmptyIterator()
{
$each = new EachPromise(new \ArrayIterator([]));
$result = $each->promise()->wait();
}
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);
}
}

View file

@ -0,0 +1,108 @@
<?php
namespace GuzzleHttp\Tests\Promise;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\FulfilledPromise;
/**
* @covers GuzzleHttp\Promise\FulfilledPromise
*/
class FulfilledPromiseTest extends \PHPUnit_Framework_TestCase
{
public function testReturnsValueWhenWaitedUpon()
{
$p = new FulfilledPromise('foo');
$this->assertEquals('fulfilled', $p->getState());
$this->assertEquals('foo', $p->wait(true));
}
public function testCannotCancel()
{
$p = new FulfilledPromise('foo');
$this->assertEquals('fulfilled', $p->getState());
$p->cancel();
$this->assertEquals('foo', $p->wait());
}
/**
* @expectedException \LogicException
* @exepctedExceptionMessage Cannot resolve a fulfilled promise
*/
public function testCannotResolve()
{
$p = new FulfilledPromise('foo');
$p->resolve('bar');
}
/**
* @expectedException \LogicException
* @exepctedExceptionMessage Cannot reject a fulfilled promise
*/
public function testCannotReject()
{
$p = new FulfilledPromise('foo');
$p->reject('bar');
}
public function testCanResolveWithSameValue()
{
$p = new FulfilledPromise('foo');
$p->resolve('foo');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testCannotResolveWithPromise()
{
new FulfilledPromise(new Promise());
}
public function testReturnsSelfWhenNoOnFulfilled()
{
$p = new FulfilledPromise('a');
$this->assertSame($p, $p->then());
}
public function testAsynchronouslyInvokesOnFulfilled()
{
$p = new FulfilledPromise('a');
$r = null;
$f = function ($d) use (&$r) { $r = $d; };
$p2 = $p->then($f);
$this->assertNotSame($p, $p2);
$this->assertNull($r);
\GuzzleHttp\Promise\queue()->run();
$this->assertEquals('a', $r);
}
public function testReturnsNewRejectedWhenOnFulfilledFails()
{
$p = new FulfilledPromise('a');
$f = function () { throw new \Exception('b'); };
$p2 = $p->then($f);
$this->assertNotSame($p, $p2);
try {
$p2->wait();
$this->fail();
} catch (\Exception $e) {
$this->assertEquals('b', $e->getMessage());
}
}
public function testOtherwiseIsSugarForRejections()
{
$c = null;
$p = new FulfilledPromise('foo');
$p->otherwise(function ($v) use (&$c) { $c = $v; });
$this->assertNull($c);
}
public function testDoesNotTryToFulfillTwiceDuringTrampoline()
{
$fp = new FulfilledPromise('a');
$t1 = $fp->then(function ($v) { return $v . ' b'; });
$t1->resolve('why!');
$this->assertEquals('why!', $t1->wait());
}
}

View file

@ -0,0 +1,50 @@
<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\PromiseInterface;
class NotPromiseInstance extends Thennable implements PromiseInterface
{
private $nextPromise = null;
public function __construct()
{
$this->nextPromise = new Promise();
}
public function then(callable $res = null, callable $rej = null)
{
return $this->nextPromise->then($res, $rej);
}
public function otherwise(callable $onRejected)
{
return $this->then($onRejected);
}
public function resolve($value)
{
$this->nextPromise->resolve($value);
}
public function reject($reason)
{
$this->nextPromise->reject($reason);
}
public function wait($unwrap = true, $defaultResolution = null)
{
}
public function cancel()
{
}
public function getState()
{
return $this->nextPromise->getState();
}
}

View file

@ -0,0 +1,579 @@
<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise\CancellationException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Promise\RejectionException;
/**
* @covers GuzzleHttp\Promise\Promise
*/
class PromiseTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \LogicException
* @expectedExceptionMessage The promise is already fulfilled
*/
public function testCannotResolveNonPendingPromise()
{
$p = new Promise();
$p->resolve('foo');
$p->resolve('bar');
$this->assertEquals('foo', $p->wait());
}
public function testCanResolveWithSameValue()
{
$p = new Promise();
$p->resolve('foo');
$p->resolve('foo');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot change a fulfilled promise to rejected
*/
public function testCannotRejectNonPendingPromise()
{
$p = new Promise();
$p->resolve('foo');
$p->reject('bar');
$this->assertEquals('foo', $p->wait());
}
public function testCanRejectWithSameValue()
{
$p = new Promise();
$p->reject('foo');
$p->reject('foo');
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot change a fulfilled promise to rejected
*/
public function testCannotRejectResolveWithSameValue()
{
$p = new Promise();
$p->resolve('foo');
$p->reject('foo');
}
public function testInvokesWaitFunction()
{
$p = new Promise(function () use (&$p) { $p->resolve('10'); });
$this->assertEquals('10', $p->wait());
}
/**
* @expectedException \GuzzleHttp\Promise\RejectionException
*/
public function testRejectsAndThrowsWhenWaitFailsToResolve()
{
$p = new Promise(function () {});
$p->wait();
}
/**
* @expectedException \GuzzleHttp\Promise\RejectionException
* @expectedExceptionMessage The promise was rejected with reason: foo
*/
public function testThrowsWhenUnwrapIsRejectedWithNonException()
{
$p = new Promise(function () use (&$p) { $p->reject('foo'); });
$p->wait();
}
/**
* @expectedException \UnexpectedValueException
* @expectedExceptionMessage foo
*/
public function testThrowsWhenUnwrapIsRejectedWithException()
{
$e = new \UnexpectedValueException('foo');
$p = new Promise(function () use (&$p, $e) { $p->reject($e); });
$p->wait();
}
public function testDoesNotUnwrapExceptionsWhenDisabled()
{
$p = new Promise(function () use (&$p) { $p->reject('foo'); });
$this->assertEquals('pending', $p->getState());
$p->wait(false);
$this->assertEquals('rejected', $p->getState());
}
public function testRejectsSelfWhenWaitThrows()
{
$e = new \UnexpectedValueException('foo');
$p = new Promise(function () use ($e) { throw $e; });
try {
$p->wait();
$this->fail();
} catch (\UnexpectedValueException $e) {
$this->assertEquals('rejected', $p->getState());
}
}
public function testWaitsOnNestedPromises()
{
$p = new Promise(function () use (&$p) { $p->resolve('_'); });
$p2 = new Promise(function () use (&$p2) { $p2->resolve('foo'); });
$p3 = $p->then(function () use ($p2) { return $p2; });
$this->assertSame('foo', $p3->wait());
}
/**
* @expectedException \GuzzleHttp\Promise\RejectionException
*/
public function testThrowsWhenWaitingOnPromiseWithNoWaitFunction()
{
$p = new Promise();
$p->wait();
}
public function testThrowsWaitExceptionAfterPromiseIsResolved()
{
$p = new Promise(function () use (&$p) {
$p->reject('Foo!');
throw new \Exception('Bar?');
});
try {
$p->wait();
$this->fail();
} catch (\Exception $e) {
$this->assertEquals('Bar?', $e->getMessage());
}
}
public function testGetsActualWaitValueFromThen()
{
$p = new Promise(function () use (&$p) { $p->reject('Foo!'); });
$p2 = $p->then(null, function ($reason) {
return new RejectedPromise([$reason]);
});
try {
$p2->wait();
$this->fail('Should have thrown');
} catch (RejectionException $e) {
$this->assertEquals(['Foo!'], $e->getReason());
}
}
public function testWaitBehaviorIsBasedOnLastPromiseInChain()
{
$p3 = new Promise(function () use (&$p3) { $p3->resolve('Whoop'); });
$p2 = new Promise(function () use (&$p2, $p3) { $p2->reject($p3); });
$p = new Promise(function () use (&$p, $p2) { $p->reject($p2); });
$this->assertEquals('Whoop', $p->wait());
}
public function testCannotCancelNonPending()
{
$p = new Promise();
$p->resolve('foo');
$p->cancel();
$this->assertEquals('fulfilled', $p->getState());
}
/**
* @expectedException \GuzzleHttp\Promise\CancellationException
*/
public function testCancelsPromiseWhenNoCancelFunction()
{
$p = new Promise();
$p->cancel();
$this->assertEquals('rejected', $p->getState());
$p->wait();
}
public function testCancelsPromiseWithCancelFunction()
{
$called = false;
$p = new Promise(null, function () use (&$called) { $called = true; });
$p->cancel();
$this->assertEquals('rejected', $p->getState());
$this->assertTrue($called);
}
public function testCancelsUppermostPendingPromise()
{
$called = false;
$p1 = new Promise(null, function () use (&$called) { $called = true; });
$p2 = $p1->then(function () {});
$p3 = $p2->then(function () {});
$p4 = $p3->then(function () {});
$p3->cancel();
$this->assertEquals('rejected', $p1->getState());
$this->assertEquals('rejected', $p2->getState());
$this->assertEquals('rejected', $p3->getState());
$this->assertEquals('pending', $p4->getState());
$this->assertTrue($called);
try {
$p3->wait();
$this->fail();
} catch (CancellationException $e) {
$this->assertContains('cancelled', $e->getMessage());
}
try {
$p4->wait();
$this->fail();
} catch (CancellationException $e) {
$this->assertContains('cancelled', $e->getMessage());
}
$this->assertEquals('rejected', $p4->getState());
}
public function testCancelsChildPromises()
{
$called1 = $called2 = $called3 = false;
$p1 = new Promise(null, function () use (&$called1) { $called1 = true; });
$p2 = new Promise(null, function () use (&$called2) { $called2 = true; });
$p3 = new Promise(null, function () use (&$called3) { $called3 = true; });
$p4 = $p2->then(function () use ($p3) { return $p3; });
$p5 = $p4->then(function () { $this->fail(); });
$p4->cancel();
$this->assertEquals('pending', $p1->getState());
$this->assertEquals('rejected', $p2->getState());
$this->assertEquals('rejected', $p4->getState());
$this->assertEquals('pending', $p5->getState());
$this->assertFalse($called1);
$this->assertTrue($called2);
$this->assertFalse($called3);
}
public function testRejectsPromiseWhenCancelFails()
{
$called = false;
$p = new Promise(null, function () use (&$called) {
$called = true;
throw new \Exception('e');
});
$p->cancel();
$this->assertEquals('rejected', $p->getState());
$this->assertTrue($called);
try {
$p->wait();
$this->fail();
} catch (\Exception $e) {
$this->assertEquals('e', $e->getMessage());
}
}
public function testCreatesPromiseWhenFulfilledAfterThen()
{
$p = new Promise();
$carry = null;
$p2 = $p->then(function ($v) use (&$carry) { $carry = $v; });
$this->assertNotSame($p, $p2);
$p->resolve('foo');
P\queue()->run();
$this->assertEquals('foo', $carry);
}
public function testCreatesPromiseWhenFulfilledBeforeThen()
{
$p = new Promise();
$p->resolve('foo');
$carry = null;
$p2 = $p->then(function ($v) use (&$carry) { $carry = $v; });
$this->assertNotSame($p, $p2);
$this->assertNull($carry);
\GuzzleHttp\Promise\queue()->run();
$this->assertEquals('foo', $carry);
}
public function testCreatesPromiseWhenFulfilledWithNoCallback()
{
$p = new Promise();
$p->resolve('foo');
$p2 = $p->then();
$this->assertNotSame($p, $p2);
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p2);
}
public function testCreatesPromiseWhenRejectedAfterThen()
{
$p = new Promise();
$carry = null;
$p2 = $p->then(null, function ($v) use (&$carry) { $carry = $v; });
$this->assertNotSame($p, $p2);
$p->reject('foo');
P\queue()->run();
$this->assertEquals('foo', $carry);
}
public function testCreatesPromiseWhenRejectedBeforeThen()
{
$p = new Promise();
$p->reject('foo');
$carry = null;
$p2 = $p->then(null, function ($v) use (&$carry) { $carry = $v; });
$this->assertNotSame($p, $p2);
$this->assertNull($carry);
P\queue()->run();
$this->assertEquals('foo', $carry);
}
public function testCreatesPromiseWhenRejectedWithNoCallback()
{
$p = new Promise();
$p->reject('foo');
$p2 = $p->then();
$this->assertNotSame($p, $p2);
$this->assertInstanceOf('GuzzleHttp\Promise\RejectedPromise', $p2);
}
public function testInvokesWaitFnsForThens()
{
$p = new Promise(function () use (&$p) { $p->resolve('a'); });
$p2 = $p
->then(function ($v) { return $v . '-1-'; })
->then(function ($v) { return $v . '2'; });
$this->assertEquals('a-1-2', $p2->wait());
}
public function testStacksThenWaitFunctions()
{
$p1 = new Promise(function () use (&$p1) { $p1->resolve('a'); });
$p2 = new Promise(function () use (&$p2) { $p2->resolve('b'); });
$p3 = new Promise(function () use (&$p3) { $p3->resolve('c'); });
$p4 = $p1
->then(function () use ($p2) { return $p2; })
->then(function () use ($p3) { return $p3; });
$this->assertEquals('c', $p4->wait());
}
public function testForwardsFulfilledDownChainBetweenGaps()
{
$p = new Promise();
$r = $r2 = null;
$p->then(null, null)
->then(function ($v) use (&$r) { $r = $v; return $v . '2'; })
->then(function ($v) use (&$r2) { $r2 = $v; });
$p->resolve('foo');
P\queue()->run();
$this->assertEquals('foo', $r);
$this->assertEquals('foo2', $r2);
}
public function testForwardsRejectedPromisesDownChainBetweenGaps()
{
$p = new Promise();
$r = $r2 = null;
$p->then(null, null)
->then(null, function ($v) use (&$r) { $r = $v; return $v . '2'; })
->then(function ($v) use (&$r2) { $r2 = $v; });
$p->reject('foo');
P\queue()->run();
$this->assertEquals('foo', $r);
$this->assertEquals('foo2', $r2);
}
public function testForwardsThrownPromisesDownChainBetweenGaps()
{
$e = new \Exception();
$p = new Promise();
$r = $r2 = null;
$p->then(null, null)
->then(null, function ($v) use (&$r, $e) {
$r = $v;
throw $e;
})
->then(
null,
function ($v) use (&$r2) { $r2 = $v; }
);
$p->reject('foo');
P\queue()->run();
$this->assertEquals('foo', $r);
$this->assertSame($e, $r2);
}
public function testForwardsReturnedRejectedPromisesDownChainBetweenGaps()
{
$p = new Promise();
$rejected = new RejectedPromise('bar');
$r = $r2 = null;
$p->then(null, null)
->then(null, function ($v) use (&$r, $rejected) {
$r = $v;
return $rejected;
})
->then(
null,
function ($v) use (&$r2) { $r2 = $v; }
);
$p->reject('foo');
P\queue()->run();
$this->assertEquals('foo', $r);
$this->assertEquals('bar', $r2);
try {
$p->wait();
} catch (RejectionException $e) {
$this->assertEquals('foo', $e->getReason());
}
}
public function testForwardsHandlersToNextPromise()
{
$p = new Promise();
$p2 = new Promise();
$resolved = null;
$p
->then(function ($v) use ($p2) { return $p2; })
->then(function ($value) use (&$resolved) { $resolved = $value; });
$p->resolve('a');
$p2->resolve('b');
P\queue()->run();
$this->assertEquals('b', $resolved);
}
public function testRemovesReferenceFromChildWhenParentWaitedUpon()
{
$r = null;
$p = new Promise(function () use (&$p) { $p->resolve('a'); });
$p2 = new Promise(function () use (&$p2) { $p2->resolve('b'); });
$pb = $p->then(
function ($v) use ($p2, &$r) {
$r = $v;
return $p2;
})
->then(function ($v) { return $v . '.'; });
$this->assertEquals('a', $p->wait());
$this->assertEquals('b', $p2->wait());
$this->assertEquals('b.', $pb->wait());
$this->assertEquals('a', $r);
}
public function testForwardsHandlersWhenFulfilledPromiseIsReturned()
{
$res = [];
$p = new Promise();
$p2 = new Promise();
$p2->resolve('foo');
$p2->then(function ($v) use (&$res) { $res[] = 'A:' . $v; });
// $res is A:foo
$p
->then(function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
$p->resolve('a');
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
P\queue()->run();
$this->assertEquals(['A:foo', 'B', 'D:a', 'C:foo'], $res);
}
public function testForwardsHandlersWhenRejectedPromiseIsReturned()
{
$res = [];
$p = new Promise();
$p2 = new Promise();
$p2->reject('foo');
$p2->then(null, function ($v) use (&$res) { $res[] = 'A:' . $v; });
$p->then(null, function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
->then(null, function ($v) use (&$res) { $res[] = 'C:' . $v; });
$p->reject('a');
$p->then(null, function ($v) use (&$res) { $res[] = 'D:' . $v; });
P\queue()->run();
$this->assertEquals(['A:foo', 'B', 'D:a', 'C:foo'], $res);
}
public function testDoesNotForwardRejectedPromise()
{
$res = [];
$p = new Promise();
$p2 = new Promise();
$p2->cancel();
$p2->then(function ($v) use (&$res) { $res[] = "B:$v"; return $v; });
$p->then(function ($v) use ($p2, &$res) { $res[] = "B:$v"; return $p2; })
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
$p->resolve('a');
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
P\queue()->run();
$this->assertEquals(['B:a', 'D:a'], $res);
}
public function testRecursivelyForwardsWhenOnlyThennable()
{
$res = [];
$p = new Promise();
$p2 = new Thennable();
$p2->resolve('foo');
$p2->then(function ($v) use (&$res) { $res[] = 'A:' . $v; });
$p->then(function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
$p->resolve('a');
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
P\queue()->run();
$this->assertEquals(['A:foo', 'B', 'D:a', 'C:foo'], $res);
}
public function testRecursivelyForwardsWhenNotInstanceOfPromise()
{
$res = [];
$p = new Promise();
$p2 = new NotPromiseInstance();
$p2->then(function ($v) use (&$res) { $res[] = 'A:' . $v; });
$p->then(function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
$p->resolve('a');
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
P\queue()->run();
$this->assertEquals(['B', 'D:a'], $res);
$p2->resolve('foo');
P\queue()->run();
$this->assertEquals(['B', 'D:a', 'A:foo', 'C:foo'], $res);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot fulfill or reject a promise with itself
*/
public function testCannotResolveWithSelf()
{
$p = new Promise();
$p->resolve($p);
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage Cannot fulfill or reject a promise with itself
*/
public function testCannotRejectWithSelf()
{
$p = new Promise();
$p->reject($p);
}
public function testDoesNotBlowStackWhenWaitingOnNestedThens()
{
$inner = new Promise(function () use (&$inner) { $inner->resolve(0); });
$prev = $inner;
for ($i = 1; $i < 100; $i++) {
$prev = $prev->then(function ($i) { return $i + 1; });
}
$parent = new Promise(function () use (&$parent, $prev) {
$parent->resolve($prev);
});
$this->assertEquals(99, $parent->wait());
}
public function testOtherwiseIsSugarForRejections()
{
$p = new Promise();
$p->reject('foo');
$p->otherwise(function ($v) use (&$c) { $c = $v; });
P\queue()->run();
$this->assertEquals($c, 'foo');
}
}

View file

@ -0,0 +1,143 @@
<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\RejectedPromise;
/**
* @covers GuzzleHttp\Promise\RejectedPromise
*/
class RejectedPromiseTest extends \PHPUnit_Framework_TestCase
{
public function testThrowsReasonWhenWaitedUpon()
{
$p = new RejectedPromise('foo');
$this->assertEquals('rejected', $p->getState());
try {
$p->wait(true);
$this->fail();
} catch (\Exception $e) {
$this->assertEquals('rejected', $p->getState());
$this->assertContains('foo', $e->getMessage());
}
}
public function testCannotCancel()
{
$p = new RejectedPromise('foo');
$p->cancel();
$this->assertEquals('rejected', $p->getState());
}
/**
* @expectedException \LogicException
* @exepctedExceptionMessage Cannot resolve a rejected promise
*/
public function testCannotResolve()
{
$p = new RejectedPromise('foo');
$p->resolve('bar');
}
/**
* @expectedException \LogicException
* @exepctedExceptionMessage Cannot reject a rejected promise
*/
public function testCannotReject()
{
$p = new RejectedPromise('foo');
$p->reject('bar');
}
public function testCanRejectWithSameValue()
{
$p = new RejectedPromise('foo');
$p->reject('foo');
}
public function testThrowsSpecificException()
{
$e = new \Exception();
$p = new RejectedPromise($e);
try {
$p->wait(true);
$this->fail();
} catch (\Exception $e2) {
$this->assertSame($e, $e2);
}
}
/**
* @expectedException \InvalidArgumentException
*/
public function testCannotResolveWithPromise()
{
new RejectedPromise(new Promise());
}
public function testReturnsSelfWhenNoOnReject()
{
$p = new RejectedPromise('a');
$this->assertSame($p, $p->then());
}
public function testInvokesOnRejectedAsynchronously()
{
$p = new RejectedPromise('a');
$r = null;
$f = function ($reason) use (&$r) { $r = $reason; };
$p->then(null, $f);
$this->assertNull($r);
\GuzzleHttp\Promise\queue()->run();
$this->assertEquals('a', $r);
}
public function testReturnsNewRejectedWhenOnRejectedFails()
{
$p = new RejectedPromise('a');
$f = function () { throw new \Exception('b'); };
$p2 = $p->then(null, $f);
$this->assertNotSame($p, $p2);
try {
$p2->wait();
$this->fail();
} catch (\Exception $e) {
$this->assertEquals('b', $e->getMessage());
}
}
public function testWaitingIsNoOp()
{
$p = new RejectedPromise('a');
$p->wait(false);
}
public function testOtherwiseIsSugarForRejections()
{
$p = new RejectedPromise('foo');
$p->otherwise(function ($v) use (&$c) { $c = $v; });
\GuzzleHttp\Promise\queue()->run();
$this->assertSame('foo', $c);
}
public function testCanResolveThenWithSuccess()
{
$actual = null;
$p = new RejectedPromise('foo');
$p->otherwise(function ($v) {
return $v . ' bar';
})->then(function ($v) use (&$actual) {
$actual = $v;
});
\GuzzleHttp\Promise\queue()->run();
$this->assertEquals('foo bar', $actual);
}
public function testDoesNotTryToRejectTwiceDuringTrampoline()
{
$fp = new RejectedPromise('a');
$t1 = $fp->then(null, function ($v) { return $v . ' b'; });
$t1->resolve('why!');
$this->assertEquals('why!', $t1->wait());
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise\RejectionException;
class Thing1
{
public function __construct($message)
{
$this->message = $message;
}
public function __toString()
{
return $this->message;
}
}
class Thing2 implements \JsonSerializable
{
public function jsonSerialize()
{
return '{}';
}
}
/**
* @covers GuzzleHttp\Promise\RejectionException
*/
class RejectionExceptionTest extends \PHPUnit_Framework_TestCase
{
public function testCanGetReasonFromException()
{
$thing = new Thing1('foo');
$e = new RejectionException($thing);
$this->assertSame($thing, $e->getReason());
$this->assertEquals('The promise was rejected with reason: foo', $e->getMessage());
}
public function testCanGetReasonMessageFromJson()
{
$reason = new Thing2();
$e = new RejectionException($reason);
$this->assertContains("{}", $e->getMessage());
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace GuzzleHttp\Promise\Test;
use GuzzleHttp\Promise\TaskQueue;
class TaskQueueTest extends \PHPUnit_Framework_TestCase
{
public function testKnowsIfEmpty()
{
$tq = new TaskQueue(false);
$this->assertTrue($tq->isEmpty());
}
public function testKnowsIfFull()
{
$tq = new TaskQueue(false);
$tq->add(function () {});
$this->assertFalse($tq->isEmpty());
}
public function testExecutesTasksInOrder()
{
$tq = new TaskQueue(false);
$called = [];
$tq->add(function () use (&$called) { $called[] = 'a'; });
$tq->add(function () use (&$called) { $called[] = 'b'; });
$tq->add(function () use (&$called) { $called[] = 'c'; });
$tq->run();
$this->assertEquals(['a', 'b', 'c'], $called);
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise\Promise;
class Thennable
{
private $nextPromise = null;
public function __construct()
{
$this->nextPromise = new Promise();
}
public function then(callable $res = null, callable $rej = null)
{
return $this->nextPromise->then($res, $rej);
}
public function resolve($value)
{
$this->nextPromise->resolve($value);
}
}

View file

@ -0,0 +1,4 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/Thennable.php';
require __DIR__ . '/NotPromiseInstance.php';

View file

@ -0,0 +1,694 @@
<?php
namespace GuzzleHttp\Promise\Tests;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\RejectedPromise;
class FunctionsTest extends \PHPUnit_Framework_TestCase
{
public function testCreatesPromiseForValue()
{
$p = \GuzzleHttp\Promise\promise_for('foo');
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
}
public function testReturnsPromiseForPromise()
{
$p = new Promise();
$this->assertSame($p, \GuzzleHttp\Promise\promise_for($p));
}
public function testReturnsPromiseForThennable()
{
$p = new Thennable();
$wrapped = \GuzzleHttp\Promise\promise_for($p);
$this->assertNotSame($p, $wrapped);
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $wrapped);
$p->resolve('foo');
P\queue()->run();
$this->assertEquals('foo', $wrapped->wait());
}
public function testReturnsRejection()
{
$p = \GuzzleHttp\Promise\rejection_for('fail');
$this->assertInstanceOf('GuzzleHttp\Promise\RejectedPromise', $p);
$this->assertEquals('fail', $this->readAttribute($p, 'reason'));
}
public function testReturnsPromisesAsIsInRejectionFor()
{
$a = new Promise();
$b = \GuzzleHttp\Promise\rejection_for($a);
$this->assertSame($a, $b);
}
public function testWaitsOnAllPromisesIntoArray()
{
$e = new \Exception();
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
$b = new Promise(function () use (&$b) { $b->reject('b'); });
$c = new Promise(function () use (&$c, $e) { $c->reject($e); });
$results = \GuzzleHttp\Promise\inspect_all([$a, $b, $c]);
$this->assertEquals([
['state' => 'fulfilled', 'value' => 'a'],
['state' => 'rejected', 'reason' => 'b'],
['state' => 'rejected', 'reason' => $e]
], $results);
}
/**
* @expectedException \GuzzleHttp\Promise\RejectionException
*/
public function testUnwrapsPromisesWithNoDefaultAndFailure()
{
$promises = [new FulfilledPromise('a'), new Promise()];
\GuzzleHttp\Promise\unwrap($promises);
}
public function testUnwrapsPromisesWithNoDefault()
{
$promises = [new FulfilledPromise('a')];
$this->assertEquals(['a'], \GuzzleHttp\Promise\unwrap($promises));
}
public function testUnwrapsPromisesWithKeys()
{
$promises = [
'foo' => new FulfilledPromise('a'),
'bar' => new FulfilledPromise('b'),
];
$this->assertEquals([
'foo' => 'a',
'bar' => 'b'
], \GuzzleHttp\Promise\unwrap($promises));
}
public function testAllAggregatesSortedArray()
{
$a = new Promise();
$b = new Promise();
$c = new Promise();
$d = \GuzzleHttp\Promise\all([$a, $b, $c]);
$b->resolve('b');
$a->resolve('a');
$c->resolve('c');
$d->then(
function ($value) use (&$result) { $result = $value; },
function ($reason) use (&$result) { $result = $reason; }
);
P\queue()->run();
$this->assertEquals(['a', 'b', 'c'], $result);
}
public function testAllThrowsWhenAnyRejected()
{
$a = new Promise();
$b = new Promise();
$c = new Promise();
$d = \GuzzleHttp\Promise\all([$a, $b, $c]);
$b->resolve('b');
$a->reject('fail');
$c->resolve('c');
$d->then(
function ($value) use (&$result) { $result = $value; },
function ($reason) use (&$result) { $result = $reason; }
);
P\queue()->run();
$this->assertEquals('fail', $result);
}
public function testSomeAggregatesSortedArrayWithMax()
{
$a = new Promise();
$b = new Promise();
$c = new Promise();
$d = \GuzzleHttp\Promise\some(2, [$a, $b, $c]);
$b->resolve('b');
$c->resolve('c');
$a->resolve('a');
$d->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals(['b', 'c'], $result);
}
public function testSomeRejectsWhenTooManyRejections()
{
$a = new Promise();
$b = new Promise();
$d = \GuzzleHttp\Promise\some(2, [$a, $b]);
$a->reject('bad');
$b->resolve('good');
P\queue()->run();
$this->assertEquals($a::REJECTED, $d->getState());
$d->then(null, function ($reason) use (&$called) {
$called = $reason;
});
P\queue()->run();
$this->assertInstanceOf('GuzzleHttp\Promise\AggregateException', $called);
$this->assertContains('bad', $called->getReason());
}
public function testCanWaitUntilSomeCountIsSatisfied()
{
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
$b = new Promise(function () use (&$b) { $b->resolve('b'); });
$c = new Promise(function () use (&$c) { $c->resolve('c'); });
$d = \GuzzleHttp\Promise\some(2, [$a, $b, $c]);
$this->assertEquals(['a', 'b'], $d->wait());
}
/**
* @expectedException \GuzzleHttp\Promise\AggregateException
* @expectedExceptionMessage Not enough promises to fulfill count
*/
public function testThrowsIfImpossibleToWaitForSomeCount()
{
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
$d = \GuzzleHttp\Promise\some(2, [$a]);
$d->wait();
}
/**
* @expectedException \GuzzleHttp\Promise\AggregateException
* @expectedExceptionMessage Not enough promises to fulfill count
*/
public function testThrowsIfResolvedWithoutCountTotalResults()
{
$a = new Promise();
$b = new Promise();
$d = \GuzzleHttp\Promise\some(3, [$a, $b]);
$a->resolve('a');
$b->resolve('b');
$d->wait();
}
public function testAnyReturnsFirstMatch()
{
$a = new Promise();
$b = new Promise();
$c = \GuzzleHttp\Promise\any([$a, $b]);
$b->resolve('b');
$a->resolve('a');
//P\queue()->run();
//$this->assertEquals('fulfilled', $c->getState());
$c->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals('b', $result);
}
public function testSettleFulfillsWithFulfilledAndRejected()
{
$a = new Promise();
$b = new Promise();
$c = new Promise();
$d = \GuzzleHttp\Promise\settle([$a, $b, $c]);
$b->resolve('b');
$c->resolve('c');
$a->reject('a');
P\queue()->run();
$this->assertEquals('fulfilled', $d->getState());
$d->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals([
['state' => 'rejected', 'reason' => 'a'],
['state' => 'fulfilled', 'value' => 'b'],
['state' => 'fulfilled', 'value' => 'c']
], $result);
}
public function testCanInspectFulfilledPromise()
{
$p = new FulfilledPromise('foo');
$this->assertEquals([
'state' => 'fulfilled',
'value' => 'foo'
], \GuzzleHttp\Promise\inspect($p));
}
public function testCanInspectRejectedPromise()
{
$p = new RejectedPromise('foo');
$this->assertEquals([
'state' => 'rejected',
'reason' => 'foo'
], \GuzzleHttp\Promise\inspect($p));
}
public function testCanInspectRejectedPromiseWithNormalException()
{
$e = new \Exception('foo');
$p = new RejectedPromise($e);
$this->assertEquals([
'state' => 'rejected',
'reason' => $e
], \GuzzleHttp\Promise\inspect($p));
}
public function testCallsEachLimit()
{
$p = new Promise();
$aggregate = \GuzzleHttp\Promise\each_limit($p, 2);
$p->resolve('a');
P\queue()->run();
$this->assertEquals($p::FULFILLED, $aggregate->getState());
}
public function testEachLimitAllRejectsOnFailure()
{
$p = [new FulfilledPromise('a'), new RejectedPromise('b')];
$aggregate = \GuzzleHttp\Promise\each_limit_all($p, 2);
P\queue()->run();
$this->assertEquals(P\PromiseInterface::REJECTED, $aggregate->getState());
$result = \GuzzleHttp\Promise\inspect($aggregate);
$this->assertEquals('b', $result['reason']);
}
public function testIterForReturnsIterator()
{
$iter = new \ArrayIterator();
$this->assertSame($iter, \GuzzleHttp\Promise\iter_for($iter));
}
public function testKnowsIfFulfilled()
{
$p = new FulfilledPromise(null);
$this->assertTrue(P\is_fulfilled($p));
$this->assertFalse(P\is_rejected($p));
}
public function testKnowsIfRejected()
{
$p = new RejectedPromise(null);
$this->assertTrue(P\is_rejected($p));
$this->assertFalse(P\is_fulfilled($p));
}
public function testKnowsIfSettled()
{
$p = new RejectedPromise(null);
$this->assertTrue(P\is_settled($p));
$p = new Promise();
$this->assertFalse(P\is_settled($p));
}
public function testReturnsTrampoline()
{
$this->assertInstanceOf('GuzzleHttp\Promise\TaskQueue', P\queue());
$this->assertSame(P\queue(), P\queue());
}
public function testCanScheduleThunk()
{
$tramp = P\queue();
$promise = P\task(function () { return 'Hi!'; });
$c = null;
$promise->then(function ($v) use (&$c) { $c = $v; });
$this->assertNull($c);
$tramp->run();
$this->assertEquals('Hi!', $c);
}
public function testCanScheduleThunkWithRejection()
{
$tramp = P\queue();
$promise = P\task(function () { throw new \Exception('Hi!'); });
$c = null;
$promise->otherwise(function ($v) use (&$c) { $c = $v; });
$this->assertNull($c);
$tramp->run();
$this->assertEquals('Hi!', $c->getMessage());
}
public function testCanScheduleThunkWithWait()
{
$tramp = P\queue();
$promise = P\task(function () { return 'a'; });
$this->assertEquals('a', $promise->wait());
$tramp->run();
}
public function testYieldsFromCoroutine()
{
$promise = P\coroutine(function () {
$value = (yield new P\FulfilledPromise('a'));
yield $value . 'b';
});
$promise->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals('ab', $result);
}
public function testCanCatchExceptionsInCoroutine()
{
$promise = P\coroutine(function () {
try {
yield new P\RejectedPromise('a');
$this->fail('Should have thrown into the coroutine!');
} catch (P\RejectionException $e) {
$value = (yield new P\FulfilledPromise($e->getReason()));
yield $value . 'b';
}
});
$promise->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals(P\PromiseInterface::FULFILLED, $promise->getState());
$this->assertEquals('ab', $result);
}
public function testRejectsParentExceptionWhenException()
{
$promise = P\coroutine(function () {
yield new P\FulfilledPromise(0);
throw new \Exception('a');
});
$promise->then(
function () { $this->fail(); },
function ($reason) use (&$result) { $result = $reason; }
);
P\queue()->run();
$this->assertInstanceOf('Exception', $result);
$this->assertEquals('a', $result->getMessage());
}
public function testCanRejectFromRejectionCallback()
{
$promise = P\coroutine(function () {
yield new P\FulfilledPromise(0);
yield new P\RejectedPromise('no!');
});
$promise->then(
function () { $this->fail(); },
function ($reason) use (&$result) { $result = $reason; }
);
P\queue()->run();
$this->assertInstanceOf('GuzzleHttp\Promise\RejectionException', $result);
$this->assertEquals('no!', $result->getReason());
}
public function testCanAsyncReject()
{
$rej = new P\Promise();
$promise = P\coroutine(function () use ($rej) {
yield new P\FulfilledPromise(0);
yield $rej;
});
$promise->then(
function () { $this->fail(); },
function ($reason) use (&$result) { $result = $reason; }
);
$rej->reject('no!');
P\queue()->run();
$this->assertInstanceOf('GuzzleHttp\Promise\RejectionException', $result);
$this->assertEquals('no!', $result->getReason());
}
public function testCanCatchAndThrowOtherException()
{
$promise = P\coroutine(function () {
try {
yield new P\RejectedPromise('a');
$this->fail('Should have thrown into the coroutine!');
} catch (P\RejectionException $e) {
throw new \Exception('foo');
}
});
$promise->otherwise(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals(P\PromiseInterface::REJECTED, $promise->getState());
$this->assertContains('foo', $result->getMessage());
}
public function testCanCatchAndYieldOtherException()
{
$promise = P\coroutine(function () {
try {
yield new P\RejectedPromise('a');
$this->fail('Should have thrown into the coroutine!');
} catch (P\RejectionException $e) {
yield new P\RejectedPromise('foo');
}
});
$promise->otherwise(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals(P\PromiseInterface::REJECTED, $promise->getState());
$this->assertContains('foo', $result->getMessage());
}
public function createLotsOfSynchronousPromise()
{
return P\coroutine(function () {
$value = 0;
for ($i = 0; $i < 1000; $i++) {
$value = (yield new P\FulfilledPromise($i));
}
yield $value;
});
}
public function testLotsOfSynchronousDoesNotBlowStack()
{
$promise = $this->createLotsOfSynchronousPromise();
$promise->then(function ($v) use (&$r) { $r = $v; });
P\queue()->run();
$this->assertEquals(999, $r);
}
public function testLotsOfSynchronousWaitDoesNotBlowStack()
{
$promise = $this->createLotsOfSynchronousPromise();
$promise->then(function ($v) use (&$r) { $r = $v; });
$this->assertEquals(999, $promise->wait());
$this->assertEquals(999, $r);
}
private function createLotsOfFlappingPromise()
{
return P\coroutine(function () {
$value = 0;
for ($i = 0; $i < 1000; $i++) {
try {
if ($i % 2) {
$value = (yield new P\FulfilledPromise($i));
} else {
$value = (yield new P\RejectedPromise($i));
}
} catch (\Exception $e) {
$value = (yield new P\FulfilledPromise($i));
}
}
yield $value;
});
}
public function testLotsOfTryCatchingDoesNotBlowStack()
{
$promise = $this->createLotsOfFlappingPromise();
$promise->then(function ($v) use (&$r) { $r = $v; });
P\queue()->run();
$this->assertEquals(999, $r);
}
public function testLotsOfTryCatchingWaitingDoesNotBlowStack()
{
$promise = $this->createLotsOfFlappingPromise();
$promise->then(function ($v) use (&$r) { $r = $v; });
$this->assertEquals(999, $promise->wait());
$this->assertEquals(999, $r);
}
public function testAsyncPromisesWithCorrectlyYieldedValues()
{
$promises = [
new P\Promise(),
new P\Promise(),
new P\Promise()
];
$promise = P\coroutine(function () use ($promises) {
$value = null;
$this->assertEquals('skip', (yield new P\FulfilledPromise('skip')));
foreach ($promises as $idx => $p) {
$value = (yield $p);
$this->assertEquals($value, $idx);
$this->assertEquals('skip', (yield new P\FulfilledPromise('skip')));
}
$this->assertEquals('skip', (yield new P\FulfilledPromise('skip')));
yield $value;
});
$promises[0]->resolve(0);
$promises[1]->resolve(1);
$promises[2]->resolve(2);
$promise->then(function ($v) use (&$r) { $r = $v; });
P\queue()->run();
$this->assertEquals(2, $r);
}
public function testYieldFinalWaitablePromise()
{
$p1 = new P\Promise(function () use (&$p1) {
$p1->resolve('skip me');
});
$p2 = new P\Promise(function () use (&$p2) {
$p2->resolve('hello!');
});
$co = P\coroutine(function() use ($p1, $p2) {
yield $p1;
yield $p2;
});
P\queue()->run();
$this->assertEquals('hello!', $co->wait());
}
public function testCanYieldFinalPendingPromise()
{
$p1 = new P\Promise();
$p2 = new P\Promise();
$co = P\coroutine(function() use ($p1, $p2) {
yield $p1;
yield $p2;
});
$p1->resolve('a');
$p2->resolve('b');
$co->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals('b', $result);
}
public function testCanNestYieldsAndFailures()
{
$p1 = new P\Promise();
$p2 = new P\Promise();
$p3 = new P\Promise();
$p4 = new P\Promise();
$p5 = new P\Promise();
$co = P\coroutine(function() use ($p1, $p2, $p3, $p4, $p5) {
try {
yield $p1;
} catch (\Exception $e) {
yield $p2;
try {
yield $p3;
yield $p4;
} catch (\Exception $e) {
yield $p5;
}
}
});
$p1->reject('a');
$p2->resolve('b');
$p3->resolve('c');
$p4->reject('d');
$p5->resolve('e');
$co->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals('e', $result);
}
public function testCanYieldErrorsAndSuccessesWithoutRecursion()
{
$promises = [];
for ($i = 0; $i < 20; $i++) {
$promises[] = new P\Promise();
}
$co = P\coroutine(function() use ($promises) {
for ($i = 0; $i < 20; $i += 4) {
try {
yield $promises[$i];
yield $promises[$i + 1];
} catch (\Exception $e) {
yield $promises[$i + 2];
yield $promises[$i + 3];
}
}
});
for ($i = 0; $i < 20; $i += 4) {
$promises[$i]->resolve($i);
$promises[$i + 1]->reject($i + 1);
$promises[$i + 2]->resolve($i + 2);
$promises[$i + 3]->resolve($i + 3);
}
$co->then(function ($value) use (&$result) { $result = $value; });
P\queue()->run();
$this->assertEquals('19', $result);
}
public function testCanWaitOnPromiseAfterFulfilled()
{
$f = function () {
static $i = 0;
$i++;
return $p = new P\Promise(function () use (&$p, $i) {
$p->resolve($i . '-bar');
});
};
$promises = [];
for ($i = 0; $i < 20; $i++) {
$promises[] = $f();
}
$p = P\coroutine(function () use ($promises) {
yield new P\FulfilledPromise('foo!');
foreach ($promises as $promise) {
yield $promise;
}
});
$this->assertEquals('20-bar', $p->wait());
}
public function testCanWaitOnErroredPromises()
{
$p1 = new P\Promise(function () use (&$p1) { $p1->reject('a'); });
$p2 = new P\Promise(function () use (&$p2) { $p2->resolve('b'); });
$p3 = new P\Promise(function () use (&$p3) { $p3->resolve('c'); });
$p4 = new P\Promise(function () use (&$p4) { $p4->reject('d'); });
$p5 = new P\Promise(function () use (&$p5) { $p5->resolve('e'); });
$p6 = new P\Promise(function () use (&$p6) { $p6->reject('f'); });
$co = P\coroutine(function() use ($p1, $p2, $p3, $p4, $p5, $p6) {
try {
yield $p1;
} catch (\Exception $e) {
yield $p2;
try {
yield $p3;
yield $p4;
} catch (\Exception $e) {
yield $p5;
yield $p6;
}
}
});
$res = P\inspect($co);
$this->assertEquals('f', $res['reason']);
}
public function testCoroutineOtherwiseIntegrationTest()
{
$a = new P\Promise();
$b = new P\Promise();
$promise = P\coroutine(function () use ($a, $b) {
// Execute the pool of commands concurrently, and process errors.
yield $a;
yield $b;
})->otherwise(function (\Exception $e) {
// Throw errors from the operations as a specific Multipart error.
throw new \OutOfBoundsException('a', 0, $e);
});
$a->resolve('a');
$b->reject('b');
$reason = P\inspect($promise)['reason'];
$this->assertInstanceOf('OutOfBoundsException', $reason);
$this->assertInstanceOf('GuzzleHttp\Promise\RejectionException', $reason->getPrevious());
}
}