592 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			592 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?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 testWaitsOnAPromiseChainEvenWhenNotUnwrapped()
 | |
|     {
 | |
|         $p2 = new Promise(function () use (&$p2) {
 | |
|             $p2->reject('Fail');
 | |
|         });
 | |
|         $p = new Promise(function () use ($p2, &$p) {
 | |
|             $p->resolve($p2);
 | |
|         });
 | |
|         $p->wait(false);
 | |
|         $this->assertSame(Promise::REJECTED, $p2->getState());
 | |
|     }
 | |
| 
 | |
|     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');
 | |
|     }
 | |
| }
 | 
