diff --git a/README.md b/README.md index 6cd4dbf5..e1e4c139 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,11 @@ Table of Contents * [PromiseInterface](#promiseinterface) * [PromiseInterface::then()](#promiseinterfacethen) * [PromiseInterface::done()](#promiseinterfacedone) - * [PromiseInterface::otherwise()](#promiseinterfaceotherwise) - * [PromiseInterface::always()](#promiseinterfacealways) + * [PromiseInterface::catch()](#promiseinterfacecatch) + * [PromiseInterface::finally()](#promiseinterfacefinally) * [PromiseInterface::cancel()](#promiseinterfacecancel) + * [~~PromiseInterface::otherwise()~~](#promiseinterfaceotherwise) + * [~~PromiseInterface::always()~~](#promiseinterfacealways) * [Promise](#promise-2) * [Functions](#functions) * [resolve()](#resolve) @@ -206,10 +208,10 @@ Since the purpose of `done()` is consumption rather than transformation, * [PromiseInterface::then()](#promiseinterfacethen) * [done() vs. then()](#done-vs-then) -#### PromiseInterface::otherwise() +#### PromiseInterface::catch() ```php -$promise->otherwise(callable $onRejected); +$promise->catch(callable $onRejected); ``` Registers a rejection handler for promise. It is a shortcut for: @@ -223,19 +225,19 @@ only specific errors. ```php $promise - ->otherwise(function (\RuntimeException $reason) { + ->catch(function (\RuntimeException $reason) { // Only catch \RuntimeException instances // All other types of errors will propagate automatically }) - ->otherwise(function (\Throwable $reason) { + ->catch(function (\Throwable $reason) { // Catch other errors }); ``` -#### PromiseInterface::always() +#### PromiseInterface::finally() ```php -$newPromise = $promise->always(callable $onFulfilledOrRejected); +$newPromise = $promise->finally(callable $onFulfilledOrRejected); ``` Allows you to execute "cleanup" type tasks in a promise chain. @@ -254,15 +256,15 @@ when the promise is either fulfilled or rejected. rejected promise, `$newPromise` will reject with the thrown exception or rejected promise's reason. -`always()` behaves similarly to the synchronous finally statement. When combined -with `otherwise()`, `always()` allows you to write code that is similar to the familiar +`finally()` behaves similarly to the synchronous finally statement. When combined +with `catch()`, `finally()` allows you to write code that is similar to the familiar synchronous catch/finally pair. Consider the following synchronous code: ```php try { - return doSomething(); + return doSomething(); } catch (\Throwable $e) { return handleError($e); } finally { @@ -275,8 +277,8 @@ written: ```php return doSomething() - ->otherwise('handleError') - ->always('cleanup'); + ->catch('handleError') + ->finally('cleanup'); ``` #### PromiseInterface::cancel() @@ -291,6 +293,32 @@ further interest in the results of the operation. Once a promise is settled (either fulfilled or rejected), calling `cancel()` on a promise has no effect. +#### ~~PromiseInterface::otherwise()~~ + +> Deprecated since v3.0.0, see [`catch()`](#promiseinterfacecatch) instead. + +The `otherwise()` method registers a rejection handler for a promise. + +This method continues to exist only for BC reasons and to ease upgrading +between versions. It is an alias for: + +```php +$promise->catch($onRejected); +``` + +#### ~~PromiseInterface::always()~~ + +> Deprecated since v3.0.0, see [`finally()`](#promiseinterfacefinally) instead. + +The `always()` method allows you to execute "cleanup" type tasks in a promise chain. + +This method continues to exist only for BC reasons and to ease upgrading +between versions. It is an alias for: + +```php +$promise->finally($onFulfilledOrRejected); +``` + ### Promise Creates a promise whose state is controlled by the functions passed to @@ -559,17 +587,17 @@ $deferred->promise() ->then(function ($x) { throw new \Exception($x + 1); }) - ->otherwise(function (\Exception $x) { + ->catch(function (\Exception $x) { // Propagate the rejection throw $x; }) - ->otherwise(function (\Exception $x) { + ->catch(function (\Exception $x) { // Can also propagate by returning another rejection return React\Promise\reject( new \Exception($x->getMessage() + 1) ); }) - ->otherwise(function ($x) { + ->catch(function ($x) { echo 'Reject ' . $x->getMessage(); // 3 }); @@ -591,7 +619,7 @@ $deferred->promise() ->then(function ($x) { throw new \Exception($x + 1); }) - ->otherwise(function (\Exception $x) { + ->catch(function (\Exception $x) { // Handle the rejection, and don't propagate. // This is like catch without a rethrow return $x->getMessage() + 1; diff --git a/src/Internal/FulfilledPromise.php b/src/Internal/FulfilledPromise.php index e95d5aa4..df0c86b6 100644 --- a/src/Internal/FulfilledPromise.php +++ b/src/Internal/FulfilledPromise.php @@ -60,12 +60,12 @@ public function done(callable $onFulfilled = null, callable $onRejected = null): }); } - public function otherwise(callable $onRejected): PromiseInterface + public function catch(callable $onRejected): PromiseInterface { return $this; } - public function always(callable $onFulfilledOrRejected): PromiseInterface + public function finally(callable $onFulfilledOrRejected): PromiseInterface { return $this->then(function ($value) use ($onFulfilledOrRejected): PromiseInterface { return resolve($onFulfilledOrRejected())->then(function () use ($value) { @@ -77,4 +77,22 @@ public function always(callable $onFulfilledOrRejected): PromiseInterface public function cancel(): void { } + + /** + * @deprecated 3.0.0 Use `catch()` instead + * @see self::catch() + */ + public function otherwise(callable $onRejected): PromiseInterface + { + return $this->catch($onRejected); + } + + /** + * @deprecated 3.0.0 Use `finally()` instead + * @see self::finally() + */ + public function always(callable $onFulfilledOrRejected): PromiseInterface + { + return $this->finally($onFulfilledOrRejected); + } } diff --git a/src/Internal/RejectedPromise.php b/src/Internal/RejectedPromise.php index da50cde4..6b24d972 100644 --- a/src/Internal/RejectedPromise.php +++ b/src/Internal/RejectedPromise.php @@ -61,7 +61,7 @@ public function done(callable $onFulfilled = null, callable $onRejected = null): }); } - public function otherwise(callable $onRejected): PromiseInterface + public function catch(callable $onRejected): PromiseInterface { if (!_checkTypehint($onRejected, $this->reason)) { return $this; @@ -70,7 +70,7 @@ public function otherwise(callable $onRejected): PromiseInterface return $this->then(null, $onRejected); } - public function always(callable $onFulfilledOrRejected): PromiseInterface + public function finally(callable $onFulfilledOrRejected): PromiseInterface { return $this->then(null, function (\Throwable $reason) use ($onFulfilledOrRejected): PromiseInterface { return resolve($onFulfilledOrRejected())->then(function () use ($reason): PromiseInterface { @@ -82,4 +82,22 @@ public function always(callable $onFulfilledOrRejected): PromiseInterface public function cancel(): void { } + + /** + * @deprecated 3.0.0 Use `catch()` instead + * @see self::catch() + */ + public function otherwise(callable $onRejected): PromiseInterface + { + return $this->catch($onRejected); + } + + /** + * @deprecated 3.0.0 Use `always()` instead + * @see self::always() + */ + public function always(callable $onFulfilledOrRejected): PromiseInterface + { + return $this->finally($onFulfilledOrRejected); + } } diff --git a/src/Promise.php b/src/Promise.php index a4765e08..b5633e3d 100644 --- a/src/Promise.php +++ b/src/Promise.php @@ -70,7 +70,7 @@ public function done(callable $onFulfilled = null, callable $onRejected = null): }; } - public function otherwise(callable $onRejected): PromiseInterface + public function catch(callable $onRejected): PromiseInterface { return $this->then(null, static function ($reason) use ($onRejected) { if (!_checkTypehint($onRejected, $reason)) { @@ -81,7 +81,7 @@ public function otherwise(callable $onRejected): PromiseInterface }); } - public function always(callable $onFulfilledOrRejected): PromiseInterface + public function finally(callable $onFulfilledOrRejected): PromiseInterface { return $this->then(static function ($value) use ($onFulfilledOrRejected) { return resolve($onFulfilledOrRejected())->then(function () use ($value) { @@ -129,6 +129,24 @@ public function cancel(): void } } + /** + * @deprecated 3.0.0 Use `catch()` instead + * @see self::catch() + */ + public function otherwise(callable $onRejected): PromiseInterface + { + return $this->catch($onRejected); + } + + /** + * @deprecated 3.0.0 Use `finally()` instead + * @see self::finally() + */ + public function always(callable $onFulfilledOrRejected): PromiseInterface + { + return $this->finally($onFulfilledOrRejected); + } + private function resolver(callable $onFulfilled = null, callable $onRejected = null): callable { return function ($resolve, $reject) use ($onFulfilled, $onRejected) { diff --git a/src/PromiseInterface.php b/src/PromiseInterface.php index 3f854b94..e6b46c2a 100644 --- a/src/PromiseInterface.php +++ b/src/PromiseInterface.php @@ -63,7 +63,7 @@ public function done(callable $onFulfilled = null, callable $onRejected = null): * @param callable $onRejected * @return PromiseInterface */ - public function otherwise(callable $onRejected): PromiseInterface; + public function catch(callable $onRejected): PromiseInterface; /** * Allows you to execute "cleanup" type tasks in a promise chain. @@ -82,8 +82,8 @@ public function otherwise(callable $onRejected): PromiseInterface; * rejected promise, `$newPromise` will reject with the thrown exception or * rejected promise's reason. * - * `always()` behaves similarly to the synchronous finally statement. When combined - * with `otherwise()`, `always()` allows you to write code that is similar to the familiar + * `finally()` behaves similarly to the synchronous finally statement. When combined + * with `catch()`, `finally()` allows you to write code that is similar to the familiar * synchronous catch/finally pair. * * Consider the following synchronous code: @@ -103,14 +103,14 @@ public function otherwise(callable $onRejected): PromiseInterface; * * ```php * return doSomething() - * ->otherwise('handleError') - * ->always('cleanup'); + * ->catch('handleError') + * ->finally('cleanup'); * ``` * * @param callable $onFulfilledOrRejected * @return PromiseInterface */ - public function always(callable $onFulfilledOrRejected): PromiseInterface; + public function finally(callable $onFulfilledOrRejected): PromiseInterface; /** * The `cancel()` method notifies the creator of the promise that there is no @@ -122,4 +122,38 @@ public function always(callable $onFulfilledOrRejected): PromiseInterface; * @return void */ public function cancel(): void; + + /** + * [Deprecated] Registers a rejection handler for a promise. + * + * This method continues to exist only for BC reasons and to ease upgrading + * between versions. It is an alias for: + * + * ```php + * $promise->catch($onRejected); + * ``` + * + * @param callable $onRejected + * @return PromiseInterface + * @deprecated 3.0.0 Use catch() instead + * @see self::catch() + */ + public function otherwise(callable $onRejected): PromiseInterface; + + /** + * [Deprecated] Allows you to execute "cleanup" type tasks in a promise chain. + * + * This method continues to exist only for BC reasons and to ease upgrading + * between versions. It is an alias for: + * + * ```php + * $promise->finally($onFulfilledOrRejected); + * ``` + * + * @param callable $onFulfilledOrRejected + * @return PromiseInterface + * @deprecated 3.0.0 Use finally() instead + * @see self::finally() + */ + public function always(callable $onFulfilledOrRejected): PromiseInterface; } diff --git a/tests/PromiseTest.php b/tests/PromiseTest.php index 6af65ce5..e8e9f090 100644 --- a/tests/PromiseTest.php +++ b/tests/PromiseTest.php @@ -224,6 +224,31 @@ public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPro } /** @test */ + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithCatchFollowers() + { + gc_collect_cycles(); + $promise = new Promise(function () { }); + $promise->catch(function () { }); + unset($promise); + + $this->assertSame(0, gc_collect_cycles()); + } + + /** @test */ + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithFinallyFollowers() + { + gc_collect_cycles(); + $promise = new Promise(function () { }); + $promise->finally(function () { }); + unset($promise); + + $this->assertSame(0, gc_collect_cycles()); + } + + /** + * @test + * @deprecated + */ public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithOtherwiseFollowers() { gc_collect_cycles(); @@ -234,7 +259,10 @@ public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPro $this->assertSame(0, gc_collect_cycles()); } - /** @test */ + /** + * @test + * @deprecated + */ public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithAlwaysFollowers() { gc_collect_cycles(); diff --git a/tests/PromiseTest/PromiseFulfilledTestTrait.php b/tests/PromiseTest/PromiseFulfilledTestTrait.php index 0b79a95b..d58ab58a 100644 --- a/tests/PromiseTest/PromiseFulfilledTestTrait.php +++ b/tests/PromiseTest/PromiseFulfilledTestTrait.php @@ -261,6 +261,121 @@ public function doneShouldTriggerFatalErrorUnhandledRejectionExceptionWhenFulfil } /** @test */ + public function catchShouldNotInvokeRejectionHandlerForFulfilledPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $adapter->resolve(1); + $adapter->promise()->catch($this->expectCallableNever()); + } + + /** @test */ + public function finallyShouldNotSuppressValueForFulfilledPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $value = new stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($value)); + + $adapter->resolve($value); + $adapter->promise() + ->finally(function () {}) + ->then($mock); + } + + /** @test */ + public function finallyShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulfilledPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $value = new stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($value)); + + $adapter->resolve($value); + $adapter->promise() + ->finally(function () { + return 1; + }) + ->then($mock); + } + + /** @test */ + public function finallyShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfilledPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $value = new stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($value)); + + $adapter->resolve($value); + $adapter->promise() + ->finally(function () { + return resolve(1); + }) + ->then($mock); + } + + /** @test */ + public function finallyShouldRejectWhenHandlerThrowsForFulfilledPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->resolve(1); + $adapter->promise() + ->finally(function () use ($exception) { + throw $exception; + }) + ->then(null, $mock); + } + + /** @test */ + public function finallyShouldRejectWhenHandlerRejectsForFulfilledPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->resolve(1); + $adapter->promise() + ->finally(function () use ($exception) { + return reject($exception); + }) + ->then(null, $mock); + } + + /** + * @test + * @deprecated + */ public function otherwiseShouldNotInvokeRejectionHandlerForFulfilledPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -269,7 +384,10 @@ public function otherwiseShouldNotInvokeRejectionHandlerForFulfilledPromise() $adapter->promise()->otherwise($this->expectCallableNever()); } - /** @test */ + /** + * @test + * @deprecated + */ public function alwaysShouldNotSuppressValueForFulfilledPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -288,7 +406,10 @@ public function alwaysShouldNotSuppressValueForFulfilledPromise() ->then($mock); } - /** @test */ + /** + * @test + * @deprecated + */ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulfilledPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -309,7 +430,10 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulf ->then($mock); } - /** @test */ + /** + * @test + * @deprecated + */ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfilledPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -330,7 +454,10 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfill ->then($mock); } - /** @test */ + /** + * @test + * @deprecated + */ public function alwaysShouldRejectWhenHandlerThrowsForFulfilledPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -351,7 +478,10 @@ public function alwaysShouldRejectWhenHandlerThrowsForFulfilledPromise() ->then(null, $mock); } - /** @test */ + /** + * @test + * @deprecated + */ public function alwaysShouldRejectWhenHandlerRejectsForFulfilledPromise() { $adapter = $this->getPromiseTestAdapter(); diff --git a/tests/PromiseTest/PromisePendingTestTrait.php b/tests/PromiseTest/PromisePendingTestTrait.php index 87d18c32..e4750197 100644 --- a/tests/PromiseTest/PromisePendingTestTrait.php +++ b/tests/PromiseTest/PromisePendingTestTrait.php @@ -53,6 +53,26 @@ public function doneShouldReturnAllowNullForPendingPromise() } /** @test */ + public function catchShouldNotInvokeRejectionHandlerForPendingPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $adapter->settle(); + $adapter->promise()->catch($this->expectCallableNever()); + } + + /** @test */ + public function finallyShouldReturnAPromiseForPendingPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + self::assertInstanceOf(PromiseInterface::class, $adapter->promise()->finally(function () {})); + } + + /** + * @test + * @deprecated + */ public function otherwiseShouldNotInvokeRejectionHandlerForPendingPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -61,7 +81,10 @@ public function otherwiseShouldNotInvokeRejectionHandlerForPendingPromise() $adapter->promise()->otherwise($this->expectCallableNever()); } - /** @test */ + /** + * @test + * @deprecated + */ public function alwaysShouldReturnAPromiseForPendingPromise() { $adapter = $this->getPromiseTestAdapter(); diff --git a/tests/PromiseTest/PromiseRejectedTestTrait.php b/tests/PromiseTest/PromiseRejectedTestTrait.php index 68b401c4..84922f64 100644 --- a/tests/PromiseTest/PromiseRejectedTestTrait.php +++ b/tests/PromiseTest/PromiseRejectedTestTrait.php @@ -312,7 +312,7 @@ public function doneShouldRecoverWhenRejectionHandlerCatchesExceptionForRejected } /** @test */ - public function otherwiseShouldInvokeRejectionHandlerForRejectedPromise() + public function catchShouldInvokeRejectionHandlerForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -325,11 +325,11 @@ public function otherwiseShouldInvokeRejectionHandlerForRejectedPromise() ->with($this->identicalTo($exception)); $adapter->reject($exception); - $adapter->promise()->otherwise($mock); + $adapter->promise()->catch($mock); } /** @test */ - public function otherwiseShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnExceptionForRejectedPromise() + public function catchShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnExceptionForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -343,13 +343,13 @@ public function otherwiseShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnEx $adapter->reject($exception); $adapter->promise() - ->otherwise(function ($reason) use ($mock) { + ->catch(function ($reason) use ($mock) { $mock($reason); }); } /** @test */ - public function otherwiseShouldInvokeRejectionHandlerIfReasonMatchesTypehintForRejectedPromise() + public function catchShouldInvokeRejectionHandlerIfReasonMatchesTypehintForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -363,13 +363,13 @@ public function otherwiseShouldInvokeRejectionHandlerIfReasonMatchesTypehintForR $adapter->reject($exception); $adapter->promise() - ->otherwise(function (InvalidArgumentException $reason) use ($mock) { + ->catch(function (InvalidArgumentException $reason) use ($mock) { $mock($reason); }); } /** @test */ - public function otherwiseShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchTypehintForRejectedPromise() + public function catchShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchTypehintForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -379,13 +379,13 @@ public function otherwiseShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchType $adapter->reject($exception); $adapter->promise() - ->otherwise(function (InvalidArgumentException $reason) use ($mock) { + ->catch(function (InvalidArgumentException $reason) use ($mock) { $mock($reason); }); } /** @test */ - public function alwaysShouldNotSuppressRejectionForRejectedPromise() + public function finallyShouldNotSuppressRejectionForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -399,12 +399,12 @@ public function alwaysShouldNotSuppressRejectionForRejectedPromise() $adapter->reject($exception); $adapter->promise() - ->always(function () {}) + ->finally(function () {}) ->then(null, $mock); } /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseForRejectedPromise() + public function finallyShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -418,14 +418,14 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseFor $adapter->reject($exception); $adapter->promise() - ->always(function () { + ->finally(function () { return 1; }) ->then(null, $mock); } /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRejectedPromise() + public function finallyShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -439,14 +439,14 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRej $adapter->reject($exception); $adapter->promise() - ->always(function () { + ->finally(function () { return resolve(1); }) ->then(null, $mock); } /** @test */ - public function alwaysShouldRejectWhenHandlerThrowsForRejectedPromise() + public function finallyShouldRejectWhenHandlerThrowsForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -461,14 +461,14 @@ public function alwaysShouldRejectWhenHandlerThrowsForRejectedPromise() $adapter->reject($exception1); $adapter->promise() - ->always(function () use ($exception2) { + ->finally(function () use ($exception2) { throw $exception2; }) ->then(null, $mock); } /** @test */ - public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise() + public function finallyShouldRejectWhenHandlerRejectsForRejectedPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -483,7 +483,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise() $adapter->reject($exception1); $adapter->promise() - ->always(function () use ($exception2) { + ->finally(function () use ($exception2) { return reject($exception2); }) ->then(null, $mock); @@ -508,4 +508,209 @@ public function cancelShouldHaveNoEffectForRejectedPromise() $adapter->promise()->cancel(); } + + /** + * @test + * @deprecated + */ + public function otherwiseShouldInvokeRejectionHandlerForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->reject($exception); + $adapter->promise()->otherwise($mock); + } + + /** + * @test + * @deprecated + */ + public function otherwiseShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnExceptionForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->reject($exception); + $adapter->promise() + ->otherwise(function ($reason) use ($mock) { + $mock($reason); + }); + } + + /** + * @test + * @deprecated + */ + public function otherwiseShouldInvokeRejectionHandlerIfReasonMatchesTypehintForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new InvalidArgumentException(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->reject($exception); + $adapter->promise() + ->otherwise(function (InvalidArgumentException $reason) use ($mock) { + $mock($reason); + }); + } + + /** + * @test + * @deprecated + */ + public function otherwiseShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchTypehintForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->expectCallableNever(); + + $adapter->reject($exception); + $adapter->promise() + ->otherwise(function (InvalidArgumentException $reason) use ($mock) { + $mock($reason); + }); + } + + /** + * @test + * @deprecated + */ + public function alwaysShouldNotSuppressRejectionForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->reject($exception); + $adapter->promise() + ->always(function () {}) + ->then(null, $mock); + } + + /** + * @test + * @deprecated + */ + public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->reject($exception); + $adapter->promise() + ->finally(function () { + return 1; + }) + ->then(null, $mock); + } + + /** + * @test + * @deprecated + */ + public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $adapter->reject($exception); + $adapter->promise() + ->always(function () { + return resolve(1); + }) + ->then(null, $mock); + } + + /** + * @test + * @deprecated + */ + public function alwaysShouldRejectWhenHandlerThrowsForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception1 = new Exception(); + $exception2 = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception2)); + + $adapter->reject($exception1); + $adapter->promise() + ->always(function () use ($exception2) { + throw $exception2; + }) + ->then(null, $mock); + } + + /** + * @test + * @deprecated + */ + public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $exception1 = new Exception(); + $exception2 = new Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception2)); + + $adapter->reject($exception1); + $adapter->promise() + ->always(function () use ($exception2) { + return reject($exception2); + }) + ->then(null, $mock); + } } diff --git a/tests/PromiseTest/PromiseSettledTestTrait.php b/tests/PromiseTest/PromiseSettledTestTrait.php index 626011e1..bf2b6f52 100644 --- a/tests/PromiseTest/PromiseSettledTestTrait.php +++ b/tests/PromiseTest/PromiseSettledTestTrait.php @@ -69,6 +69,18 @@ public function doneShouldReturnAllowNullForSettledPromise() } /** @test */ + public function finallyShouldReturnAPromiseForSettledPromise() + { + $adapter = $this->getPromiseTestAdapter(); + + $adapter->settle(); + self::assertInstanceOf(PromiseInterface::class, $adapter->promise()->finally(function () {})); + } + + /** + * @test + * @deprecated + */ public function alwaysShouldReturnAPromiseForSettledPromise() { $adapter = $this->getPromiseTestAdapter(); diff --git a/tests/PromiseTest/RejectTestTrait.php b/tests/PromiseTest/RejectTestTrait.php index c089e0ad..8b4017aa 100644 --- a/tests/PromiseTest/RejectTestTrait.php +++ b/tests/PromiseTest/RejectTestTrait.php @@ -91,7 +91,7 @@ public function rejectShouldMakePromiseImmutable() } /** @test */ - public function rejectShouldInvokeOtherwiseHandler() + public function rejectShouldInvokeCatchHandler() { $adapter = $this->getPromiseTestAdapter(); @@ -104,7 +104,7 @@ public function rejectShouldInvokeOtherwiseHandler() ->with($this->identicalTo($exception)); $adapter->promise() - ->otherwise($mock); + ->catch($mock); $adapter->reject($exception); } @@ -247,7 +247,7 @@ public function doneShouldRecoverWhenRejectionHandlerCatchesException() } /** @test */ - public function alwaysShouldNotSuppressRejection() + public function finallyShouldNotSuppressRejection() { $adapter = $this->getPromiseTestAdapter(); @@ -260,14 +260,14 @@ public function alwaysShouldNotSuppressRejection() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () {}) + ->finally(function () {}) ->then(null, $mock); $adapter->reject($exception); } /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() + public function finallyShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -280,7 +280,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () { + ->finally(function () { return 1; }) ->then(null, $mock); @@ -289,7 +289,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() } /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise() + public function finallyShouldNotSuppressRejectionWhenHandlerReturnsAPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -302,7 +302,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () { + ->finally(function () { return resolve(1); }) ->then(null, $mock); @@ -311,7 +311,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise() } /** @test */ - public function alwaysShouldRejectWhenHandlerThrowsForRejection() + public function finallyShouldRejectWhenHandlerThrowsForRejection() { $adapter = $this->getPromiseTestAdapter(); @@ -324,7 +324,7 @@ public function alwaysShouldRejectWhenHandlerThrowsForRejection() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->finally(function () use ($exception) { throw $exception; }) ->then(null, $mock); @@ -333,7 +333,7 @@ public function alwaysShouldRejectWhenHandlerThrowsForRejection() } /** @test */ - public function alwaysShouldRejectWhenHandlerRejectsForRejection() + public function finallyShouldRejectWhenHandlerRejectsForRejection() { $adapter = $this->getPromiseTestAdapter(); @@ -346,7 +346,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForRejection() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->finally(function () use ($exception) { return reject($exception); }) ->then(null, $mock); diff --git a/tests/PromiseTest/ResolveTestTrait.php b/tests/PromiseTest/ResolveTestTrait.php index 23105bfd..e11d6a02 100644 --- a/tests/PromiseTest/ResolveTestTrait.php +++ b/tests/PromiseTest/ResolveTestTrait.php @@ -223,7 +223,7 @@ public function doneShouldTriggerFatalErrorUnhandledRejectionExceptionWhenFulfil } /** @test */ - public function alwaysShouldNotSuppressValue() + public function finallyShouldNotSuppressValue() { $adapter = $this->getPromiseTestAdapter(); @@ -236,14 +236,14 @@ public function alwaysShouldNotSuppressValue() ->with($this->identicalTo($value)); $adapter->promise() - ->always(function () {}) + ->finally(function () {}) ->then($mock); $adapter->resolve($value); } /** @test */ - public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise() + public function finallyShouldNotSuppressValueWhenHandlerReturnsANonPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -256,7 +256,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise() ->with($this->identicalTo($value)); $adapter->promise() - ->always(function () { + ->finally(function () { return 1; }) ->then($mock); @@ -265,7 +265,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise() } /** @test */ - public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise() + public function finallyShouldNotSuppressValueWhenHandlerReturnsAPromise() { $adapter = $this->getPromiseTestAdapter(); @@ -278,7 +278,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise() ->with($this->identicalTo($value)); $adapter->promise() - ->always(function () { + ->finally(function () { return resolve(1); }) ->then($mock); @@ -287,7 +287,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise() } /** @test */ - public function alwaysShouldRejectWhenHandlerThrowsForFulfillment() + public function finallyShouldRejectWhenHandlerThrowsForFulfillment() { $adapter = $this->getPromiseTestAdapter(); @@ -300,7 +300,7 @@ public function alwaysShouldRejectWhenHandlerThrowsForFulfillment() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->finally(function () use ($exception) { throw $exception; }) ->then(null, $mock); @@ -309,7 +309,7 @@ public function alwaysShouldRejectWhenHandlerThrowsForFulfillment() } /** @test */ - public function alwaysShouldRejectWhenHandlerRejectsForFulfillment() + public function finallyShouldRejectWhenHandlerRejectsForFulfillment() { $adapter = $this->getPromiseTestAdapter(); @@ -322,7 +322,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForFulfillment() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->finally(function () use ($exception) { return reject($exception); }) ->then(null, $mock);