From c38cd2dfe04ec2d03ce05d8ba2a1e1082b8bf16c Mon Sep 17 00:00:00 2001 From: David Cole Date: Tue, 23 Feb 2021 13:24:52 +1300 Subject: [PATCH 1/9] Added support for react/promise v3 --- composer.json | 2 +- src/functions.php | 2 +- tests/FunctionAwaitAllTest.php | 4 +++- tests/FunctionAwaitAnyTest.php | 8 ++++---- tests/FunctionAwaitTest.php | 3 +++ tests/TestCase.php | 13 +++++++++++++ 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 4545462..e9224eb 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "require": { "php": ">=5.3", "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", - "react/promise": "^2.7 || ^1.2.1", + "react/promise": "dev-master as 2.9.9", "react/promise-timer": "^1.5" }, "require-dev": { diff --git a/src/functions.php b/src/functions.php index 0fda798..8d2db1b 100644 --- a/src/functions.php +++ b/src/functions.php @@ -283,7 +283,7 @@ function awaitAll(array $promises, LoopInterface $loop, $timeout = null) function _cancelAllPromises(array $promises) { foreach ($promises as $promise) { - if ($promise instanceof CancellablePromiseInterface) { + if ($promise instanceof CancellablePromiseInterface || (is_callable([$promise, 'cancel']) && $promise instanceof PromiseInterface)) { $promise->cancel(); } } diff --git a/tests/FunctionAwaitAllTest.php b/tests/FunctionAwaitAllTest.php index 9532657..7ef7054 100644 --- a/tests/FunctionAwaitAllTest.php +++ b/tests/FunctionAwaitAllTest.php @@ -34,8 +34,10 @@ public function testAwaitAllRejected() Block\awaitAll($all, $this->loop); } - public function testAwaitAllRejectedWithFalseWillWrapInUnexpectedValueException() + public function testAwaitAllRejectedWithExceptionWillWrapInUnexpectedValueException() { + $this->skipForPromise3(); + $all = array( $this->createPromiseResolved(1), Promise\reject(false) diff --git a/tests/FunctionAwaitAnyTest.php b/tests/FunctionAwaitAnyTest.php index faded88..7db083a 100644 --- a/tests/FunctionAwaitAnyTest.php +++ b/tests/FunctionAwaitAnyTest.php @@ -18,7 +18,7 @@ public function testAwaitAnyEmpty() public function testAwaitAnyFirstResolved() { $all = array( - $this->createPromiseRejected(1), + $this->createPromiseRejected(new \Exception(1)), $this->createPromiseResolved(2, 0.01), $this->createPromiseResolved(3, 0.02) ); @@ -33,7 +33,7 @@ public function testAwaitAnyFirstResolvedConcurrently() $d3 = new Deferred(); $this->loop->addTimer(0.01, function() use ($d1, $d2, $d3) { - $d1->reject(1); + $d1->reject(new \Exception(1)); $d2->resolve(2); $d3->resolve(3); }); @@ -50,8 +50,8 @@ public function testAwaitAnyFirstResolvedConcurrently() public function testAwaitAnyAllRejected() { $all = array( - $this->createPromiseRejected(1), - $this->createPromiseRejected(2) + $this->createPromiseRejected(new \Exception(1)), + $this->createPromiseRejected(new \Exception(2)) ); $this->setExpectedException('UnderflowException'); diff --git a/tests/FunctionAwaitTest.php b/tests/FunctionAwaitTest.php index d50736d..0d3725f 100644 --- a/tests/FunctionAwaitTest.php +++ b/tests/FunctionAwaitTest.php @@ -18,6 +18,7 @@ public function testAwaitOneRejected() public function testAwaitOneRejectedWithFalseWillWrapInUnexpectedValueException() { + $this->skipForPromise3(); $promise = Promise\reject(false); $this->setExpectedException('UnexpectedValueException', 'Promise rejected with unexpected value of type bool'); @@ -26,6 +27,7 @@ public function testAwaitOneRejectedWithFalseWillWrapInUnexpectedValueException( public function testAwaitOneRejectedWithNullWillWrapInUnexpectedValueException() { + $this->skipForPromise3(); $promise = Promise\reject(null); $this->setExpectedException('UnexpectedValueException', 'Promise rejected with unexpected value of type NULL'); @@ -153,6 +155,7 @@ public function testAwaitOneRejectedWithTimeoutShouldNotCreateAnyGarbageReferenc public function testAwaitNullValueShouldNotCreateAnyGarbageReferences() { + $this->skipForPromise3(); if (class_exists('React\Promise\When') && PHP_VERSION_ID >= 50400) { $this->markTestSkipped('Not supported on legacy Promise v1 API with PHP 5.4+'); } diff --git a/tests/TestCase.php b/tests/TestCase.php index 6ef25bc..c22768b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -17,6 +17,19 @@ public function setUpLoop() $this->loop = \React\EventLoop\Factory::create(); } + /** + * Skips a test if the test suite is running with react/promise version + * 3.0 or later. + * + * @return void + */ + protected function skipForPromise3() + { + if (! class_exists('React\Promise\CancellablePromiseInterface')) { + $this->markTestSkipped('Test is not supported/required by the Promise v3 API.'); + } + } + protected function createPromiseResolved($value = null, $delay = 0.01) { $deferred = new Deferred(); From 6757d994ec6e8e65f51bde7d526d9962873ce5fb Mon Sep 17 00:00:00 2001 From: David Cole Date: Tue, 23 Feb 2021 13:28:55 +1300 Subject: [PATCH 2/9] CancellablePromiseInterface is an interface, not a class --- tests/TestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index c22768b..d0b02ef 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -25,7 +25,7 @@ public function setUpLoop() */ protected function skipForPromise3() { - if (! class_exists('React\Promise\CancellablePromiseInterface')) { + if (! interface_exists('React\Promise\CancellablePromiseInterface')) { $this->markTestSkipped('Test is not supported/required by the Promise v3 API.'); } } From ed86a7b89fbfdef7d7a2053fffe69f09268b0b92 Mon Sep 17 00:00:00 2001 From: David Cole Date: Tue, 23 Feb 2021 17:34:24 +1300 Subject: [PATCH 3/9] Changed the way promises were cancelled See https://github.com/reactphp/promise/pull/75#issuecomment-270373856 --- src/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/functions.php b/src/functions.php index 8d2db1b..8c9cd0a 100644 --- a/src/functions.php +++ b/src/functions.php @@ -283,8 +283,8 @@ function awaitAll(array $promises, LoopInterface $loop, $timeout = null) function _cancelAllPromises(array $promises) { foreach ($promises as $promise) { - if ($promise instanceof CancellablePromiseInterface || (is_callable([$promise, 'cancel']) && $promise instanceof PromiseInterface)) { - $promise->cancel(); + if ($promise instanceof PromiseInterface) { + Promise\resolve($promise)->cancel(); } } } From 6430badff1a0651303e219647f5fa830f53a6f28 Mon Sep 17 00:00:00 2001 From: David Cole Date: Wed, 24 Feb 2021 10:09:17 +1300 Subject: [PATCH 4/9] Changed `react/promise` version to allow 3.0 and below --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e9224eb..2779eb2 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "require": { "php": ">=5.3", "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5", - "react/promise": "dev-master as 2.9.9", + "react/promise": "^3.0 || ^2.7 || ^1.2.1", "react/promise-timer": "^1.5" }, "require-dev": { From a3fcb95be290c1ca5d318489fe6ddf0b70a204e7 Mon Sep 17 00:00:00 2001 From: David Cole Date: Fri, 26 Feb 2021 15:01:15 +1300 Subject: [PATCH 5/9] Change promise cancelling to be consistent with other React projects --- src/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/functions.php b/src/functions.php index 8c9cd0a..4394f12 100644 --- a/src/functions.php +++ b/src/functions.php @@ -283,8 +283,8 @@ function awaitAll(array $promises, LoopInterface $loop, $timeout = null) function _cancelAllPromises(array $promises) { foreach ($promises as $promise) { - if ($promise instanceof PromiseInterface) { - Promise\resolve($promise)->cancel(); + if ($promise instanceof CancellablePromiseInterface || (! \interface_exists(CancellablePromiseInterface::class) && \method_exists($promise, 'cancel'))) { + $promise->cancel(); } } } From c91da1f16a24a82a4e4c06c4c1e6e57aa30aa423 Mon Sep 17 00:00:00 2001 From: David Cole Date: Fri, 26 Feb 2021 15:03:29 +1300 Subject: [PATCH 6/9] Reverted accidental test name change --- tests/FunctionAwaitAllTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FunctionAwaitAllTest.php b/tests/FunctionAwaitAllTest.php index 7ef7054..338e81a 100644 --- a/tests/FunctionAwaitAllTest.php +++ b/tests/FunctionAwaitAllTest.php @@ -34,7 +34,7 @@ public function testAwaitAllRejected() Block\awaitAll($all, $this->loop); } - public function testAwaitAllRejectedWithExceptionWillWrapInUnexpectedValueException() + public function testAwaitAllRejectedWithFalseWillWrapInUnexpectedValueException() { $this->skipForPromise3(); From b38731c38a6d596e61f53e66ca4ce826e8f90f61 Mon Sep 17 00:00:00 2001 From: David Cole Date: Fri, 26 Feb 2021 15:06:39 +1300 Subject: [PATCH 7/9] Added reasons when skipping tests for Promise v3 --- tests/FunctionAwaitAllTest.php | 2 +- tests/FunctionAwaitTest.php | 6 +++--- tests/TestCase.php | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/FunctionAwaitAllTest.php b/tests/FunctionAwaitAllTest.php index 338e81a..de29ec6 100644 --- a/tests/FunctionAwaitAllTest.php +++ b/tests/FunctionAwaitAllTest.php @@ -36,7 +36,7 @@ public function testAwaitAllRejected() public function testAwaitAllRejectedWithFalseWillWrapInUnexpectedValueException() { - $this->skipForPromise3(); + $this->skipForPromise3('Promises must reject with an exception, so this case cannot happen.'); $all = array( $this->createPromiseResolved(1), diff --git a/tests/FunctionAwaitTest.php b/tests/FunctionAwaitTest.php index 0d3725f..8207ff7 100644 --- a/tests/FunctionAwaitTest.php +++ b/tests/FunctionAwaitTest.php @@ -18,7 +18,7 @@ public function testAwaitOneRejected() public function testAwaitOneRejectedWithFalseWillWrapInUnexpectedValueException() { - $this->skipForPromise3(); + $this->skipForPromise3('Promises must reject with an exception, so this case cannot happen.'); $promise = Promise\reject(false); $this->setExpectedException('UnexpectedValueException', 'Promise rejected with unexpected value of type bool'); @@ -27,7 +27,7 @@ public function testAwaitOneRejectedWithFalseWillWrapInUnexpectedValueException( public function testAwaitOneRejectedWithNullWillWrapInUnexpectedValueException() { - $this->skipForPromise3(); + $this->skipForPromise3('Promises must reject with an exception, so this case cannot happen.'); $promise = Promise\reject(null); $this->setExpectedException('UnexpectedValueException', 'Promise rejected with unexpected value of type NULL'); @@ -155,7 +155,7 @@ public function testAwaitOneRejectedWithTimeoutShouldNotCreateAnyGarbageReferenc public function testAwaitNullValueShouldNotCreateAnyGarbageReferences() { - $this->skipForPromise3(); + $this->skipForPromise3('Promises must reject with an exception, so this case cannot happen.'); if (class_exists('React\Promise\When') && PHP_VERSION_ID >= 50400) { $this->markTestSkipped('Not supported on legacy Promise v1 API with PHP 5.4+'); } diff --git a/tests/TestCase.php b/tests/TestCase.php index d0b02ef..0ae1ec6 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -20,13 +20,15 @@ public function setUpLoop() /** * Skips a test if the test suite is running with react/promise version * 3.0 or later. + * + * @param string $reason * * @return void */ - protected function skipForPromise3() + protected function skipForPromise3($reason) { if (! interface_exists('React\Promise\CancellablePromiseInterface')) { - $this->markTestSkipped('Test is not supported/required by the Promise v3 API.'); + $this->markTestSkipped('Test is not supported/required by the Promise v3 API: '.$reason); } } From 96f3e35305d796c583de48f0ec58792f5bd2abb6 Mon Sep 17 00:00:00 2001 From: David Cole Date: Fri, 26 Feb 2021 15:08:27 +1300 Subject: [PATCH 8/9] Create exceptions with strings as the message --- tests/FunctionAwaitAnyTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/FunctionAwaitAnyTest.php b/tests/FunctionAwaitAnyTest.php index 7db083a..61151e9 100644 --- a/tests/FunctionAwaitAnyTest.php +++ b/tests/FunctionAwaitAnyTest.php @@ -18,7 +18,7 @@ public function testAwaitAnyEmpty() public function testAwaitAnyFirstResolved() { $all = array( - $this->createPromiseRejected(new \Exception(1)), + $this->createPromiseRejected(new \Exception('1')), $this->createPromiseResolved(2, 0.01), $this->createPromiseResolved(3, 0.02) ); @@ -33,7 +33,7 @@ public function testAwaitAnyFirstResolvedConcurrently() $d3 = new Deferred(); $this->loop->addTimer(0.01, function() use ($d1, $d2, $d3) { - $d1->reject(new \Exception(1)); + $d1->reject(new \Exception('1')); $d2->resolve(2); $d3->resolve(3); }); @@ -50,8 +50,8 @@ public function testAwaitAnyFirstResolvedConcurrently() public function testAwaitAnyAllRejected() { $all = array( - $this->createPromiseRejected(new \Exception(1)), - $this->createPromiseRejected(new \Exception(2)) + $this->createPromiseRejected(new \Exception('1')), + $this->createPromiseRejected(new \Exception('2')) ); $this->setExpectedException('UnderflowException'); From d3d5a360c98bc867c1ff60f98441d5141a323c97 Mon Sep 17 00:00:00 2001 From: David Cole Date: Fri, 26 Feb 2021 16:11:47 +1300 Subject: [PATCH 9/9] Removed ::class modifier for cancel(); } }