/** @test */ public function shouldSupportVeryDeepNestedPromises() { $deferreds = []; // @TODO Increase count once global-queue is merged for ($i = 0; $i < 10; $i++) { $deferreds[] = $d = new Deferred(); $p = $d->promise(); $last = $p; for ($j = 0; $j < 10; $j++) { $last = $last->then(function ($result) { return $result; }); } } $p = null; foreach ($deferreds as $d) { if ($p) { $d->resolve($p); } $p = $d->promise(); } $deferreds[0]->resolve(true); $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo(true)); $deferreds[0]->promise()->then($mock); }
/** @test */ public function shouldForwardValueWhenCallbackIsNull() { $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo(1)); $d = new Deferred(); $d->then(null, $this->expectCallableNever())->then($mock, $this->expectCallableNever()); $d->resolve(1); }
/** @test */ public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises() { $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo([1, 2, 3])); $deferred = new Deferred(); all([resolve(1), $deferred->promise(), resolve(3)])->then($mock); $deferred->resolve(2); }
/** @test */ public function shouldRejectARejectedPromise() { $expected = 123; $d = new Deferred(); $d->reject($expected); $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo($expected)); When::reject($d->promise())->then($this->expectCallableNever(), $mock); }
/** @test */ public function shouldNotRelyOnArryIndexesWhenUnwrappingToASingleResolutionValue() { $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo(2)); $d1 = new Deferred(); $d2 = new Deferred(); When::any(array('abc' => $d1->promise(), 1 => $d2->promise()), $mock); $d2->resolve(2); $d1->resolve(1); }
/** @test */ public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseRejects() { $mock = $this->createCallableMock(); $mock->expects($this->never())->method('__invoke'); $deferred = new Deferred($mock); $deferred->reject(); $mock2 = $this->getMockBuilder('React\\Promise\\CancellablePromiseInterface')->getMock(); $mock2->expects($this->never())->method('cancel'); race([$deferred->promise(), $mock2])->cancel(); }
public function getPromiseTestAdapter() { $d = new Deferred(); $factory = function () use($d) { return $d->promise(); }; return ['promise' => function () use($factory) { return new LazyPromise($factory); }, 'resolve' => [$d, 'resolve'], 'reject' => [$d, 'reject'], 'progress' => [$d, 'progress']]; }
/** * @test * @dataProvider invalidCallbackDataProvider **/ public function shouldIgnoreNonFunctionsAndTriggerPhpNotice($var) { $errorCollector = new ErrorCollector(); $errorCollector->register(); $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo(1)); $d = new Deferred(); $d->then(null, $var)->then($this->expectCallableNever(), $mock); $d->reject(1); $errorCollector->assertCollectedError('Invalid $errorHandler argument passed to then(), must be null or callable.', E_USER_NOTICE); $errorCollector->unregister(); }
/** @test */ public function shouldRejectIfFirstSettledPromiseRejects() { $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo(2)); $d1 = new Deferred(); $d2 = new Deferred(); $d3 = new Deferred(); race([$d1->promise(), $d2->promise(), $d3->promise()])->then($this->expectCallableNever(), $mock); $d2->reject(2); $d1->resolve(1); $d3->resolve(3); }
/** * Create a new generator invoker * @param Client $client */ function __construct(Client $client) { $this->client = $client; parent::__construct(function ($resolve, $reject) { return $this->cancel($resolve, $reject); }); }
/** @test */ public function shouldSupportDeepNestingInPromiseChains() { $d = new Deferred(); $d->resolve(false); $result = When::resolve(When::resolve($d->then(function ($val) { $d = new Deferred(); $d->resolve($val); $identity = function ($val) { return $val; }; return When::resolve($d->then($identity))->then(function ($val) { return !$val; }); }))); $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo(true)); $result->then($mock); }
/** * Emits a value from the observable. The returned promise is resolved with the emitted value once all subscribers * have been invoked. * * @param mixed $value * * @return \Interop\Async\Promise * * @throws \Error If the observable has resolved. */ private function emit($value) : Promise { if ($this->resolved) { throw new \Error("The observable has been resolved; cannot emit more values"); } if ($value instanceof Promise) { $deferred = new Deferred(); $value->when(function ($e, $v) use($deferred) { if ($this->resolved) { $deferred->fail(new \Error("The observable was resolved before the promise result could be emitted")); return; } if ($e) { $this->fail($e); $deferred->fail($e); return; } $deferred->resolve($this->emit($v)); }); return $deferred->promise(); } $promises = []; foreach ($this->subscribers as $onNext) { try { $result = $onNext($value); if ($result instanceof Promise) { $promises[] = $result; } } catch (\Throwable $e) { Loop::defer(static function () use($e) { throw $e; }); } } if (!$promises) { return new Success($value); } $deferred = new Deferred(); $count = \count($promises); $f = static function ($e) use($deferred, $value, &$count) { if ($e) { Loop::defer(static function () use($e) { throw $e; }); } if (!--$count) { $deferred->resolve($value); } }; foreach ($promises as $promise) { $promise->when($f); } return $deferred->promise(); }
/** * @param \Amp\Observable $observable */ public function __construct(Observable $observable) { $this->observable = $observable; $deferred =& $this->deferred; $values =& $this->values; $deferreds =& $this->deferreds; $resolved =& $this->resolved; $this->observable->subscribe(static function ($value) use(&$deferred, &$values, &$deferreds, &$resolved) { $values[] = $value; $deferreds[] = $pressure = new Deferred(); if ($deferred !== null) { $temp = $deferred; $deferred = null; $temp->resolve(true); } if ($resolved) { return null; } return $pressure->promise(); }); $result =& $this->result; $error =& $this->exception; $this->observable->when(static function ($exception, $value) use(&$deferred, &$result, &$error, &$resolved) { $resolved = true; if ($exception) { $result = null; $error = $exception; if ($deferred !== null) { $deferred->fail($exception); } return; } $result = $value; if ($deferred !== null) { $deferred->resolve(false); } }); }
private function onParsedEntityHeaders(Client $client, array $parseResult) { $ireq = $this->initializeRequest($client, $parseResult); $id = $parseResult["id"]; $client->bodyPromisors[$id] = $bodyPromisor = new Deferred(); $ireq->body = new Body($bodyPromisor->promise()); $this->clearKeepAliveTimeout($client); $this->respond($ireq); }
/** * Get the message content as it becomes available. * * @see IncomingMessage::content() to get the content as a string. * * @see IncomingMessage::contentStream() to read the content from a stream. * * The returned promise is notified when content arrives. * @see https://github.com/reactphp/promise#extendedpromiseinterfaceprogress * * Cancelling the returned promise discards any remaining content. * * @return null [via promise] All content has been received. * @throws LogicException [via promise] The message content has already been consumed or discarded. */ public function contentUnbuffered() { if ($this->contentHandled) { return reject(new LogicException('The message content has already been consumed or discarded.')); } $this->contentHandled = true; if (0 === $this->headerFrame->contentLength) { return resolve(); } $deferred = new Deferred($this->cancelContentListener); $this->onBodyFrame = function ($exception, $frame, $final) use($deferred) { if ($exception) { $deferred->reject($exception); } else { $deferred->notify($frame->content); if ($final) { $deferred->resolve(); } } }; return $deferred->promise(); }
/** @test */ public function shouldAllowRejectAfterProgress() { $d = new Deferred(); $mock = $this->createCallableMock(); $mock->expects($this->at(0))->method('__invoke')->with($this->identicalTo(1)); $mock->expects($this->at(1))->method('__invoke')->with($this->identicalTo(2)); $d->promise()->then($this->expectCallableNever(), $mock, $mock); $d->resolver()->progress(1); $d->resolver()->reject(2); }
/** * Returns a promise that succeeds or fails when the first promise succeeds or fails. * * @param Promise[] $promises * * @return \Interop\Async\Promise * * @throws \Error If the array is empty or a non-Promise is in the array. */ function choose(array $promises) : Promise { if (empty($promises)) { throw new \Error("No promises provided"); } $deferred = new Deferred(); $resolved = false; foreach ($promises as $promise) { if (!$promise instanceof Promise) { throw new \Error("Non-promise provided"); } $promise->when(function ($exception, $value) use(&$resolved, $deferred) { if ($resolved) { return; } $resolved = true; if ($exception) { $deferred->fail($exception); return; } $deferred->resolve($value); }); } return $deferred->promise(); }
/** * Declare this exchange. * * @recoil-coroutine * * @param boolean $passive True to use a "passive" declare mode. * @param Channel|null $channel The application-managed channel to use (null = auto-managed). * * @throws ResourceNotFoundException The exchange does not exist. * @throws DeclareException The exchange already exists with different a type or options. * @throws DeclareException A reserved exchange name was used. * @throws ConnectionException The connection is closed. * @throws ChannelException The channel is closed. */ private function declareExchange($passive, Channel $channel = null) : Generator { if ('amq.' === substr($this->name, 0, 4)) { return reject(DeclareException::exchangeNameIsReserved($this->name)); } $deferred = new Deferred(); $this->broker->acquireChannel(function ($exception, $brokerChannel) use($channel, $passive, $deferred) { if ($exception) { $deferred->reject($exception); } else { $brokerChannel->call(ExchangeDeclareFrame::create($this->name, $this->type->value(), $passive, $this->options->durable, $this->options->autoDelete, $this->options->internal, false, $this->arguments), ExchangeDeclareOkFrame::METHOD_ID, function ($exception, $frame) use($brokerChannel, $channel, $deferred) { if (!$channel) { $this->broker->releaseChannel($brokerChannel); } if ($exception) { if ($exception instanceof AmqpException) { if ($exception->getCode() === Constants::PRECONDITION_FAILED) { $exception = DeclareException::exchangeTypeOrOptionMismatch($this->name, $this->type, $this->options, $exception); } elseif ($exception->getCode() === Constants::NOT_FOUND) { $exception = ResourceNotFoundException::exchangeNotFound($this->name, $exception); } } $deferred->reject($exception); } else { $deferred->resolve($this); } }); } }, $channel); return $deferred->promise(); }
public static function map($promisesOrValues, $mapFunc) { return When::resolve($promisesOrValues)->then(function ($array) use($mapFunc) { if (!is_array($array)) { $array = array(); } $toResolve = count($array); $results = array(); $deferred = new Deferred(); if (!$toResolve) { $deferred->resolve($results); } else { $resolve = function ($item, $i) use($mapFunc, &$results, &$toResolve, $deferred) { When::resolve($item)->then($mapFunc)->then(function ($mapped) use(&$results, $i, &$toResolve, $deferred) { $results[$i] = $mapped; if (0 === --$toResolve) { $deferred->resolve($results); } }, array($deferred, 'reject')); }; foreach ($array as $i => $item) { $resolve($item, $i); } } return $deferred->promise(); }); }
/** * Create an artificial timeout for any Promise instance * * If the timeout expires prior to promise resolution the returned * promise is failed. * * @param \Amp\Promise $promise The promise to which the timeout applies * @param int $msTimeout The timeout in milliseconds * @return \Amp\Promise */ function timeout(Promise $promise, $msTimeout) { $resolved = false; $promisor = new Deferred(); $watcherId = once(function () use($promisor, &$resolved) { $resolved = true; $promisor->fail(new TimeoutException("Promise resolution timed out")); }, $msTimeout); $promise->when(function ($error = null, $result = null) use($promisor, $watcherId, &$resolved) { if ($resolved) { return; } $resolved = true; cancel($watcherId); if ($error) { $promisor->fail($error); } else { $promisor->succeed($result); } }); return $promisor->promise(); }
/** @test */ public function shouldCancelOtherPendingInputArrayPromisesIfOnePromiseFulfills() { $mock = $this->createCallableMock(); $mock->expects($this->never())->method('__invoke'); $deferred = new Deferred($mock); $deferred->resolve(); $mock2 = $this->getMock('React\\Promise\\CancellablePromiseInterface'); $mock2->expects($this->once())->method('cancel'); some([$deferred->promise(), $mock2], 1)->cancel(); }
/** @test */ public function shouldProvideCorrectBasisValue() { $insertIntoArray = function ($arr, $val, $i) { $arr[$i] = $val; return $arr; }; $d1 = new Deferred(); $d2 = new Deferred(); $d3 = new Deferred(); $mock = $this->createCallableMock(); $mock->expects($this->once())->method('__invoke')->with($this->identicalTo([1, 2, 3])); reduce([$d1->promise(), $d2->promise(), $d3->promise()], $insertIntoArray, [])->then($mock); $d3->resolve(3); $d1->resolve(1); $d2->resolve(2); }
/** @test */ public function shouldReturnSilentlyOnProgressWhenAlreadyRejected() { $d = new Deferred(); $d->reject(1); $this->assertNull($d->progress()); }