From e191e8ab2f42d0b3cb2fe33e7cefeb5e4b74693d Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 17:47:43 +0400 Subject: [PATCH 01/15] chore: Update metafiles --- .editorconfig | 21 +++++++++++++++++++++ .gitattributes | 14 ++++++++------ .gitignore | 7 ++++++- composer.json | 9 ++++++--- phpunit.xml.legacy | 29 ----------------------------- 5 files changed, 41 insertions(+), 39 deletions(-) create mode 100644 .editorconfig delete mode 100644 phpunit.xml.legacy diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..20d4cdf --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.yaml] +indent_size = 2 + +[*.yml] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.gitattributes b/.gitattributes index 21be40c..90e0fc5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,8 @@ -/.gitattributes export-ignore -/.github/ export-ignore -/.gitignore export-ignore -/phpunit.xml.dist export-ignore -/phpunit.xml.legacy export-ignore -/tests/ export-ignore +* text=auto + +/.* export-ignore +/tests export-ignore +/phpunit.xml* export-ignore +/psalm.* export-ignore +/psalm-baseline.xml export-ignore +/infection.* export-ignore diff --git a/.gitignore b/.gitignore index c8153b5..1ae5173 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ -/composer.lock +/.* +!/.github/ +/runtime/ /vendor/ +/.env +/composer.lock +*.log diff --git a/composer.json b/composer.json index a18bbf6..8d7789f 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "react/promise", + "name": "internal/promise", "description": "A lightweight implementation of CommonJS Promises/A for PHP", "license": "MIT", "authors": [ @@ -25,10 +25,13 @@ } ], "require": { - "php": ">=5.4.0" + "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + "phpunit/phpunit": "^9.6" + }, + "replace": { + "react/promise": "^2.0" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.legacy b/phpunit.xml.legacy deleted file mode 100644 index 7297f8d..0000000 --- a/phpunit.xml.legacy +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - ./tests/ - - - - - ./src/ - - ./src/functions_include.php - - - - - - - - - - - - From 3fda7b256158e8b01b7cb0a0ddfc53a33bc0bab2 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 18:19:08 +0400 Subject: [PATCH 02/15] chore: Rename LICENSE to LICENSE.md and update README.md with new documentation structure --- LICENSE => LICENSE.md | 0 README.md | 894 ++---------------------------------------- documentation.md | 828 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 859 insertions(+), 863 deletions(-) rename LICENSE => LICENSE.md (100%) create mode 100644 documentation.md diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/README.md b/README.md index fd233c4..5752ca6 100644 --- a/README.md +++ b/README.md @@ -1,875 +1,43 @@ -Promise -======= +# Promise -A lightweight implementation of -[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. +A lightweight implementation of [CommonJS Promises/A][CommonJS Promises/A] for PHP. -[![CI status](https://github.com/reactphp/promise/actions/workflows/ci.yml/badge.svg?branch=2.x)](https://github.com/reactphp/promise/actions) -[![installs on Packagist](https://img.shields.io/packagist/dt/react/promise?color=blue&label=installs%20on%20Packagist)](https://packagist.org/packages/react/promise) +> [!NOTE] +> This is a fork of [reactphp/promise][reactphp/promise] with the following improvements: +> - PHP 8.1+ compatibility +> - `@yield` annotations in promise interfaces +> - Enhanced type annotations +> - Replaces `react/promise` v2 -Table of Contents ------------------ +## Install -1. [Introduction](#introduction) -2. [Concepts](#concepts) - * [Deferred](#deferred) - * [Promise](#promise-1) -3. [API](#api) - * [Deferred](#deferred-1) - * [Deferred::promise()](#deferredpromise) - * [Deferred::resolve()](#deferredresolve) - * [Deferred::reject()](#deferredreject) - * [Deferred::notify()](#deferrednotify) - * [PromiseInterface](#promiseinterface) - * [PromiseInterface::then()](#promiseinterfacethen) - * [ExtendedPromiseInterface](#extendedpromiseinterface) - * [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone) - * [ExtendedPromiseInterface::otherwise()](#extendedpromiseinterfaceotherwise) - * [ExtendedPromiseInterface::always()](#extendedpromiseinterfacealways) - * [ExtendedPromiseInterface::progress()](#extendedpromiseinterfaceprogress) - * [CancellablePromiseInterface](#cancellablepromiseinterface) - * [CancellablePromiseInterface::cancel()](#cancellablepromiseinterfacecancel) - * [Promise](#promise-2) - * [FulfilledPromise](#fulfilledpromise) - * [RejectedPromise](#rejectedpromise) - * [LazyPromise](#lazypromise) - * [Functions](#functions) - * [resolve()](#resolve) - * [reject()](#reject) - * [all()](#all) - * [race()](#race) - * [any()](#any) - * [some()](#some) - * [map()](#map) - * [reduce()](#reduce) - * [PromisorInterface](#promisorinterface) -4. [Examples](#examples) - * [How to use Deferred](#how-to-use-deferred) - * [How promise forwarding works](#how-promise-forwarding-works) - * [Resolution forwarding](#resolution-forwarding) - * [Rejection forwarding](#rejection-forwarding) - * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding) - * [Progress event forwarding](#progress-event-forwarding) - * [done() vs. then()](#done-vs-then) -5. [Install](#install) -6. [Credits](#credits) -7. [License](#license) - -Introduction ------------- - -Promise is a library implementing -[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. - -It also provides several other useful promise-related concepts, such as joining -multiple promises and mapping and reducing collections of promises. - -If you've never heard about promises before, -[read this first](https://gist.github.com/3889970). - -Concepts --------- - -### Deferred - -A **Deferred** represents a computation or unit of work that may not have -completed yet. Typically (but not always), that computation will be something -that executes asynchronously and completes at some point in the future. - -### Promise - -While a deferred represents the computation itself, a **Promise** represents -the result of that computation. Thus, each deferred has a promise that acts as -a placeholder for its actual result. - -API ---- - -### Deferred - -A deferred represents an operation whose resolution is pending. It has separate -promise and resolver parts. - -```php -$deferred = new React\Promise\Deferred(); - -$promise = $deferred->promise(); - -$deferred->resolve(mixed $value = null); -$deferred->reject(mixed $reason = null); -$deferred->notify(mixed $update = null); -``` - -The `promise` method returns the promise of the deferred. - -The `resolve` and `reject` methods control the state of the deferred. - -The deprecated `notify` method is for progress notification. - -The constructor of the `Deferred` accepts an optional `$canceller` argument. -See [Promise](#promise-2) for more information. - -#### Deferred::promise() - -```php -$promise = $deferred->promise(); -``` - -Returns the promise of the deferred, which you can hand out to others while -keeping the authority to modify its state to yourself. - -#### Deferred::resolve() - -```php -$deferred->resolve(mixed $value = null); -``` - -Resolves the promise returned by `promise()`. All consumers are notified by -having `$onFulfilled` (which they registered via `$promise->then()`) called with -`$value`. - -If `$value` itself is a promise, the promise will transition to the state of -this promise once it is resolved. - -#### Deferred::reject() - -```php -$deferred->reject(mixed $reason = null); -``` - -Rejects the promise returned by `promise()`, signalling that the deferred's -computation failed. -All consumers are notified by having `$onRejected` (which they registered via -`$promise->then()`) called with `$reason`. - -If `$reason` itself is a promise, the promise will be rejected with the outcome -of this promise regardless whether it fulfills or rejects. - -#### Deferred::notify() - -> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore. - -```php -$deferred->notify(mixed $update = null); -``` - -Triggers progress notifications, to indicate to consumers that the computation -is making progress toward its result. - -All consumers are notified by having `$onProgress` (which they registered via -`$promise->then()`) called with `$update`. - -### PromiseInterface - -The promise interface provides the common interface for all promise -implementations. - -A promise represents an eventual outcome, which is either fulfillment (success) -and an associated value, or rejection (failure) and an associated reason. - -Once in the fulfilled or rejected state, a promise becomes immutable. -Neither its state nor its result (or error) can be modified. - -#### Implementations - -* [Promise](#promise-2) -* [FulfilledPromise](#fulfilledpromise) (deprecated) -* [RejectedPromise](#rejectedpromise) (deprecated) -* [LazyPromise](#lazypromise) (deprecated) - -#### PromiseInterface::then() - -```php -$transformedPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); -``` - -Transforms a promise's value by applying a function to the promise's fulfillment -or rejection value. Returns a new promise for the transformed result. - -The `then()` method registers new fulfilled, rejection and progress handlers -with a promise (all parameters are optional): - - * `$onFulfilled` will be invoked once the promise is fulfilled and passed - the result as the first argument. - * `$onRejected` will be invoked once the promise is rejected and passed the - reason as the first argument. - * `$onProgress` (deprecated) will be invoked whenever the producer of the promise - triggers progress notifications and passed a single argument (whatever it - wants) to indicate progress. - -It returns a new promise that will fulfill with the return value of either -`$onFulfilled` or `$onRejected`, whichever is called, or will reject with -the thrown exception if either throws. - -A promise makes the following guarantees about handlers registered in -the same call to `then()`: - - 1. Only one of `$onFulfilled` or `$onRejected` will be called, - never both. - 2. `$onFulfilled` and `$onRejected` will never be called more - than once. - 3. `$onProgress` (deprecated) may be called multiple times. - -#### See also - -* [resolve()](#resolve) - Creating a resolved promise -* [reject()](#reject) - Creating a rejected promise -* [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone) -* [done() vs. then()](#done-vs-then) - -### ExtendedPromiseInterface - -The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut -and utility methods which are not part of the Promises/A specification. - -#### Implementations - -* [Promise](#promise-1) -* [FulfilledPromise](#fulfilledpromise) (deprecated) -* [RejectedPromise](#rejectedpromise) (deprecated) -* [LazyPromise](#lazypromise) (deprecated) - -#### ExtendedPromiseInterface::done() - -```php -$promise->done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); -``` - -Consumes the promise's ultimate value if the promise fulfills, or handles the -ultimate error. - -It will cause a fatal error if either `$onFulfilled` or `$onRejected` throw or -return a rejected promise. - -Since the purpose of `done()` is consumption rather than transformation, -`done()` always returns `null`. - -#### See also - -* [PromiseInterface::then()](#promiseinterfacethen) -* [done() vs. then()](#done-vs-then) - -#### ExtendedPromiseInterface::otherwise() - -```php -$promise->otherwise(callable $onRejected); -``` - -Registers a rejection handler for promise. It is a shortcut for: - -```php -$promise->then(null, $onRejected); -``` - -Additionally, you can type hint the `$reason` argument of `$onRejected` to catch -only specific errors. - -```php -$promise - ->otherwise(function (\RuntimeException $reason) { - // Only catch \RuntimeException instances - // All other types of errors will propagate automatically - }) - ->otherwise(function ($reason) { - // Catch other errors - )}; -``` - -#### ExtendedPromiseInterface::always() - -```php -$newPromise = $promise->always(callable $onFulfilledOrRejected); -``` - -Allows you to execute "cleanup" type tasks in a promise chain. - -It arranges for `$onFulfilledOrRejected` to be called, with no arguments, -when the promise is either fulfilled or rejected. - -* If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully, - `$newPromise` will fulfill with the same value as `$promise`. -* If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a - rejected promise, `$newPromise` will reject with the thrown exception or - rejected promise's reason. -* If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully, - `$newPromise` will reject with the same reason as `$promise`. -* If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a - 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 -synchronous catch/finally pair. - -Consider the following synchronous code: - -```php -try { - return doSomething(); -} catch(\Exception $e) { - return handleError($e); -} finally { - cleanup(); -} -``` - -Similar asynchronous code (with `doSomething()` that returns a promise) can be -written: - -```php -return doSomething() - ->otherwise('handleError') - ->always('cleanup'); -``` - -#### ExtendedPromiseInterface::progress() - -> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore. - -```php -$promise->progress(callable $onProgress); -``` - -Registers a handler for progress updates from promise. It is a shortcut for: - -```php -$promise->then(null, null, $onProgress); -``` - -### CancellablePromiseInterface - -A cancellable promise provides a mechanism for consumers to notify the creator -of the promise that they are not longer interested in the result of an -operation. - -#### CancellablePromiseInterface::cancel() - -``` php -$promise->cancel(); -``` - -The `cancel()` method notifies the creator of the promise that there is no -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. - -#### Implementations - -* [Promise](#promise-1) -* [FulfilledPromise](#fulfilledpromise) (deprecated) -* [RejectedPromise](#rejectedpromise) (deprecated) -* [LazyPromise](#lazypromise) (deprecated) - -### Promise - -Creates a promise whose state is controlled by the functions passed to -`$resolver`. - -```php -$resolver = function (callable $resolve, callable $reject, callable $notify) { - // Do some work, possibly asynchronously, and then - // resolve or reject. You can notify of progress events (deprecated) - // along the way if you want/need. - - $resolve($awesomeResult); - // or throw new Exception('Promise rejected'); - // or $resolve($anotherPromise); - // or $reject($nastyError); - // or $notify($progressNotification); -}; - -$canceller = function () { - // Cancel/abort any running operations like network connections, streams etc. - - // Reject promise by throwing an exception - throw new Exception('Promise cancelled'); -}; - -$promise = new React\Promise\Promise($resolver, $canceller); -``` - -The promise constructor receives a resolver function and an optional canceller -function which both will be called with 3 arguments: - - * `$resolve($value)` - Primary function that seals the fate of the - returned promise. Accepts either a non-promise value, or another promise. - When called with a non-promise value, fulfills promise with that value. - When called with another promise, e.g. `$resolve($otherPromise)`, promise's - fate will be equivalent to that of `$otherPromise`. - * `$reject($reason)` - Function that rejects the promise. It is recommended to - just throw an exception instead of using `$reject()`. - * `$notify($update)` - Deprecated function that issues progress events for the promise. - -If the resolver or canceller throw an exception, the promise will be rejected -with that thrown exception as the rejection reason. - -The resolver function will be called immediately, the canceller function only -once all consumers called the `cancel()` method of the promise. - -### FulfilledPromise - -> Deprecated in v2.8.0: External usage of `FulfilledPromise` is deprecated, use `resolve()` instead. - -Creates a already fulfilled promise. - -```php -$promise = React\Promise\FulfilledPromise($value); -``` - -Note, that `$value` **cannot** be a promise. It's recommended to use -[resolve()](#resolve) for creating resolved promises. - -### RejectedPromise - -> Deprecated in v2.8.0: External usage of `RejectedPromise` is deprecated, use `reject()` instead. - -Creates a already rejected promise. - -```php -$promise = React\Promise\RejectedPromise($reason); -``` - -Note, that `$reason` **cannot** be a promise. It's recommended to use -[reject()](#reject) for creating rejected promises. - -### LazyPromise - -> Deprecated in v2.8.0: LazyPromise is deprecated and should not be used anymore. - -Creates a promise which will be lazily initialized by `$factory` once a consumer -calls the `then()` method. - -```php -$factory = function () { - $deferred = new React\Promise\Deferred(); - - // Do some heavy stuff here and resolve the deferred once completed - - return $deferred->promise(); -}; - -$promise = new React\Promise\LazyPromise($factory); - -// $factory will only be executed once we call then() -$promise->then(function ($value) { -}); -``` - -### Functions - -Useful functions for creating, joining, mapping and reducing collections of -promises. - -All functions working on promise collections (like `all()`, `race()`, `some()` -etc.) support cancellation. This means, if you call `cancel()` on the returned -promise, all promises in the collection are cancelled. If the collection itself -is a promise which resolves to an array, this promise is also cancelled. - -#### resolve() - -```php -$promise = React\Promise\resolve(mixed $promiseOrValue); -``` - -Creates a promise for the supplied `$promiseOrValue`. - -If `$promiseOrValue` is a value, it will be the resolution value of the -returned promise. - -If `$promiseOrValue` is a thenable (any object that provides a `then()` method), -a trusted promise that follows the state of the thenable is returned. - -If `$promiseOrValue` is a promise, it will be returned as is. - -Note: The promise returned is always a promise implementing -[ExtendedPromiseInterface](#extendedpromiseinterface). If you pass in a custom -promise which only implements [PromiseInterface](#promiseinterface), this -promise will be assimilated to a extended promise following `$promiseOrValue`. - -#### reject() - -```php -$promise = React\Promise\reject(mixed $promiseOrValue); -``` - -Creates a rejected promise for the supplied `$promiseOrValue`. - -If `$promiseOrValue` is a value, it will be the rejection value of the -returned promise. - -If `$promiseOrValue` is a promise, its completion value will be the rejected -value of the returned promise. - -This can be useful in situations where you need to reject a promise without -throwing an exception. For example, it allows you to propagate a rejection with -the value of another promise. - -#### all() - -```php -$promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues); -``` - -Returns a promise that will resolve only once all the items in -`$promisesOrValues` have resolved. The resolution value of the returned promise -will be an array containing the resolution values of each of the items in -`$promisesOrValues`. - -#### race() - -```php -$promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues); -``` - -Initiates a competitive race that allows one winner. Returns a promise which is -resolved in the same way the first settled promise resolves. - -#### any() - -```php -$promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues); -``` - -Returns a promise that will resolve when any one of the items in -`$promisesOrValues` resolves. The resolution value of the returned promise -will be the resolution value of the triggering item. - -The returned promise will only reject if *all* items in `$promisesOrValues` are -rejected. The rejection value will be an array of all rejection reasons. - -The returned promise will also reject with a `React\Promise\Exception\LengthException` -if `$promisesOrValues` contains 0 items. - -#### some() - -```php -$promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany); -``` - -Returns a promise that will resolve when `$howMany` of the supplied items in -`$promisesOrValues` resolve. The resolution value of the returned promise -will be an array of length `$howMany` containing the resolution values of the -triggering items. - -The returned promise will reject if it becomes impossible for `$howMany` items -to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items -reject). The rejection value will be an array of -`(count($promisesOrValues) - $howMany) + 1` rejection reasons. - -The returned promise will also reject with a `React\Promise\Exception\LengthException` -if `$promisesOrValues` contains less items than `$howMany`. - -#### map() - -```php -$promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc); -``` - -Traditional map function, similar to `array_map()`, but allows input to contain -promises and/or values, and `$mapFunc` may return either a value or a promise. - -The map function receives each item as argument, where item is a fully resolved -value of a promise or value in `$promisesOrValues`. - -#### reduce() - -```php -$promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null); -``` - -Traditional reduce function, similar to `array_reduce()`, but input may contain -promises and/or values, and `$reduceFunc` may return either a value or a -promise, *and* `$initialValue` may be a promise or a value for the starting -value. - -### PromisorInterface - -The `React\Promise\PromisorInterface` provides a common interface for objects -that provide a promise. `React\Promise\Deferred` implements it, but since it -is part of the public API anyone can implement it. - -Examples --------- - -### How to use Deferred - -```php -function getAwesomeResultPromise() -{ - $deferred = new React\Promise\Deferred(); - - // Execute a Node.js-style function using the callback pattern - computeAwesomeResultAsynchronously(function ($error, $result) use ($deferred) { - if ($error) { - $deferred->reject($error); - } else { - $deferred->resolve($result); - } - }); - - // Return the promise - return $deferred->promise(); -} - -getAwesomeResultPromise() - ->then( - function ($value) { - // Deferred resolved, do something with $value - }, - function ($reason) { - // Deferred rejected, do something with $reason - }, - function ($update) { - // Progress notification triggered, do something with $update - } - ); -``` - -### How promise forwarding works - -A few simple examples to show how the mechanics of Promises/A forwarding works. -These examples are contrived, of course, and in real usage, promise chains will -typically be spread across several function calls, or even several levels of -your application architecture. - -#### Resolution forwarding - -Resolved promises forward resolution values to the next promise. -The first promise, `$deferred->promise()`, will resolve with the value passed -to `$deferred->resolve()` below. - -Each call to `then()` returns a new promise that will resolve with the return -value of the previous handler. This creates a promise "pipeline". - -```php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->then(function ($x) { - // $x will be the value passed to $deferred->resolve() below - // and returns a *new promise* for $x + 1 - return $x + 1; - }) - ->then(function ($x) { - // $x === 2 - // This handler receives the return value of the - // previous handler. - return $x + 1; - }) - ->then(function ($x) { - // $x === 3 - // This handler receives the return value of the - // previous handler. - return $x + 1; - }) - ->then(function ($x) { - // $x === 4 - // This handler receives the return value of the - // previous handler. - echo 'Resolve ' . $x; - }); - -$deferred->resolve(1); // Prints "Resolve 4" -``` - -#### Rejection forwarding - -Rejected promises behave similarly, and also work similarly to try/catch: -When you catch an exception, you must rethrow for it to propagate. - -Similarly, when you handle a rejected promise, to propagate the rejection, -"rethrow" it by either returning a rejected promise, or actually throwing -(since promise translates thrown exceptions into rejections) - -```php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->then(function ($x) { - throw new \Exception($x + 1); - }) - ->otherwise(function (\Exception $x) { - // Propagate the rejection - throw $x; - }) - ->otherwise(function (\Exception $x) { - // Can also propagate by returning another rejection - return React\Promise\reject( - new \Exception($x->getMessage() + 1) - ); - }) - ->otherwise(function ($x) { - echo 'Reject ' . $x->getMessage(); // 3 - }); - -$deferred->resolve(1); // Prints "Reject 3" -``` - -#### Mixed resolution and rejection forwarding - -Just like try/catch, you can choose to propagate or not. Mixing resolutions and -rejections will still forward handler results in a predictable way. - -```php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->then(function ($x) { - return $x + 1; - }) - ->then(function ($x) { - throw new \Exception($x + 1); - }) - ->otherwise(function (\Exception $x) { - // Handle the rejection, and don't propagate. - // This is like catch without a rethrow - return $x->getMessage() + 1; - }) - ->then(function ($x) { - echo 'Mixed ' . $x; // 4 - }); - -$deferred->resolve(1); // Prints "Mixed 4" -``` - -#### Progress event forwarding - -> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore. - -In the same way as resolution and rejection handlers, your progress handler -**MUST** return a progress event to be propagated to the next link in the chain. -If you return nothing, `null` will be propagated. - -Also in the same way as resolutions and rejections, if you don't register a -progress handler, the update will be propagated through. - -If your progress handler throws an exception, the exception will be propagated -to the next link in the chain. The best thing to do is to ensure your progress -handlers do not throw exceptions. - -This gives you the opportunity to transform progress events at each step in the -chain so that they are meaningful to the next step. It also allows you to choose -not to transform them, and simply let them propagate untransformed, by not -registering a progress handler. - -```php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->progress(function ($update) { - return $update + 1; - }) - ->progress(function ($update) { - echo 'Progress ' . $update; // 2 - }); - -$deferred->notify(1); // Prints "Progress 2" -``` - -### done() vs. then() - -The golden rule is: - - Either return your promise, or call done() on it. - -At a first glance, `then()` and `done()` seem very similar. However, there are -important distinctions. - -The intent of `then()` is to transform a promise's value and to pass or return -a new promise for the transformed value along to other parts of your code. - -The intent of `done()` is to consume a promise's value, transferring -responsibility for the value to your code. - -In addition to transforming a value, `then()` allows you to recover from, or -propagate intermediate errors. Any errors that are not handled will be caught -by the promise machinery and used to reject the promise returned by `then()`. - -Calling `done()` transfers all responsibility for errors to your code. If an -error (either a thrown exception or returned rejection) escapes the -`$onFulfilled` or `$onRejected` callbacks you provide to done, it will be -rethrown in an uncatchable way causing a fatal error. - -```php -function getJsonResult() -{ - return queryApi() - ->then( - // Transform API results to an object - function ($jsonResultString) { - return json_decode($jsonResultString); - }, - // Transform API errors to an exception - function ($jsonErrorString) { - $object = json_decode($jsonErrorString); - throw new ApiErrorException($object->errorMessage); - } - ); -} - -// Here we provide no rejection handler. If the promise returned has been -// rejected, the ApiErrorException will be thrown -getJsonResult() - ->done( - // Consume transformed object - function ($jsonResultObject) { - // Do something with $jsonResultObject - } - ); - -// Here we provide a rejection handler which will either throw while debugging -// or log the exception -getJsonResult() - ->done( - function ($jsonResultObject) { - // Do something with $jsonResultObject - }, - function (ApiErrorException $exception) { - if (isDebug()) { - throw $exception; - } else { - logException($exception); - } - } - ); -``` - -Note that if a rejection value is not an instance of `\Exception`, it will be -wrapped in an exception of the type `React\Promise\UnhandledRejectionException`. - -You can get the original rejection reason by calling `$exception->getReason()`. - -Install -------- - -The recommended way to install this library is [through Composer](https://getcomposer.org). -[New to Composer?](https://getcomposer.org/doc/00-intro.md) - -This project follows [SemVer](https://semver.org/). -This will install the latest supported version: +The recommended way to install this library is [through Composer][Composer]. ```bash -composer require react/promise:^2.11 +composer require internal/promise ``` -See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades. - -This project aims to run on any platform and thus does not require any PHP -extensions and supports running on legacy PHP 5.4 through current PHP 8+ and HHVM. -It's *highly recommended to use the latest supported PHP version* for this project. - -Credits -------- +[![PHP](https://img.shields.io/packagist/php-v/internal/promise.svg?style=flat-square&logo=php)](https://packagist.org/packages/internal/promise) +[![Latest Version on Packagist](https://img.shields.io/packagist/v/internal/promise.svg?style=flat-square&logo=packagist)](https://packagist.org/packages/internal/promise) +[![License](https://img.shields.io/packagist/l/internal/promise.svg?style=flat-square)](LICENSE.md) +[![Total Downloads](https://img.shields.io/packagist/dt/internal/promise.svg?style=flat-square)](https://packagist.org/packages/buggregator/trap) -Promise is a port of [when.js](https://github.com/cujojs/when) -by [Brian Cavalier](https://github.com/briancavalier). +## Credits -Also, large parts of the documentation have been ported from the when.js -[Wiki](https://github.com/cujojs/when/wiki) and the -[API docs](https://github.com/cujojs/when/blob/master/docs/api.md). +This fork is based on [reactphp/promise][reactphp/promise], which is a port of [when.js][when.js] +by [Brian Cavalier][Brian Cavalier]. -License -------- +Also, large parts of the [documentation][documentation] have been ported from the when.js +[Wiki][Wiki] and the +[API docs][API docs]. -Released under the [MIT](LICENSE) license. +[documentation]: documentation.md +[CommonJS Promises/A]: http://wiki.commonjs.org/wiki/Promises/A +[CI status]: https://img.shields.io/github/actions/workflow/status/internal/promise/ci.yml?branch=2.x +[CI status link]: https://github.com/internal/promise/actions +[installs]: https://img.shields.io/packagist/dt/internal/promise?color=blue&label=installs%20on%20Packagist +[packagist link]: https://packagist.org/packages/internal/promise +[Composer]: https://getcomposer.org +[when.js]: https://github.com/cujojs/when +[Brian Cavalier]: https://github.com/briancavalier +[reactphp/promise]: https://github.com/reactphp/promise diff --git a/documentation.md b/documentation.md new file mode 100644 index 0000000..9c74277 --- /dev/null +++ b/documentation.md @@ -0,0 +1,828 @@ +# Promise + +A lightweight implementation of [CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. + +## Table of Contents + +1. [Introduction](#introduction) +2. [Concepts](#concepts) + * [Deferred](#deferred) + * [Promise](#promise-1) +3. [API](#api) + * [Deferred](#deferred-1) + * [Deferred::promise()](#deferredpromise) + * [Deferred::resolve()](#deferredresolve) + * [Deferred::reject()](#deferredreject) + * [Deferred::notify()](#deferrednotify) + * [PromiseInterface](#promiseinterface) + * [PromiseInterface::then()](#promiseinterfacethen) + * [ExtendedPromiseInterface](#extendedpromiseinterface) + * [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone) + * [ExtendedPromiseInterface::otherwise()](#extendedpromiseinterfaceotherwise) + * [ExtendedPromiseInterface::always()](#extendedpromiseinterfacealways) + * [ExtendedPromiseInterface::progress()](#extendedpromiseinterfaceprogress) + * [CancellablePromiseInterface](#cancellablepromiseinterface) + * [CancellablePromiseInterface::cancel()](#cancellablepromiseinterfacecancel) + * [Promise](#promise-2) + * [FulfilledPromise](#fulfilledpromise) + * [RejectedPromise](#rejectedpromise) + * [LazyPromise](#lazypromise) + * [Functions](#functions) + * [resolve()](#resolve) + * [reject()](#reject) + * [all()](#all) + * [race()](#race) + * [any()](#any) + * [some()](#some) + * [map()](#map) + * [reduce()](#reduce) + * [PromisorInterface](#promisorinterface) +4. [Examples](#examples) + * [How to use Deferred](#how-to-use-deferred) + * [How promise forwarding works](#how-promise-forwarding-works) + * [Resolution forwarding](#resolution-forwarding) + * [Rejection forwarding](#rejection-forwarding) + * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding) + * [Progress event forwarding](#progress-event-forwarding) + * [done() vs. then()](#done-vs-then) + +## Introduction + +Promise is a library implementing +[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. + +It also provides several other useful promise-related concepts, such as joining +multiple promises and mapping and reducing collections of promises. + +If you've never heard about promises before, +[read this first](https://gist.github.com/3889970). + +## Concepts + +### Deferred + +A **Deferred** represents a computation or unit of work that may not have +completed yet. Typically (but not always), that computation will be something +that executes asynchronously and completes at some point in the future. + +### Promise + +While a deferred represents the computation itself, a **Promise** represents +the result of that computation. Thus, each deferred has a promise that acts as +a placeholder for its actual result. + +## API + +### Deferred + +A deferred represents an operation whose resolution is pending. It has separate +promise and resolver parts. + +```php +$deferred = new React\Promise\Deferred(); + +$promise = $deferred->promise(); + +$deferred->resolve(mixed $value = null); +$deferred->reject(mixed $reason = null); +$deferred->notify(mixed $update = null); +``` + +The `promise` method returns the promise of the deferred. + +The `resolve` and `reject` methods control the state of the deferred. + +The deprecated `notify` method is for progress notification. + +The constructor of the `Deferred` accepts an optional `$canceller` argument. +See [Promise](#promise-2) for more information. + +#### Deferred::promise() + +```php +$promise = $deferred->promise(); +``` + +Returns the promise of the deferred, which you can hand out to others while +keeping the authority to modify its state to yourself. + +#### Deferred::resolve() + +```php +$deferred->resolve(mixed $value = null); +``` + +Resolves the promise returned by `promise()`. All consumers are notified by +having `$onFulfilled` (which they registered via `$promise->then()`) called with +`$value`. + +If `$value` itself is a promise, the promise will transition to the state of +this promise once it is resolved. + +#### Deferred::reject() + +```php +$deferred->reject(mixed $reason = null); +``` + +Rejects the promise returned by `promise()`, signalling that the deferred's +computation failed. +All consumers are notified by having `$onRejected` (which they registered via +`$promise->then()`) called with `$reason`. + +If `$reason` itself is a promise, the promise will be rejected with the outcome +of this promise regardless whether it fulfills or rejects. + +#### Deferred::notify() + +> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore. + +```php +$deferred->notify(mixed $update = null); +``` + +Triggers progress notifications, to indicate to consumers that the computation +is making progress toward its result. + +All consumers are notified by having `$onProgress` (which they registered via +`$promise->then()`) called with `$update`. + +### PromiseInterface + +The promise interface provides the common interface for all promise +implementations. + +A promise represents an eventual outcome, which is either fulfillment (success) +and an associated value, or rejection (failure) and an associated reason. + +Once in the fulfilled or rejected state, a promise becomes immutable. +Neither its state nor its result (or error) can be modified. + +#### Implementations + +* [Promise](#promise-2) +* [FulfilledPromise](#fulfilledpromise) (deprecated) +* [RejectedPromise](#rejectedpromise) (deprecated) +* [LazyPromise](#lazypromise) (deprecated) + +#### PromiseInterface::then() + +```php +$transformedPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); +``` + +Transforms a promise's value by applying a function to the promise's fulfillment +or rejection value. Returns a new promise for the transformed result. + +The `then()` method registers new fulfilled, rejection and progress handlers +with a promise (all parameters are optional): + + * `$onFulfilled` will be invoked once the promise is fulfilled and passed + the result as the first argument. + * `$onRejected` will be invoked once the promise is rejected and passed the + reason as the first argument. + * `$onProgress` (deprecated) will be invoked whenever the producer of the promise + triggers progress notifications and passed a single argument (whatever it + wants) to indicate progress. + +It returns a new promise that will fulfill with the return value of either +`$onFulfilled` or `$onRejected`, whichever is called, or will reject with +the thrown exception if either throws. + +A promise makes the following guarantees about handlers registered in +the same call to `then()`: + + 1. Only one of `$onFulfilled` or `$onRejected` will be called, + never both. + 2. `$onFulfilled` and `$onRejected` will never be called more + than once. + 3. `$onProgress` (deprecated) may be called multiple times. + +#### See also + +* [resolve()](#resolve) - Creating a resolved promise +* [reject()](#reject) - Creating a rejected promise +* [ExtendedPromiseInterface::done()](#extendedpromiseinterfacedone) +* [done() vs. then()](#done-vs-then) + +### ExtendedPromiseInterface + +The ExtendedPromiseInterface extends the PromiseInterface with useful shortcut +and utility methods which are not part of the Promises/A specification. + +#### Implementations + +* [Promise](#promise-1) +* [FulfilledPromise](#fulfilledpromise) (deprecated) +* [RejectedPromise](#rejectedpromise) (deprecated) +* [LazyPromise](#lazypromise) (deprecated) + +#### ExtendedPromiseInterface::done() + +```php +$promise->done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); +``` + +Consumes the promise's ultimate value if the promise fulfills, or handles the +ultimate error. + +It will cause a fatal error if either `$onFulfilled` or `$onRejected` throw or +return a rejected promise. + +Since the purpose of `done()` is consumption rather than transformation, +`done()` always returns `null`. + +#### See also + +* [PromiseInterface::then()](#promiseinterfacethen) +* [done() vs. then()](#done-vs-then) + +#### ExtendedPromiseInterface::otherwise() + +```php +$promise->otherwise(callable $onRejected); +``` + +Registers a rejection handler for promise. It is a shortcut for: + +```php +$promise->then(null, $onRejected); +``` + +Additionally, you can type hint the `$reason` argument of `$onRejected` to catch +only specific errors. + +```php +$promise + ->otherwise(function (\RuntimeException $reason) { + // Only catch \RuntimeException instances + // All other types of errors will propagate automatically + }) + ->otherwise(function ($reason) { + // Catch other errors + )}; +``` + +#### ExtendedPromiseInterface::always() + +```php +$newPromise = $promise->always(callable $onFulfilledOrRejected); +``` + +Allows you to execute "cleanup" type tasks in a promise chain. + +It arranges for `$onFulfilledOrRejected` to be called, with no arguments, +when the promise is either fulfilled or rejected. + +* If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully, + `$newPromise` will fulfill with the same value as `$promise`. +* If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a + rejected promise, `$newPromise` will reject with the thrown exception or + rejected promise's reason. +* If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully, + `$newPromise` will reject with the same reason as `$promise`. +* If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a + 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 +synchronous catch/finally pair. + +Consider the following synchronous code: + +```php +try { + return doSomething(); +} catch(\Exception $e) { + return handleError($e); +} finally { + cleanup(); +} +``` + +Similar asynchronous code (with `doSomething()` that returns a promise) can be +written: + +```php +return doSomething() + ->otherwise('handleError') + ->always('cleanup'); +``` + +#### ExtendedPromiseInterface::progress() + +> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore. + +```php +$promise->progress(callable $onProgress); +``` + +Registers a handler for progress updates from promise. It is a shortcut for: + +```php +$promise->then(null, null, $onProgress); +``` + +### CancellablePromiseInterface + +A cancellable promise provides a mechanism for consumers to notify the creator +of the promise that they are not longer interested in the result of an +operation. + +#### CancellablePromiseInterface::cancel() + +``` php +$promise->cancel(); +``` + +The `cancel()` method notifies the creator of the promise that there is no +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. + +#### Implementations + +* [Promise](#promise-1) +* [FulfilledPromise](#fulfilledpromise) (deprecated) +* [RejectedPromise](#rejectedpromise) (deprecated) +* [LazyPromise](#lazypromise) (deprecated) + +### Promise + +Creates a promise whose state is controlled by the functions passed to +`$resolver`. + +```php +$resolver = function (callable $resolve, callable $reject, callable $notify) { + // Do some work, possibly asynchronously, and then + // resolve or reject. You can notify of progress events (deprecated) + // along the way if you want/need. + + $resolve($awesomeResult); + // or throw new Exception('Promise rejected'); + // or $resolve($anotherPromise); + // or $reject($nastyError); + // or $notify($progressNotification); +}; + +$canceller = function () { + // Cancel/abort any running operations like network connections, streams etc. + + // Reject promise by throwing an exception + throw new Exception('Promise cancelled'); +}; + +$promise = new React\Promise\Promise($resolver, $canceller); +``` + +The promise constructor receives a resolver function and an optional canceller +function which both will be called with 3 arguments: + + * `$resolve($value)` - Primary function that seals the fate of the + returned promise. Accepts either a non-promise value, or another promise. + When called with a non-promise value, fulfills promise with that value. + When called with another promise, e.g. `$resolve($otherPromise)`, promise's + fate will be equivalent to that of `$otherPromise`. + * `$reject($reason)` - Function that rejects the promise. It is recommended to + just throw an exception instead of using `$reject()`. + * `$notify($update)` - Deprecated function that issues progress events for the promise. + +If the resolver or canceller throw an exception, the promise will be rejected +with that thrown exception as the rejection reason. + +The resolver function will be called immediately, the canceller function only +once all consumers called the `cancel()` method of the promise. + +### FulfilledPromise + +> Deprecated in v2.8.0: External usage of `FulfilledPromise` is deprecated, use `resolve()` instead. + +Creates a already fulfilled promise. + +```php +$promise = React\Promise\FulfilledPromise($value); +``` + +Note, that `$value` **cannot** be a promise. It's recommended to use +[resolve()](#resolve) for creating resolved promises. + +### RejectedPromise + +> Deprecated in v2.8.0: External usage of `RejectedPromise` is deprecated, use `reject()` instead. + +Creates a already rejected promise. + +```php +$promise = React\Promise\RejectedPromise($reason); +``` + +Note, that `$reason` **cannot** be a promise. It's recommended to use +[reject()](#reject) for creating rejected promises. + +### LazyPromise + +> Deprecated in v2.8.0: LazyPromise is deprecated and should not be used anymore. + +Creates a promise which will be lazily initialized by `$factory` once a consumer +calls the `then()` method. + +```php +$factory = function () { + $deferred = new React\Promise\Deferred(); + + // Do some heavy stuff here and resolve the deferred once completed + + return $deferred->promise(); +}; + +$promise = new React\Promise\LazyPromise($factory); + +// $factory will only be executed once we call then() +$promise->then(function ($value) { +}); +``` + +### Functions + +Useful functions for creating, joining, mapping and reducing collections of +promises. + +All functions working on promise collections (like `all()`, `race()`, `some()` +etc.) support cancellation. This means, if you call `cancel()` on the returned +promise, all promises in the collection are cancelled. If the collection itself +is a promise which resolves to an array, this promise is also cancelled. + +#### resolve() + +```php +$promise = React\Promise\resolve(mixed $promiseOrValue); +``` + +Creates a promise for the supplied `$promiseOrValue`. + +If `$promiseOrValue` is a value, it will be the resolution value of the +returned promise. + +If `$promiseOrValue` is a thenable (any object that provides a `then()` method), +a trusted promise that follows the state of the thenable is returned. + +If `$promiseOrValue` is a promise, it will be returned as is. + +Note: The promise returned is always a promise implementing +[ExtendedPromiseInterface](#extendedpromiseinterface). If you pass in a custom +promise which only implements [PromiseInterface](#promiseinterface), this +promise will be assimilated to a extended promise following `$promiseOrValue`. + +#### reject() + +```php +$promise = React\Promise\reject(mixed $promiseOrValue); +``` + +Creates a rejected promise for the supplied `$promiseOrValue`. + +If `$promiseOrValue` is a value, it will be the rejection value of the +returned promise. + +If `$promiseOrValue` is a promise, its completion value will be the rejected +value of the returned promise. + +This can be useful in situations where you need to reject a promise without +throwing an exception. For example, it allows you to propagate a rejection with +the value of another promise. + +#### all() + +```php +$promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues); +``` + +Returns a promise that will resolve only once all the items in +`$promisesOrValues` have resolved. The resolution value of the returned promise +will be an array containing the resolution values of each of the items in +`$promisesOrValues`. + +#### race() + +```php +$promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues); +``` + +Initiates a competitive race that allows one winner. Returns a promise which is +resolved in the same way the first settled promise resolves. + +#### any() + +```php +$promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues); +``` + +Returns a promise that will resolve when any one of the items in +`$promisesOrValues` resolves. The resolution value of the returned promise +will be the resolution value of the triggering item. + +The returned promise will only reject if *all* items in `$promisesOrValues` are +rejected. The rejection value will be an array of all rejection reasons. + +The returned promise will also reject with a `React\Promise\Exception\LengthException` +if `$promisesOrValues` contains 0 items. + +#### some() + +```php +$promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany); +``` + +Returns a promise that will resolve when `$howMany` of the supplied items in +`$promisesOrValues` resolve. The resolution value of the returned promise +will be an array of length `$howMany` containing the resolution values of the +triggering items. + +The returned promise will reject if it becomes impossible for `$howMany` items +to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items +reject). The rejection value will be an array of +`(count($promisesOrValues) - $howMany) + 1` rejection reasons. + +The returned promise will also reject with a `React\Promise\Exception\LengthException` +if `$promisesOrValues` contains less items than `$howMany`. + +#### map() + +```php +$promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc); +``` + +Traditional map function, similar to `array_map()`, but allows input to contain +promises and/or values, and `$mapFunc` may return either a value or a promise. + +The map function receives each item as argument, where item is a fully resolved +value of a promise or value in `$promisesOrValues`. + +#### reduce() + +```php +$promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null); +``` + +Traditional reduce function, similar to `array_reduce()`, but input may contain +promises and/or values, and `$reduceFunc` may return either a value or a +promise, *and* `$initialValue` may be a promise or a value for the starting +value. + +### PromisorInterface + +The `React\Promise\PromisorInterface` provides a common interface for objects +that provide a promise. `React\Promise\Deferred` implements it, but since it +is part of the public API anyone can implement it. + +## Examples + +### How to use Deferred + +```php +function getAwesomeResultPromise() +{ + $deferred = new React\Promise\Deferred(); + + // Execute a Node.js-style function using the callback pattern + computeAwesomeResultAsynchronously(function ($error, $result) use ($deferred) { + if ($error) { + $deferred->reject($error); + } else { + $deferred->resolve($result); + } + }); + + // Return the promise + return $deferred->promise(); +} + +getAwesomeResultPromise() + ->then( + function ($value) { + // Deferred resolved, do something with $value + }, + function ($reason) { + // Deferred rejected, do something with $reason + }, + function ($update) { + // Progress notification triggered, do something with $update + } + ); +``` + +### How promise forwarding works + +A few simple examples to show how the mechanics of Promises/A forwarding works. +These examples are contrived, of course, and in real usage, promise chains will +typically be spread across several function calls, or even several levels of +your application architecture. + +#### Resolution forwarding + +Resolved promises forward resolution values to the next promise. +The first promise, `$deferred->promise()`, will resolve with the value passed +to `$deferred->resolve()` below. + +Each call to `then()` returns a new promise that will resolve with the return +value of the previous handler. This creates a promise "pipeline". + +```php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->then(function ($x) { + // $x will be the value passed to $deferred->resolve() below + // and returns a *new promise* for $x + 1 + return $x + 1; + }) + ->then(function ($x) { + // $x === 2 + // This handler receives the return value of the + // previous handler. + return $x + 1; + }) + ->then(function ($x) { + // $x === 3 + // This handler receives the return value of the + // previous handler. + return $x + 1; + }) + ->then(function ($x) { + // $x === 4 + // This handler receives the return value of the + // previous handler. + echo 'Resolve ' . $x; + }); + +$deferred->resolve(1); // Prints "Resolve 4" +``` + +#### Rejection forwarding + +Rejected promises behave similarly, and also work similarly to try/catch: +When you catch an exception, you must rethrow for it to propagate. + +Similarly, when you handle a rejected promise, to propagate the rejection, +"rethrow" it by either returning a rejected promise, or actually throwing +(since promise translates thrown exceptions into rejections) + +```php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->then(function ($x) { + throw new \Exception($x + 1); + }) + ->otherwise(function (\Exception $x) { + // Propagate the rejection + throw $x; + }) + ->otherwise(function (\Exception $x) { + // Can also propagate by returning another rejection + return React\Promise\reject( + new \Exception($x->getMessage() + 1) + ); + }) + ->otherwise(function ($x) { + echo 'Reject ' . $x->getMessage(); // 3 + }); + +$deferred->resolve(1); // Prints "Reject 3" +``` + +#### Mixed resolution and rejection forwarding + +Just like try/catch, you can choose to propagate or not. Mixing resolutions and +rejections will still forward handler results in a predictable way. + +```php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->then(function ($x) { + return $x + 1; + }) + ->then(function ($x) { + throw new \Exception($x + 1); + }) + ->otherwise(function (\Exception $x) { + // Handle the rejection, and don't propagate. + // This is like catch without a rethrow + return $x->getMessage() + 1; + }) + ->then(function ($x) { + echo 'Mixed ' . $x; // 4 + }); + +$deferred->resolve(1); // Prints "Mixed 4" +``` + +#### Progress event forwarding + +> Deprecated in v2.6.0: Progress support is deprecated and should not be used anymore. + +In the same way as resolution and rejection handlers, your progress handler +**MUST** return a progress event to be propagated to the next link in the chain. +If you return nothing, `null` will be propagated. + +Also in the same way as resolutions and rejections, if you don't register a +progress handler, the update will be propagated through. + +If your progress handler throws an exception, the exception will be propagated +to the next link in the chain. The best thing to do is to ensure your progress +handlers do not throw exceptions. + +This gives you the opportunity to transform progress events at each step in the +chain so that they are meaningful to the next step. It also allows you to choose +not to transform them, and simply let them propagate untransformed, by not +registering a progress handler. + +```php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->progress(function ($update) { + return $update + 1; + }) + ->progress(function ($update) { + echo 'Progress ' . $update; // 2 + }); + +$deferred->notify(1); // Prints "Progress 2" +``` + +### done() vs. then() + +The golden rule is: + + Either return your promise, or call done() on it. + +At a first glance, `then()` and `done()` seem very similar. However, there are +important distinctions. + +The intent of `then()` is to transform a promise's value and to pass or return +a new promise for the transformed value along to other parts of your code. + +The intent of `done()` is to consume a promise's value, transferring +responsibility for the value to your code. + +In addition to transforming a value, `then()` allows you to recover from, or +propagate intermediate errors. Any errors that are not handled will be caught +by the promise machinery and used to reject the promise returned by `then()`. + +Calling `done()` transfers all responsibility for errors to your code. If an +error (either a thrown exception or returned rejection) escapes the +`$onFulfilled` or `$onRejected` callbacks you provide to done, it will be +rethrown in an uncatchable way causing a fatal error. + +```php +function getJsonResult() +{ + return queryApi() + ->then( + // Transform API results to an object + function ($jsonResultString) { + return json_decode($jsonResultString); + }, + // Transform API errors to an exception + function ($jsonErrorString) { + $object = json_decode($jsonErrorString); + throw new ApiErrorException($object->errorMessage); + } + ); +} + +// Here we provide no rejection handler. If the promise returned has been +// rejected, the ApiErrorException will be thrown +getJsonResult() + ->done( + // Consume transformed object + function ($jsonResultObject) { + // Do something with $jsonResultObject + } + ); + +// Here we provide a rejection handler which will either throw while debugging +// or log the exception +getJsonResult() + ->done( + function ($jsonResultObject) { + // Do something with $jsonResultObject + }, + function (ApiErrorException $exception) { + if (isDebug()) { + throw $exception; + } else { + logException($exception); + } + } + ); +``` + +Note that if a rejection value is not an instance of `\Exception`, it will be +wrapped in an exception of the type `React\Promise\UnhandledRejectionException`. + +You can get the original rejection reason by calling `$exception->getReason()`. From 761a765f6ec62cb3a0db89723434947f65d8e6cd Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 18:40:43 +0400 Subject: [PATCH 03/15] tests: Update tests and PHPUnit to v10 --- composer.json | 17 +- tests/CancellationQueueTest.php | 26 +-- tests/DeferredTest.php | 70 ++++--- tests/FulfilledPromiseTest.php | 42 ++-- tests/FunctionAllTest.php | 34 +-- tests/FunctionAnyTest.php | 70 ++++--- tests/FunctionCheckTypehintTest.php | 157 ++++++-------- tests/FunctionMapTest.php | 102 ++++----- tests/FunctionRaceTest.php | 80 +++---- tests/FunctionReduceTest.php | 152 +++++++------- tests/FunctionRejectTest.php | 20 +- tests/FunctionResolveTest.php | 56 ++--- tests/FunctionSomeTest.php | 100 ++++----- tests/LazyPromiseTest.php | 28 +-- .../PromiseAdapter/CallbackPromiseAdapter.php | 14 +- .../PromiseAdapterInterface.php | 8 +- tests/PromiseTest.php | 196 +++++++++--------- tests/PromiseTest/CancelTestTrait.php | 96 ++++----- tests/PromiseTest/FullTestTrait.php | 18 +- tests/PromiseTest/NotifyTestTrait.php | 118 ++++++----- .../PromiseTest/PromiseFulfilledTestTrait.php | 120 +++++------ tests/PromiseTest/PromisePendingTestTrait.php | 38 ++-- .../PromiseTest/PromiseRejectedTestTrait.php | 180 ++++++++-------- tests/PromiseTest/PromiseSettledTestTrait.php | 46 ++-- tests/PromiseTest/RejectTestTrait.php | 128 ++++++------ tests/PromiseTest/ResolveTestTrait.php | 96 +++++---- tests/RejectedPromiseTest.php | 40 ++-- tests/TestCase.php | 16 +- tests/fixtures/ArrayAccessibleException.php | 6 +- .../CallbackWithIntersectionTypehintClass.php | 17 +- tests/fixtures/CallbackWithTypehintClass.php | 16 +- .../CallbackWithUnionTypehintClass.php | 17 +- .../fixtures/CallbackWithoutTypehintClass.php | 14 +- tests/fixtures/CountableException.php | 8 +- tests/fixtures/CountableNonException.php | 8 +- tests/fixtures/SimpleFulfilledTestPromise.php | 4 +- .../fixtures/SimpleFulfilledTestThenable.php | 4 +- tests/fixtures/SimpleRejectedTestPromise.php | 4 +- tests/fixtures/SimpleTestCancellable.php | 4 +- .../SimpleTestCancellableThenable.php | 6 +- 40 files changed, 1099 insertions(+), 1077 deletions(-) diff --git a/composer.json b/composer.json index 8d7789f..755ac23 100644 --- a/composer.json +++ b/composer.json @@ -2,6 +2,10 @@ "name": "internal/promise", "description": "A lightweight implementation of CommonJS Promises/A for PHP", "license": "MIT", + "keywords": [ + "promise", + "promises" + ], "authors": [ { "name": "Jan Sorgalla", @@ -28,7 +32,8 @@ "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^9.6" + "phpunit/phpunit": "^10.5.10", + "ta-tikoma/phpunit-architecture-test": "^0.8.5" }, "replace": { "react/promise": "^2.0" @@ -49,8 +54,10 @@ ] } }, - "keywords": [ - "promise", - "promises" - ] + "config": { + "audit": { + "abandoned": "report" + }, + "sort-packages": true + } } diff --git a/tests/CancellationQueueTest.php b/tests/CancellationQueueTest.php index 32cedf4..7899428 100644 --- a/tests/CancellationQueueTest.php +++ b/tests/CancellationQueueTest.php @@ -1,11 +1,13 @@ assertTrue($p->cancelCalled); } - /** @test */ - public function ignoresSimpleCancellable() + #[\PHPUnit\Framework\Attributes\Test] + public function ignoresSimpleCancellable(): void { $p = new SimpleTestCancellable(); @@ -30,8 +32,8 @@ public function ignoresSimpleCancellable() $this->assertFalse($p->cancelCalled); } - /** @test */ - public function callsCancelOnPromisesEnqueuedBeforeStart() + #[\PHPUnit\Framework\Attributes\Test] + public function callsCancelOnPromisesEnqueuedBeforeStart(): void { $d1 = $this->getCancellableDeferred(); $d2 = $this->getCancellableDeferred(); @@ -43,8 +45,8 @@ public function callsCancelOnPromisesEnqueuedBeforeStart() $cancellationQueue(); } - /** @test */ - public function callsCancelOnPromisesEnqueuedAfterStart() + #[\PHPUnit\Framework\Attributes\Test] + public function callsCancelOnPromisesEnqueuedAfterStart(): void { $d1 = $this->getCancellableDeferred(); $d2 = $this->getCancellableDeferred(); @@ -57,8 +59,8 @@ public function callsCancelOnPromisesEnqueuedAfterStart() $cancellationQueue->enqueue($d1->promise()); } - /** @test */ - public function doesNotCallCancelTwiceWhenStartedTwice() + #[\PHPUnit\Framework\Attributes\Test] + public function doesNotCallCancelTwiceWhenStartedTwice(): void { $d = $this->getCancellableDeferred(); @@ -69,8 +71,8 @@ public function doesNotCallCancelTwiceWhenStartedTwice() $cancellationQueue(); } - /** @test */ - public function rethrowsExceptionsThrownFromCancel() + #[\PHPUnit\Framework\Attributes\Test] + public function rethrowsExceptionsThrownFromCancel(): void { $this->setExpectedException('\Exception', 'test'); diff --git a/tests/DeferredTest.php b/tests/DeferredTest.php index b11199b..ef05304 100644 --- a/tests/DeferredTest.php +++ b/tests/DeferredTest.php @@ -1,5 +1,7 @@ progress($sentinel); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException(): void { - gc_collect_cycles(); - gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on + \gc_collect_cycles(); + \gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on - $deferred = new Deferred(function ($resolve, $reject) { + $deferred = new Deferred(static function ($resolve, $reject): void { $reject(new \Exception('foo')); }); $deferred->promise()->cancel(); unset($deferred); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfParentCancellerRejectsWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfParentCancellerRejectsWithException(): void { - gc_collect_cycles(); - gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on + \gc_collect_cycles(); + \gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on - $deferred = new Deferred(function ($resolve, $reject) { + $deferred = new Deferred(static function ($resolve, $reject): void { $reject(new \Exception('foo')); }); $deferred->promise()->then()->cancel(); unset($deferred); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndExplicitlyRejectWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndExplicitlyRejectWithException(): void { - gc_collect_cycles(); - $deferred = new Deferred(function () use (&$deferred) { }); + \gc_collect_cycles(); + $deferred = new Deferred(static function () use (&$deferred): void {}); $deferred->reject(new \Exception('foo')); unset($deferred); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingDeferred() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingDeferred(): void { - gc_collect_cycles(); + \gc_collect_cycles(); $deferred = new Deferred(); $deferred->promise(); unset($deferred); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingDeferredWithUnusedCanceller() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingDeferredWithUnusedCanceller(): void { - gc_collect_cycles(); - $deferred = new Deferred(function () { }); + \gc_collect_cycles(); + $deferred = new Deferred(static function (): void {}); $deferred->promise(); unset($deferred); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingDeferredWithNoopCanceller() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingDeferredWithNoopCanceller(): void { - gc_collect_cycles(); - $deferred = new Deferred(function () { }); + \gc_collect_cycles(); + $deferred = new Deferred(static function (): void {}); $deferred->promise()->cancel(); unset($deferred); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } } diff --git a/tests/FulfilledPromiseTest.php b/tests/FulfilledPromiseTest.php index d814c2a..7bedc4f 100644 --- a/tests/FulfilledPromiseTest.php +++ b/tests/FulfilledPromiseTest.php @@ -1,38 +1,40 @@ function () use (&$promise) { + 'promise' => static function () use (&$promise) { if (!$promise) { throw new \LogicException('FulfilledPromise must be resolved before obtaining the promise'); } return $promise; }, - 'resolve' => function ($value = null) use (&$promise) { + 'resolve' => static function ($value = null) use (&$promise): void { if (!$promise) { $promise = new FulfilledPromise($value); } }, - 'reject' => function () { + 'reject' => static function (): void { throw new \LogicException('You cannot call reject() for React\Promise\FulfilledPromise'); }, - 'notify' => function () { + 'notify' => static function (): void { // no-op }, - 'settle' => function ($value = null) use (&$promise) { + 'settle' => static function ($value = null) use (&$promise): void { if (!$promise) { $promise = new FulfilledPromise($value); } @@ -40,7 +42,7 @@ public function getPromiseTestAdapter(callable $canceller = null) ]); } - /** @test */ + #[\PHPUnit\Framework\Attributes\Test] public function shouldThrowExceptionIfConstructedWithAPromise() { $this->setExpectedException('\InvalidArgumentException'); @@ -48,31 +50,31 @@ public function shouldThrowExceptionIfConstructedWithAPromise() return new FulfilledPromise(new FulfilledPromise()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToFulfilledPromiseWithAlwaysFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToFulfilledPromiseWithAlwaysFollowers(): void { - gc_collect_cycles(); - gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on + \gc_collect_cycles(); + \gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on $promise = new FulfilledPromise(1); - $promise->always(function () { + $promise->always(static function (): void { throw new \RuntimeException(); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToFulfilledPromiseWithThenFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToFulfilledPromiseWithThenFollowers(): void { - gc_collect_cycles(); + \gc_collect_cycles(); $promise = new FulfilledPromise(1); - $promise = $promise->then(function () { + $promise = $promise->then(static function (): void { throw new \RuntimeException(); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } } diff --git a/tests/FunctionAllTest.php b/tests/FunctionAllTest.php index 74c1d7c..50f8807 100644 --- a/tests/FunctionAllTest.php +++ b/tests/FunctionAllTest.php @@ -1,11 +1,13 @@ createCallableMock(); $mock @@ -17,8 +19,8 @@ public function shouldResolveEmptyInput() ->then($mock); } - /** @test */ - public function shouldResolveValuesArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveValuesArray(): void { $mock = $this->createCallableMock(); $mock @@ -30,8 +32,8 @@ public function shouldResolveValuesArray() ->then($mock); } - /** @test */ - public function shouldResolvePromisesArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolvePromisesArray(): void { $mock = $this->createCallableMock(); $mock @@ -43,8 +45,8 @@ public function shouldResolvePromisesArray() ->then($mock); } - /** @test */ - public function shouldResolveSparseArrayInput() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveSparseArrayInput(): void { $mock = $this->createCallableMock(); $mock @@ -56,8 +58,8 @@ public function shouldResolveSparseArrayInput() ->then($mock); } - /** @test */ - public function shouldRejectIfAnyInputPromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectIfAnyInputPromiseRejects(): void { $mock = $this->createCallableMock(); $mock @@ -69,8 +71,8 @@ public function shouldRejectIfAnyInputPromiseRejects() ->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldAcceptAPromiseForAnArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptAPromiseForAnArray(): void { $mock = $this->createCallableMock(); $mock @@ -82,8 +84,8 @@ public function shouldAcceptAPromiseForAnArray() ->then($mock); } - /** @test */ - public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray(): void { $mock = $this->createCallableMock(); $mock @@ -95,8 +97,8 @@ public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() ->then($mock); } - /** @test */ - public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises(): void { $mock = $this->createCallableMock(); $mock diff --git a/tests/FunctionAnyTest.php b/tests/FunctionAnyTest.php index 140b551..ed90ae6 100644 --- a/tests/FunctionAnyTest.php +++ b/tests/FunctionAnyTest.php @@ -1,31 +1,33 @@ createCallableMock(); $mock ->expects($this->once()) ->method('__invoke') ->with( - $this->callback(function($exception){ + $this->callback(static function ($exception) { return $exception instanceof LengthException && - 'Input array must contain at least 1 item but contains only 0 items.' === $exception->getMessage(); - }) + $exception->getMessage() === 'Input array must contain at least 1 item but contains only 0 items.'; + }), ); any([]) ->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldResolveToNullWithNonArrayInput() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToNullWithNonArrayInput(): void { $mock = $this->createCallableMock(); $mock @@ -37,8 +39,8 @@ public function shouldResolveToNullWithNonArrayInput() ->then($mock); } - /** @test */ - public function shouldResolveWithAnInputValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveWithAnInputValue(): void { $mock = $this->createCallableMock(); $mock @@ -50,8 +52,8 @@ public function shouldResolveWithAnInputValue() ->then($mock); } - /** @test */ - public function shouldResolveWithAPromisedInputValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveWithAPromisedInputValue(): void { $mock = $this->createCallableMock(); $mock @@ -63,8 +65,8 @@ public function shouldResolveWithAPromisedInputValue() ->then($mock); } - /** @test */ - public function shouldRejectWithAllRejectedInputValuesIfAllInputsAreRejected() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithAllRejectedInputValuesIfAllInputsAreRejected(): void { $mock = $this->createCallableMock(); $mock @@ -76,8 +78,8 @@ public function shouldRejectWithAllRejectedInputValuesIfAllInputsAreRejected() ->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldResolveWhenFirstInputPromiseResolves() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveWhenFirstInputPromiseResolves(): void { $mock = $this->createCallableMock(); $mock @@ -89,8 +91,8 @@ public function shouldResolveWhenFirstInputPromiseResolves() ->then($mock); } - /** @test */ - public function shouldAcceptAPromiseForAnArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptAPromiseForAnArray(): void { $mock = $this->createCallableMock(); $mock @@ -102,8 +104,8 @@ public function shouldAcceptAPromiseForAnArray() ->then($mock); } - /** @test */ - public function shouldResolveToNullArrayWhenInputPromiseDoesNotResolveToArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToNullArrayWhenInputPromiseDoesNotResolveToArray(): void { $mock = $this->createCallableMock(); $mock @@ -115,8 +117,8 @@ public function shouldResolveToNullArrayWhenInputPromiseDoesNotResolveToArray() ->then($mock); } - /** @test */ - public function shouldNotRelyOnArryIndexesWhenUnwrappingToASingleResolutionValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotRelyOnArryIndexesWhenUnwrappingToASingleResolutionValue(): void { $mock = $this->createCallableMock(); $mock @@ -134,8 +136,8 @@ public function shouldNotRelyOnArryIndexesWhenUnwrappingToASingleResolutionValue $d1->resolve(1); } - /** @test */ - public function shouldRejectWhenInputPromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWhenInputPromiseRejects(): void { $mock = $this->createCallableMock(); $mock @@ -147,11 +149,11 @@ public function shouldRejectWhenInputPromiseRejects() ->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldCancelInputPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputPromise(): void { $mock = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock ->expects($this->once()) @@ -160,18 +162,18 @@ public function shouldCancelInputPromise() any($mock)->cancel(); } - /** @test */ - public function shouldCancelInputArrayPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputArrayPromises(): void { $mock1 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock1 ->expects($this->once()) ->method('cancel'); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->once()) @@ -180,8 +182,8 @@ public function shouldCancelInputArrayPromises() any([$mock1, $mock2])->cancel(); } - /** @test */ - public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseFulfills() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseFulfills(): void { $mock = $this->createCallableMock(); $mock @@ -189,11 +191,11 @@ public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseFulfill ->method('__invoke'); - $deferred = New Deferred($mock); + $deferred = new Deferred($mock); $deferred->resolve(); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->never()) diff --git a/tests/FunctionCheckTypehintTest.php b/tests/FunctionCheckTypehintTest.php index ed923d5..d8b8973 100644 --- a/tests/FunctionCheckTypehintTest.php +++ b/tests/FunctionCheckTypehintTest.php @@ -1,51 +1,49 @@ assertTrue(_checkTypehint(function (\InvalidArgumentException $e) { - }, new \InvalidArgumentException())); - $this->assertfalse(_checkTypehint(function (\InvalidArgumentException $e) { - }, new \Exception())); + $this->assertTrue(_checkTypehint(static function (\InvalidArgumentException $e): void {}, new \InvalidArgumentException())); + $this->assertfalse(_checkTypehint(static function (\InvalidArgumentException $e): void {}, new \Exception())); } - /** @test */ - public function shouldAcceptFunctionStringCallbackWithTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptFunctionStringCallbackWithTypehint(): void { $this->assertTrue(_checkTypehint('React\Promise\testCallbackWithTypehint', new \InvalidArgumentException())); $this->assertfalse(_checkTypehint('React\Promise\testCallbackWithTypehint', new \Exception())); } - /** @test */ - public function shouldAcceptInvokableObjectCallbackWithTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptInvokableObjectCallbackWithTypehint(): void { $this->assertTrue(_checkTypehint(new CallbackWithTypehintClass(), new \InvalidArgumentException())); $this->assertfalse(_checkTypehint(new CallbackWithTypehintClass(), new \Exception())); } - /** @test */ - public function shouldAcceptObjectMethodCallbackWithTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptObjectMethodCallbackWithTypehint(): void { $this->assertTrue(_checkTypehint([new CallbackWithTypehintClass(), 'testCallback'], new \InvalidArgumentException())); $this->assertfalse(_checkTypehint([new CallbackWithTypehintClass(), 'testCallback'], new \Exception())); } - /** @test */ - public function shouldAcceptStaticClassCallbackWithTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptStaticClassCallbackWithTypehint(): void { $this->assertTrue(_checkTypehint([new CallbackWithTypehintClass(), 'testCallbackStatic'], new \InvalidArgumentException())); $this->assertfalse(_checkTypehint([new CallbackWithTypehintClass(), 'testCallbackStatic'], new \Exception())); } - /** - * @test - * @requires PHP 8 - */ - public function shouldAcceptClosureCallbackWithUnionTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptClosureCallbackWithUnionTypehint(): void { eval( 'namespace React\Promise;' . @@ -54,138 +52,115 @@ public function shouldAcceptClosureCallbackWithUnionTypehint() ); } - /** - * @test - * @requires PHP 8 - */ - public function shouldAcceptInvokableObjectCallbackWithUnionTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptInvokableObjectCallbackWithUnionTypehint(): void { self::assertTrue(_checkTypehint(new CallbackWithUnionTypehintClass(), new \InvalidArgumentException())); self::assertFalse(_checkTypehint(new CallbackWithUnionTypehintClass(), new \Exception())); } - /** - * @test - * @requires PHP 8 - */ - public function shouldAcceptObjectMethodCallbackWithUnionTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptObjectMethodCallbackWithUnionTypehint(): void { self::assertTrue(_checkTypehint([new CallbackWithUnionTypehintClass(), 'testCallback'], new \InvalidArgumentException())); self::assertFalse(_checkTypehint([new CallbackWithUnionTypehintClass(), 'testCallback'], new \Exception())); } - /** - * @test - * @requires PHP 8 - */ - public function shouldAcceptStaticClassCallbackWithUnionTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptStaticClassCallbackWithUnionTypehint(): void { - self::assertTrue(_checkTypehint(['React\Promise\CallbackWithUnionTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException())); - self::assertFalse(_checkTypehint(['React\Promise\CallbackWithUnionTypehintClass', 'testCallbackStatic'], new \Exception())); + self::assertTrue(_checkTypehint([\React\Promise\CallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new \InvalidArgumentException())); + self::assertFalse(_checkTypehint([\React\Promise\CallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new \Exception())); } - /** - * @test - * @requires PHP 8.1 - */ - public function shouldAcceptInvokableObjectCallbackWithIntersectionTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8.1')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptInvokableObjectCallbackWithIntersectionTypehint(): void { self::assertFalse(_checkTypehint(new CallbackWithIntersectionTypehintClass(), new \RuntimeException())); self::assertFalse(_checkTypehint(new CallbackWithIntersectionTypehintClass(), new CountableNonException())); self::assertTrue(_checkTypehint(new CallbackWithIntersectionTypehintClass(), new CountableException())); } - /** - * @test - * @requires PHP 8.1 - */ - public function shouldAcceptObjectMethodCallbackWithIntersectionTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8.1')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptObjectMethodCallbackWithIntersectionTypehint(): void { self::assertFalse(_checkTypehint([new CallbackWithIntersectionTypehintClass(), 'testCallback'], new \RuntimeException())); self::assertFalse(_checkTypehint([new CallbackWithIntersectionTypehintClass(), 'testCallback'], new CountableNonException())); self::assertTrue(_checkTypehint([new CallbackWithIntersectionTypehintClass(), 'testCallback'], new CountableException())); } - /** - * @test - * @requires PHP 8.1 - */ - public function shouldAcceptStaticClassCallbackWithIntersectionTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8.1')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptStaticClassCallbackWithIntersectionTypehint(): void { - self::assertFalse(_checkTypehint(['React\Promise\CallbackWithIntersectionTypehintClass', 'testCallbackStatic'], new \RuntimeException())); - self::assertFalse(_checkTypehint(['React\Promise\CallbackWithIntersectionTypehintClass', 'testCallbackStatic'], new CountableNonException())); - self::assertTrue(_checkTypehint(['React\Promise\CallbackWithIntersectionTypehintClass', 'testCallbackStatic'], new CountableException())); + self::assertFalse(_checkTypehint([\React\Promise\CallbackWithIntersectionTypehintClass::class, 'testCallbackStatic'], new \RuntimeException())); + self::assertFalse(_checkTypehint([\React\Promise\CallbackWithIntersectionTypehintClass::class, 'testCallbackStatic'], new CountableNonException())); + self::assertTrue(_checkTypehint([\React\Promise\CallbackWithIntersectionTypehintClass::class, 'testCallbackStatic'], new CountableException())); } - /** - * @test - * @requires PHP 8.2 - */ - public function shouldAcceptInvokableObjectCallbackWithDNFTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8.2')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptInvokableObjectCallbackWithDNFTypehint(): void { self::assertFalse(_checkTypehint(new CallbackWithDNFTypehintClass(), new \RuntimeException())); self::assertTrue(_checkTypehint(new CallbackWithDNFTypehintClass(), new ArrayAccessibleException())); self::assertTrue(_checkTypehint(new CallbackWithDNFTypehintClass(), new CountableException())); } - /** - * @test - * @requires PHP 8.2 - */ - public function shouldAcceptObjectMethodCallbackWithDNFTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8.2')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptObjectMethodCallbackWithDNFTypehint(): void { self::assertFalse(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new \RuntimeException())); self::assertTrue(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new CountableException())); self::assertTrue(_checkTypehint([new CallbackWithDNFTypehintClass(), 'testCallback'], new ArrayAccessibleException())); } - /** - * @test - * @requires PHP 8.2 - */ - public function shouldAcceptStaticClassCallbackWithDNFTypehint() + #[\PHPUnit\Framework\Attributes\RequiresPhp('8.2')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptStaticClassCallbackWithDNFTypehint(): void { - self::assertFalse(_checkTypehint(['React\Promise\CallbackWithDNFTypehintClass', 'testCallbackStatic'], new \RuntimeException())); - self::assertTrue(_checkTypehint(['React\Promise\CallbackWithDNFTypehintClass', 'testCallbackStatic'], new CountableException())); - self::assertTrue(_checkTypehint(['React\Promise\CallbackWithDNFTypehintClass', 'testCallbackStatic'], new ArrayAccessibleException())); + self::assertFalse(_checkTypehint([\React\Promise\CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new \RuntimeException())); + self::assertTrue(_checkTypehint([\React\Promise\CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new CountableException())); + self::assertTrue(_checkTypehint([\React\Promise\CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new ArrayAccessibleException())); } - /** @test */ - public function shouldAcceptClosureCallbackWithoutTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptClosureCallbackWithoutTypehint(): void { - $this->assertTrue(_checkTypehint(function (\InvalidArgumentException $e) { - }, new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint(static function (\InvalidArgumentException $e): void {}, new \InvalidArgumentException())); } - /** @test */ - public function shouldAcceptFunctionStringCallbackWithoutTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptFunctionStringCallbackWithoutTypehint(): void { $this->assertTrue(_checkTypehint('React\Promise\testCallbackWithoutTypehint', new \InvalidArgumentException())); } - /** @test */ - public function shouldAcceptInvokableObjectCallbackWithoutTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptInvokableObjectCallbackWithoutTypehint(): void { $this->assertTrue(_checkTypehint(new CallbackWithoutTypehintClass(), new \InvalidArgumentException())); } - /** @test */ - public function shouldAcceptObjectMethodCallbackWithoutTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptObjectMethodCallbackWithoutTypehint(): void { $this->assertTrue(_checkTypehint([new CallbackWithoutTypehintClass(), 'testCallback'], new \InvalidArgumentException())); } - /** @test */ - public function shouldAcceptStaticClassCallbackWithoutTypehint() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptStaticClassCallbackWithoutTypehint(): void { - $this->assertTrue(_checkTypehint(['React\Promise\CallbackWithoutTypehintClass', 'testCallbackStatic'], new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint([\React\Promise\CallbackWithoutTypehintClass::class, 'testCallbackStatic'], new \InvalidArgumentException())); } } -function testCallbackWithTypehint(\InvalidArgumentException $e) -{ -} +function testCallbackWithTypehint(\InvalidArgumentException $e): void {} -function testCallbackWithoutTypehint() -{ -} +function testCallbackWithoutTypehint(): void {} diff --git a/tests/FunctionMapTest.php b/tests/FunctionMapTest.php index 1ea560a..7ff7ac9 100644 --- a/tests/FunctionMapTest.php +++ b/tests/FunctionMapTest.php @@ -1,25 +1,13 @@ createCallableMock(); $mock @@ -29,12 +17,12 @@ public function shouldMapInputValuesArray() map( [1, 2, 3], - $this->mapper() + $this->mapper(), )->then($mock); } - /** @test */ - public function shouldMapInputPromisesArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldMapInputPromisesArray(): void { $mock = $this->createCallableMock(); $mock @@ -44,12 +32,12 @@ public function shouldMapInputPromisesArray() map( [resolve(1), resolve(2), resolve(3)], - $this->mapper() + $this->mapper(), )->then($mock); } - /** @test */ - public function shouldMapMixedInputArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldMapMixedInputArray(): void { $mock = $this->createCallableMock(); $mock @@ -59,12 +47,12 @@ public function shouldMapMixedInputArray() map( [1, resolve(2), 3], - $this->mapper() + $this->mapper(), )->then($mock); } - /** @test */ - public function shouldMapInputWhenMapperReturnsAPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldMapInputWhenMapperReturnsAPromise(): void { $mock = $this->createCallableMock(); $mock @@ -74,12 +62,12 @@ public function shouldMapInputWhenMapperReturnsAPromise() map( [1, 2, 3], - $this->promiseMapper() + $this->promiseMapper(), )->then($mock); } - /** @test */ - public function shouldAcceptAPromiseForAnArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptAPromiseForAnArray(): void { $mock = $this->createCallableMock(); $mock @@ -89,12 +77,12 @@ public function shouldAcceptAPromiseForAnArray() map( resolve([1, resolve(2), 3]), - $this->mapper() + $this->mapper(), )->then($mock); } - /** @test */ - public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray(): void { $mock = $this->createCallableMock(); $mock @@ -104,12 +92,12 @@ public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() map( resolve(1), - $this->mapper() + $this->mapper(), )->then($mock); } - /** @test */ - public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises(): void { $mock = $this->createCallableMock(); $mock @@ -121,14 +109,14 @@ public function shouldPreserveTheOrderOfArrayWhenResolvingAsyncPromises() map( [resolve(1), $deferred->promise(), resolve(3)], - $this->mapper() + $this->mapper(), )->then($mock); $deferred->resolve(2); } - /** @test */ - public function shouldRejectWhenInputContainsRejection() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWhenInputContainsRejection(): void { $mock = $this->createCallableMock(); $mock @@ -138,12 +126,12 @@ public function shouldRejectWhenInputContainsRejection() map( [resolve(1), reject(2), resolve(3)], - $this->mapper() + $this->mapper(), )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldRejectWhenInputPromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWhenInputPromiseRejects(): void { $mock = $this->createCallableMock(); $mock @@ -153,15 +141,15 @@ public function shouldRejectWhenInputPromiseRejects() map( reject(), - $this->mapper() + $this->mapper(), )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldCancelInputPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputPromise(): void { $mock = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock ->expects($this->once()) @@ -169,22 +157,22 @@ public function shouldCancelInputPromise() map( $mock, - $this->mapper() + $this->mapper(), )->cancel(); } - /** @test */ - public function shouldCancelInputArrayPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputArrayPromises(): void { $mock1 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock1 ->expects($this->once()) ->method('cancel'); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->once()) @@ -192,7 +180,21 @@ public function shouldCancelInputArrayPromises() map( [$mock1, $mock2], - $this->mapper() + $this->mapper(), )->cancel(); } + + protected function mapper() + { + return static function ($val) { + return $val * 2; + }; + } + + protected function promiseMapper() + { + return static function ($val) { + return resolve($val * 2); + }; + } } diff --git a/tests/FunctionRaceTest.php b/tests/FunctionRaceTest.php index 83770ec..42984a2 100644 --- a/tests/FunctionRaceTest.php +++ b/tests/FunctionRaceTest.php @@ -1,11 +1,13 @@ createCallableMock(); $mock @@ -14,12 +16,12 @@ public function shouldResolveEmptyInput() ->with($this->identicalTo(null)); race( - [] + [], )->then($mock); } - /** @test */ - public function shouldResolveValuesArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveValuesArray(): void { $mock = $this->createCallableMock(); $mock @@ -28,12 +30,12 @@ public function shouldResolveValuesArray() ->with($this->identicalTo(1)); race( - [1, 2, 3] + [1, 2, 3], )->then($mock); } - /** @test */ - public function shouldResolvePromisesArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolvePromisesArray(): void { $mock = $this->createCallableMock(); $mock @@ -46,7 +48,7 @@ public function shouldResolvePromisesArray() $d3 = new Deferred(); race( - [$d1->promise(), $d2->promise(), $d3->promise()] + [$d1->promise(), $d2->promise(), $d3->promise()], )->then($mock); $d2->resolve(2); @@ -55,8 +57,8 @@ public function shouldResolvePromisesArray() $d3->resolve(3); } - /** @test */ - public function shouldResolveSparseArrayInput() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveSparseArrayInput(): void { $mock = $this->createCallableMock(); $mock @@ -65,12 +67,12 @@ public function shouldResolveSparseArrayInput() ->with($this->identicalTo(null)); race( - [null, 1, null, 2, 3] + [null, 1, null, 2, 3], )->then($mock); } - /** @test */ - public function shouldRejectIfFirstSettledPromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectIfFirstSettledPromiseRejects(): void { $mock = $this->createCallableMock(); $mock @@ -83,7 +85,7 @@ public function shouldRejectIfFirstSettledPromiseRejects() $d3 = new Deferred(); race( - [$d1->promise(), $d2->promise(), $d3->promise()] + [$d1->promise(), $d2->promise(), $d3->promise()], )->then($this->expectCallableNever(), $mock); $d2->reject(2); @@ -92,8 +94,8 @@ public function shouldRejectIfFirstSettledPromiseRejects() $d3->resolve(3); } - /** @test */ - public function shouldAcceptAPromiseForAnArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptAPromiseForAnArray(): void { $mock = $this->createCallableMock(); $mock @@ -102,12 +104,12 @@ public function shouldAcceptAPromiseForAnArray() ->with($this->identicalTo(1)); race( - resolve([1, 2, 3]) + resolve([1, 2, 3]), )->then($mock); } - /** @test */ - public function shouldResolveToNullWhenInputPromiseDoesNotResolveToArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToNullWhenInputPromiseDoesNotResolveToArray(): void { $mock = $this->createCallableMock(); $mock @@ -116,12 +118,12 @@ public function shouldResolveToNullWhenInputPromiseDoesNotResolveToArray() ->with($this->identicalTo(null)); race( - resolve(1) + resolve(1), )->then($mock); } - /** @test */ - public function shouldRejectWhenInputPromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWhenInputPromiseRejects(): void { $mock = $this->createCallableMock(); $mock @@ -130,15 +132,15 @@ public function shouldRejectWhenInputPromiseRejects() ->with($this->identicalTo(null)); race( - reject() + reject(), )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldCancelInputPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputPromise(): void { $mock = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock ->expects($this->once()) @@ -147,18 +149,18 @@ public function shouldCancelInputPromise() race($mock)->cancel(); } - /** @test */ - public function shouldCancelInputArrayPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputArrayPromises(): void { $mock1 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock1 ->expects($this->once()) ->method('cancel'); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->once()) @@ -167,19 +169,19 @@ public function shouldCancelInputArrayPromises() race([$mock1, $mock2])->cancel(); } - /** @test */ - public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseFulfills() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseFulfills(): void { $mock = $this->createCallableMock(); $mock ->expects($this->never()) ->method('__invoke'); - $deferred = New Deferred($mock); + $deferred = new Deferred($mock); $deferred->resolve(); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->never()) @@ -188,19 +190,19 @@ public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseFulfill race([$deferred->promise(), $mock2])->cancel(); } - /** @test */ - public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotCancelOtherPendingInputArrayPromisesIfOnePromiseRejects(): void { $mock = $this->createCallableMock(); $mock ->expects($this->never()) ->method('__invoke'); - $deferred = New Deferred($mock); + $deferred = new Deferred($mock); $deferred->reject(); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->never()) diff --git a/tests/FunctionReduceTest.php b/tests/FunctionReduceTest.php index 8b43a87..a15a743 100644 --- a/tests/FunctionReduceTest.php +++ b/tests/FunctionReduceTest.php @@ -1,25 +1,13 @@ createCallableMock(); $mock @@ -29,12 +17,12 @@ public function shouldReduceValuesWithoutInitialValue() reduce( [1, 2, 3], - $this->plus() + $this->plus(), )->then($mock); } - /** @test */ - public function shouldReduceValuesWithInitialValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReduceValuesWithInitialValue(): void { $mock = $this->createCallableMock(); $mock @@ -45,12 +33,12 @@ public function shouldReduceValuesWithInitialValue() reduce( [1, 2, 3], $this->plus(), - 1 + 1, )->then($mock); } - /** @test */ - public function shouldReduceValuesWithInitialPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReduceValuesWithInitialPromise(): void { $mock = $this->createCallableMock(); $mock @@ -61,12 +49,12 @@ public function shouldReduceValuesWithInitialPromise() reduce( [1, 2, 3], $this->plus(), - resolve(1) + resolve(1), )->then($mock); } - /** @test */ - public function shouldReducePromisedValuesWithoutInitialValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReducePromisedValuesWithoutInitialValue(): void { $mock = $this->createCallableMock(); $mock @@ -76,12 +64,12 @@ public function shouldReducePromisedValuesWithoutInitialValue() reduce( [resolve(1), resolve(2), resolve(3)], - $this->plus() + $this->plus(), )->then($mock); } - /** @test */ - public function shouldReducePromisedValuesWithInitialValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReducePromisedValuesWithInitialValue(): void { $mock = $this->createCallableMock(); $mock @@ -92,12 +80,12 @@ public function shouldReducePromisedValuesWithInitialValue() reduce( [resolve(1), resolve(2), resolve(3)], $this->plus(), - 1 + 1, )->then($mock); } - /** @test */ - public function shouldReducePromisedValuesWithInitialPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReducePromisedValuesWithInitialPromise(): void { $mock = $this->createCallableMock(); $mock @@ -108,12 +96,12 @@ public function shouldReducePromisedValuesWithInitialPromise() reduce( [resolve(1), resolve(2), resolve(3)], $this->plus(), - resolve(1) + resolve(1), )->then($mock); } - /** @test */ - public function shouldReduceEmptyInputWithInitialValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReduceEmptyInputWithInitialValue(): void { $mock = $this->createCallableMock(); $mock @@ -124,12 +112,12 @@ public function shouldReduceEmptyInputWithInitialValue() reduce( [], $this->plus(), - 1 + 1, )->then($mock); } - /** @test */ - public function shouldReduceEmptyInputWithInitialPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReduceEmptyInputWithInitialPromise(): void { $mock = $this->createCallableMock(); $mock @@ -140,12 +128,12 @@ public function shouldReduceEmptyInputWithInitialPromise() reduce( [], $this->plus(), - resolve(1) + resolve(1), )->then($mock); } - /** @test */ - public function shouldRejectWhenInputContainsRejection() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWhenInputContainsRejection(): void { $mock = $this->createCallableMock(); $mock @@ -156,12 +144,12 @@ public function shouldRejectWhenInputContainsRejection() reduce( [resolve(1), reject(2), resolve(3)], $this->plus(), - resolve(1) + resolve(1), )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldResolveWithNullWhenInputIsEmptyAndNoInitialValueOrPromiseProvided() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveWithNullWhenInputIsEmptyAndNoInitialValueOrPromiseProvided(): void { // Note: this is different from when.js's behavior! // In when.reduce(), this rejects with a TypeError exception (following @@ -175,12 +163,12 @@ public function shouldResolveWithNullWhenInputIsEmptyAndNoInitialValueOrPromiseP reduce( [], - $this->plus() + $this->plus(), )->then($mock); } - /** @test */ - public function shouldAllowSparseArrayInputWithoutInitialValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAllowSparseArrayInputWithoutInitialValue(): void { $mock = $this->createCallableMock(); $mock @@ -190,12 +178,12 @@ public function shouldAllowSparseArrayInputWithoutInitialValue() reduce( [null, null, 1, null, 1, 1], - $this->plus() + $this->plus(), )->then($mock); } - /** @test */ - public function shouldAllowSparseArrayInputWithInitialValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAllowSparseArrayInputWithInitialValue(): void { $mock = $this->createCallableMock(); $mock @@ -206,12 +194,12 @@ public function shouldAllowSparseArrayInputWithInitialValue() reduce( [null, null, 1, null, 1, 1], $this->plus(), - 1 + 1, )->then($mock); } - /** @test */ - public function shouldReduceInInputOrder() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReduceInInputOrder(): void { $mock = $this->createCallableMock(); $mock @@ -222,12 +210,12 @@ public function shouldReduceInInputOrder() reduce( [1, 2, 3], $this->append(), - '' + '', )->then($mock); } - /** @test */ - public function shouldAcceptAPromiseForAnArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptAPromiseForAnArray(): void { $mock = $this->createCallableMock(); $mock @@ -238,12 +226,12 @@ public function shouldAcceptAPromiseForAnArray() reduce( resolve([1, 2, 3]), $this->append(), - '' + '', )->then($mock); } - /** @test */ - public function shouldResolveToInitialValueWhenInputPromiseDoesNotResolveToAnArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToInitialValueWhenInputPromiseDoesNotResolveToAnArray(): void { $mock = $this->createCallableMock(); $mock @@ -254,14 +242,14 @@ public function shouldResolveToInitialValueWhenInputPromiseDoesNotResolveToAnArr reduce( resolve(1), $this->plus(), - 1 + 1, )->then($mock); } - /** @test */ - public function shouldProvideCorrectBasisValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldProvideCorrectBasisValue(): void { - $insertIntoArray = function ($arr, $val, $i) { + $insertIntoArray = static function ($arr, $val, $i) { $arr[$i] = $val; return $arr; @@ -280,7 +268,7 @@ public function shouldProvideCorrectBasisValue() reduce( [$d1->promise(), $d2->promise(), $d3->promise()], $insertIntoArray, - [] + [], )->then($mock); $d3->resolve(3); @@ -288,8 +276,8 @@ public function shouldProvideCorrectBasisValue() $d2->resolve(2); } - /** @test */ - public function shouldRejectWhenInputPromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWhenInputPromiseRejects(): void { $mock = $this->createCallableMock(); $mock @@ -300,15 +288,15 @@ public function shouldRejectWhenInputPromiseRejects() reduce( reject(), $this->plus(), - 1 + 1, )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldCancelInputPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputPromise(): void { $mock = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock ->expects($this->once()) @@ -317,22 +305,22 @@ public function shouldCancelInputPromise() reduce( $mock, $this->plus(), - 1 + 1, )->cancel(); } - /** @test */ - public function shouldCancelInputArrayPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputArrayPromises(): void { $mock1 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock1 ->expects($this->once()) ->method('cancel'); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->once()) @@ -341,7 +329,21 @@ public function shouldCancelInputArrayPromises() reduce( [$mock1, $mock2], $this->plus(), - 1 + 1, )->cancel(); } + + protected function plus() + { + return static function ($sum, $val) { + return $sum + $val; + }; + } + + protected function append() + { + return static function ($sum, $val) { + return $sum . $val; + }; + } } diff --git a/tests/FunctionRejectTest.php b/tests/FunctionRejectTest.php index 84b8ec6..4f5d427 100644 --- a/tests/FunctionRejectTest.php +++ b/tests/FunctionRejectTest.php @@ -1,11 +1,13 @@ then( $this->expectCallableNever(), - $mock + $mock, ); } - /** @test */ - public function shouldRejectAFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectAFulfilledPromise(): void { $expected = 123; @@ -38,12 +40,12 @@ public function shouldRejectAFulfilledPromise() reject($resolved) ->then( $this->expectCallableNever(), - $mock + $mock, ); } - /** @test */ - public function shouldRejectARejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectARejectedPromise(): void { $expected = 123; @@ -58,7 +60,7 @@ public function shouldRejectARejectedPromise() reject($resolved) ->then( $this->expectCallableNever(), - $mock + $mock, ); } } diff --git a/tests/FunctionResolveTest.php b/tests/FunctionResolveTest.php index 53126bc..eb5c0c7 100644 --- a/tests/FunctionResolveTest.php +++ b/tests/FunctionResolveTest.php @@ -1,11 +1,13 @@ then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function shouldResolveAFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveAFulfilledPromise(): void { $expected = 123; @@ -38,12 +40,12 @@ public function shouldResolveAFulfilledPromise() resolve($resolved) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function shouldResolveAThenable() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveAThenable(): void { $thenable = new SimpleFulfilledTestThenable(); @@ -56,12 +58,12 @@ public function shouldResolveAThenable() resolve($thenable) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function shouldResolveACancellableThenable() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveACancellableThenable(): void { $thenable = new SimpleTestCancellableThenable(); @@ -71,8 +73,8 @@ public function shouldResolveACancellableThenable() $this->assertTrue($thenable->cancelCalled); } - /** @test */ - public function shouldRejectARejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectARejectedPromise(): void { $expected = 123; @@ -87,28 +89,28 @@ public function shouldRejectARejectedPromise() resolve($resolved) ->then( $this->expectCallableNever(), - $mock + $mock, ); } - /** @test */ - public function shouldSupportDeepNestingInPromiseChains() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldSupportDeepNestingInPromiseChains(): void { $d = new Deferred(); $d->resolve(false); - $result = resolve(resolve($d->promise()->then(function ($val) { + $result = resolve(resolve($d->promise()->then(static function ($val) { $d = new Deferred(); $d->resolve($val); - $identity = function ($val) { + $identity = static function ($val) { return $val; }; return resolve($d->promise()->then($identity))->then( - function ($val) { + static function ($val) { return !$val; - } + }, ); }))); @@ -121,8 +123,8 @@ function ($val) { $result->then($mock); } - /** @test */ - public function shouldSupportVeryDeepNestedPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldSupportVeryDeepNestedPromises(): void { $deferreds = []; @@ -133,7 +135,7 @@ public function shouldSupportVeryDeepNestedPromises() $last = $p; for ($j = 0; $j < 10; $j++) { - $last = $last->then(function($result) { + $last = $last->then(static function ($result) { return $result; }); } @@ -159,13 +161,13 @@ public function shouldSupportVeryDeepNestedPromises() $deferreds[0]->promise()->then($mock); } - /** @test */ - public function returnsExtendePromiseForSimplePromise() + #[\PHPUnit\Framework\Attributes\Test] + public function returnsExtendePromiseForSimplePromise(): void { $promise = $this - ->getMockBuilder('React\Promise\PromiseInterface') + ->getMockBuilder(\React\Promise\PromiseInterface::class) ->getMock(); - $this->assertInstanceOf('React\Promise\ExtendedPromiseInterface', resolve($promise)); + $this->assertInstanceOf(\React\Promise\ExtendedPromiseInterface::class, resolve($promise)); } } diff --git a/tests/FunctionSomeTest.php b/tests/FunctionSomeTest.php index 276b54b..d3d9024 100644 --- a/tests/FunctionSomeTest.php +++ b/tests/FunctionSomeTest.php @@ -1,53 +1,55 @@ createCallableMock(); $mock ->expects($this->once()) ->method('__invoke') ->with( - $this->callback(function($exception){ + $this->callback(static function ($exception) { return $exception instanceof LengthException && - 'Input array must contain at least 1 item but contains only 0 items.' === $exception->getMessage(); - }) + $exception->getMessage() === 'Input array must contain at least 1 item but contains only 0 items.'; + }), ); some( [], - 1 + 1, )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldRejectWithLengthExceptionWithInputArrayContainingNotEnoughItems() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithLengthExceptionWithInputArrayContainingNotEnoughItems(): void { $mock = $this->createCallableMock(); $mock ->expects($this->once()) ->method('__invoke') ->with( - $this->callback(function($exception){ + $this->callback(static function ($exception) { return $exception instanceof LengthException && - 'Input array must contain at least 4 items but contains only 3 items.' === $exception->getMessage(); - }) + $exception->getMessage() === 'Input array must contain at least 4 items but contains only 3 items.'; + }), ); some( [1, 2, 3], - 4 + 4, )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldResolveToEmptyArrayWithNonArrayInput() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToEmptyArrayWithNonArrayInput(): void { $mock = $this->createCallableMock(); $mock @@ -57,12 +59,12 @@ public function shouldResolveToEmptyArrayWithNonArrayInput() some( null, - 1 + 1, )->then($mock); } - /** @test */ - public function shouldResolveValuesArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveValuesArray(): void { $mock = $this->createCallableMock(); $mock @@ -72,12 +74,12 @@ public function shouldResolveValuesArray() some( [1, 2, 3], - 2 + 2, )->then($mock); } - /** @test */ - public function shouldResolvePromisesArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolvePromisesArray(): void { $mock = $this->createCallableMock(); $mock @@ -87,12 +89,12 @@ public function shouldResolvePromisesArray() some( [resolve(1), resolve(2), resolve(3)], - 2 + 2, )->then($mock); } - /** @test */ - public function shouldResolveSparseArrayInput() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveSparseArrayInput(): void { $mock = $this->createCallableMock(); $mock @@ -102,12 +104,12 @@ public function shouldResolveSparseArrayInput() some( [null, 1, null, 2, 3], - 2 + 2, )->then($mock); } - /** @test */ - public function shouldRejectIfAnyInputPromiseRejectsBeforeDesiredNumberOfInputsAreResolved() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectIfAnyInputPromiseRejectsBeforeDesiredNumberOfInputsAreResolved(): void { $mock = $this->createCallableMock(); $mock @@ -117,12 +119,12 @@ public function shouldRejectIfAnyInputPromiseRejectsBeforeDesiredNumberOfInputsA some( [resolve(1), reject(2), reject(3)], - 2 + 2, )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldAcceptAPromiseForAnArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldAcceptAPromiseForAnArray(): void { $mock = $this->createCallableMock(); $mock @@ -132,12 +134,12 @@ public function shouldAcceptAPromiseForAnArray() some( resolve([1, 2, 3]), - 2 + 2, )->then($mock); } - /** @test */ - public function shouldResolveWithEmptyArrayIfHowManyIsLessThanOne() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveWithEmptyArrayIfHowManyIsLessThanOne(): void { $mock = $this->createCallableMock(); $mock @@ -147,12 +149,12 @@ public function shouldResolveWithEmptyArrayIfHowManyIsLessThanOne() some( [1], - 0 + 0, )->then($mock); } - /** @test */ - public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray(): void { $mock = $this->createCallableMock(); $mock @@ -162,12 +164,12 @@ public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() some( resolve(1), - 1 + 1, )->then($mock); } - /** @test */ - public function shouldRejectWhenInputPromiseRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWhenInputPromiseRejects(): void { $mock = $this->createCallableMock(); $mock @@ -177,12 +179,12 @@ public function shouldRejectWhenInputPromiseRejects() some( reject(), - 1 + 1, )->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldCancelInputPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputPromise(): void { $mock = $this ->getMockBuilder('React\Promise\CancellablePromiseInterface') @@ -194,8 +196,8 @@ public function shouldCancelInputPromise() some($mock, 1)->cancel(); } - /** @test */ - public function shouldCancelInputArrayPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCancelInputArrayPromises(): void { $mock1 = $this ->getMockBuilder('React\Promise\CancellablePromiseInterface') @@ -214,15 +216,15 @@ public function shouldCancelInputArrayPromises() some([$mock1, $mock2], 1)->cancel(); } - /** @test */ - public function shouldNotCancelOtherPendingInputArrayPromisesIfEnoughPromisesFulfill() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotCancelOtherPendingInputArrayPromisesIfEnoughPromisesFulfill(): void { $mock = $this->createCallableMock(); $mock ->expects($this->never()) ->method('__invoke'); - $deferred = New Deferred($mock); + $deferred = new Deferred($mock); $deferred->resolve(); $mock2 = $this @@ -235,15 +237,15 @@ public function shouldNotCancelOtherPendingInputArrayPromisesIfEnoughPromisesFul some([$deferred->promise(), $mock2], 1); } - /** @test */ - public function shouldNotCancelOtherPendingInputArrayPromisesIfEnoughPromisesReject() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotCancelOtherPendingInputArrayPromisesIfEnoughPromisesReject(): void { $mock = $this->createCallableMock(); $mock ->expects($this->never()) ->method('__invoke'); - $deferred = New Deferred($mock); + $deferred = new Deferred($mock); $deferred->reject(); $mock2 = $this diff --git a/tests/LazyPromiseTest.php b/tests/LazyPromiseTest.php index b630881..7542e39 100644 --- a/tests/LazyPromiseTest.php +++ b/tests/LazyPromiseTest.php @@ -1,5 +1,7 @@ promise(); }; return new CallbackPromiseAdapter([ - 'promise' => function () use ($factory) { + 'promise' => static function () use ($factory) { return new LazyPromise($factory); }, 'resolve' => [$d, 'resolve'], @@ -27,8 +29,8 @@ public function getPromiseTestAdapter(callable $canceller = null) ]); } - /** @test */ - public function shouldNotCallFactoryIfThenIsNotInvoked() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotCallFactoryIfThenIsNotInvoked(): void { $factory = $this->createCallableMock(); $factory @@ -38,8 +40,8 @@ public function shouldNotCallFactoryIfThenIsNotInvoked() new LazyPromise($factory); } - /** @test */ - public function shouldCallFactoryIfThenIsInvoked() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldCallFactoryIfThenIsInvoked(): void { $factory = $this->createCallableMock(); $factory @@ -50,8 +52,8 @@ public function shouldCallFactoryIfThenIsInvoked() $p->then(); } - /** @test */ - public function shouldReturnPromiseFromFactory() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReturnPromiseFromFactory(): void { $factory = $this->createCallableMock(); $factory @@ -70,8 +72,8 @@ public function shouldReturnPromiseFromFactory() $p->then($onFulfilled); } - /** @test */ - public function shouldReturnPromiseIfFactoryReturnsNull() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReturnPromiseIfFactoryReturnsNull(): void { $factory = $this->createCallableMock(); $factory @@ -83,8 +85,8 @@ public function shouldReturnPromiseIfFactoryReturnsNull() $this->assertInstanceOf('React\\Promise\\PromiseInterface', $p->then()); } - /** @test */ - public function shouldReturnRejectedPromiseIfFactoryThrowsException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldReturnRejectedPromiseIfFactoryThrowsException(): void { $exception = new \Exception(); diff --git a/tests/PromiseAdapter/CallbackPromiseAdapter.php b/tests/PromiseAdapter/CallbackPromiseAdapter.php index bdedf46..bd85fc5 100644 --- a/tests/PromiseAdapter/CallbackPromiseAdapter.php +++ b/tests/PromiseAdapter/CallbackPromiseAdapter.php @@ -1,8 +1,8 @@ callbacks['promise'], func_get_args()); + return \call_user_func_array($this->callbacks['promise'], \func_get_args()); } public function resolve() { - return call_user_func_array($this->callbacks['resolve'], func_get_args()); + return \call_user_func_array($this->callbacks['resolve'], \func_get_args()); } public function reject() { - return call_user_func_array($this->callbacks['reject'], func_get_args()); + return \call_user_func_array($this->callbacks['reject'], \func_get_args()); } public function notify() { - return call_user_func_array($this->callbacks['notify'], func_get_args()); + return \call_user_func_array($this->callbacks['notify'], \func_get_args()); } public function settle() { - return call_user_func_array($this->callbacks['settle'], func_get_args()); + return \call_user_func_array($this->callbacks['settle'], \func_get_args()); } } diff --git a/tests/PromiseAdapter/PromiseAdapterInterface.php b/tests/PromiseAdapter/PromiseAdapterInterface.php index 9157cd4..34b28a6 100644 --- a/tests/PromiseAdapter/PromiseAdapterInterface.php +++ b/tests/PromiseAdapter/PromiseAdapterInterface.php @@ -1,14 +1,18 @@ function () use ($promise) { + 'promise' => static function () use ($promise) { return $promise; }, 'resolve' => $resolveCallback, @@ -29,12 +31,12 @@ public function getPromiseTestAdapter(callable $canceller = null) ]); } - /** @test */ - public function shouldRejectIfResolverThrowsException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectIfResolverThrowsException(): void { $exception = new \Exception('foo'); - $promise = new Promise(function () use ($exception) { + $promise = new Promise(static function () use ($exception): void { throw $exception; }); @@ -48,80 +50,80 @@ public function shouldRejectIfResolverThrowsException() ->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldResolveWithoutCreatingGarbageCyclesIfResolverResolvesWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldResolveWithoutCreatingGarbageCyclesIfResolverResolvesWithException(): void { - gc_collect_cycles(); - gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on + \gc_collect_cycles(); + \gc_collect_cycles(); // clear twice to avoid leftovers in PHP 7.4 with ext-xdebug and code coverage turned on - $promise = new Promise(function ($resolve) { + $promise = new Promise(static function ($resolve): void { $resolve(new \Exception('foo')); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfResolverThrowsExceptionWithoutResolver() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfResolverThrowsExceptionWithoutResolver(): void { - gc_collect_cycles(); - $promise = new Promise(function () { + \gc_collect_cycles(); + $promise = new Promise(static function (): void { throw new \Exception('foo'); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfResolverRejectsWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfResolverRejectsWithException(): void { - gc_collect_cycles(); - $promise = new Promise(function ($resolve, $reject) { + \gc_collect_cycles(); + $promise = new Promise(static function ($resolve, $reject): void { $reject(new \Exception('foo')); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerRejectsWithException(): void { - gc_collect_cycles(); - $promise = new Promise(function ($resolve, $reject) { }, function ($resolve, $reject) { + \gc_collect_cycles(); + $promise = new Promise(static function ($resolve, $reject): void {}, static function ($resolve, $reject): void { $reject(new \Exception('foo')); }); $promise->cancel(); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfParentCancellerRejectsWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfParentCancellerRejectsWithException(): void { - gc_collect_cycles(); - $promise = new Promise(function ($resolve, $reject) { }, function ($resolve, $reject) { + \gc_collect_cycles(); + $promise = new Promise(static function ($resolve, $reject): void {}, static function ($resolve, $reject): void { $reject(new \Exception('foo')); }); $promise->then()->then()->then()->cancel(); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldRejectWithoutCreatingGarbageCyclesIfResolverThrowsException() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfResolverThrowsException(): void { - gc_collect_cycles(); - $promise = new Promise(function ($resolve, $reject) { + \gc_collect_cycles(); + $promise = new Promise(static function ($resolve, $reject): void { throw new \Exception('foo'); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } /** @@ -133,58 +135,57 @@ public function shouldRejectWithoutCreatingGarbageCyclesIfResolverThrowsExceptio * Reassigned arguments only show up in the stack trace in PHP 7, so we can't * avoid this on legacy PHP. As an alternative, consider explicitly unsetting * any references before throwing. - * - * @test - * @requires PHP 7 */ - public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerWithReferenceThrowsException() + #[\PHPUnit\Framework\Attributes\RequiresPhp('7')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerWithReferenceThrowsException(): void { - gc_collect_cycles(); - $promise = new Promise(function () {}, function () use (&$promise) { + \gc_collect_cycles(); + $promise = new Promise(static function (): void {}, static function () use (&$promise): void { throw new \Exception('foo'); }); $promise->cancel(); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } /** - * @test - * @requires PHP 7 * @see self::shouldRejectWithoutCreatingGarbageCyclesIfCancellerWithReferenceThrowsException */ - public function shouldRejectWithoutCreatingGarbageCyclesIfResolverWithReferenceThrowsException() + #[\PHPUnit\Framework\Attributes\RequiresPhp('7')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfResolverWithReferenceThrowsException(): void { - gc_collect_cycles(); - $promise = new Promise(function () use (&$promise) { + \gc_collect_cycles(); + $promise = new Promise(static function () use (&$promise): void { throw new \Exception('foo'); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } /** - * @test - * @requires PHP 7 * @see self::shouldRejectWithoutCreatingGarbageCyclesIfCancellerWithReferenceThrowsException */ - public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndResolverThrowsException() + #[\PHPUnit\Framework\Attributes\RequiresPhp('7')] + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndResolverThrowsException(): void { - gc_collect_cycles(); - $promise = new Promise(function () { + \gc_collect_cycles(); + $promise = new Promise(static function (): void { throw new \Exception('foo'); - }, function () use (&$promise) { }); + }, static function () use (&$promise): void {}); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldIgnoreNotifyAfterReject() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldIgnoreNotifyAfterReject(): void { - $promise = new Promise(function () { }, function ($resolve, $reject, $notify) { + $promise = new Promise(static function (): void {}, static function ($resolve, $reject, $notify): void { $reject(new \Exception('foo')); $notify(42); }); @@ -193,74 +194,73 @@ public function shouldIgnoreNotifyAfterReject() $promise->cancel(); } - - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromise(): void { - gc_collect_cycles(); - $promise = new Promise(function () { }); + \gc_collect_cycles(); + $promise = new Promise(static function (): void {}); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithThenFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithThenFollowers(): void { - gc_collect_cycles(); - $promise = new Promise(function () { }); + \gc_collect_cycles(); + $promise = new Promise(static function (): void {}); $promise->then()->then()->then(); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithDoneFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithDoneFollowers(): void { - gc_collect_cycles(); - $promise = new Promise(function () { }); + \gc_collect_cycles(); + $promise = new Promise(static function (): void {}); $promise->done(); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithOtherwiseFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithOtherwiseFollowers(): void { - gc_collect_cycles(); - $promise = new Promise(function () { }); - $promise->otherwise(function () { }); + \gc_collect_cycles(); + $promise = new Promise(static function (): void {}); + $promise->otherwise(static function (): void {}); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithAlwaysFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithAlwaysFollowers(): void { - gc_collect_cycles(); - $promise = new Promise(function () { }); - $promise->always(function () { }); + \gc_collect_cycles(); + $promise = new Promise(static function (): void {}); + $promise->always(static function (): void {}); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithProgressFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToPendingPromiseWithProgressFollowers(): void { - gc_collect_cycles(); - $promise = new Promise(function () { }); - $promise->then(null, null, function () { }); + \gc_collect_cycles(); + $promise = new Promise(static function (): void {}); + $promise->then(null, null, static function (): void {}); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldFulfillIfFullfilledWithSimplePromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldFulfillIfFullfilledWithSimplePromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -276,8 +276,8 @@ public function shouldFulfillIfFullfilledWithSimplePromise() $adapter->resolve(new SimpleFulfilledTestPromise()); } - /** @test */ - public function shouldRejectIfRejectedWithSimplePromise() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldRejectIfRejectedWithSimplePromise(): void { $adapter = $this->getPromiseTestAdapter(); diff --git a/tests/PromiseTest/CancelTestTrait.php b/tests/PromiseTest/CancelTestTrait.php index 2baab02..3792393 100644 --- a/tests/PromiseTest/CancelTestTrait.php +++ b/tests/PromiseTest/CancelTestTrait.php @@ -1,5 +1,7 @@ getPromiseTestAdapter(function ($resolve, $reject, $notify) use (&$args) { - $args = func_get_args(); + $adapter = $this->getPromiseTestAdapter(static function ($resolve, $reject, $notify) use (&$args): void { + $args = \func_get_args(); }); $adapter->promise()->cancel(); $this->assertCount(3, $args); - $this->assertTrue(is_callable($args[0])); - $this->assertTrue(is_callable($args[1])); - $this->assertTrue(is_callable($args[2])); + $this->assertTrue(\is_callable($args[0])); + $this->assertTrue(\is_callable($args[1])); + $this->assertTrue(\is_callable($args[2])); } - /** @test */ - public function cancelShouldCallCancellerWithoutArgumentsIfNotAccessed() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldCallCancellerWithoutArgumentsIfNotAccessed(): void { $args = null; - $adapter = $this->getPromiseTestAdapter(function () use (&$args) { - $args = func_num_args(); + $adapter = $this->getPromiseTestAdapter(static function () use (&$args): void { + $args = \func_num_args(); }); $adapter->promise()->cancel(); @@ -40,10 +42,10 @@ public function cancelShouldCallCancellerWithoutArgumentsIfNotAccessed() $this->assertSame(0, $args); } - /** @test */ - public function cancelShouldFulfillPromiseIfCancellerFulfills() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldFulfillPromiseIfCancellerFulfills(): void { - $adapter = $this->getPromiseTestAdapter(function ($resolve) { + $adapter = $this->getPromiseTestAdapter(static function ($resolve): void { $resolve(1); }); @@ -59,10 +61,10 @@ public function cancelShouldFulfillPromiseIfCancellerFulfills() $adapter->promise()->cancel(); } - /** @test */ - public function cancelShouldRejectPromiseIfCancellerRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldRejectPromiseIfCancellerRejects(): void { - $adapter = $this->getPromiseTestAdapter(function ($resolve, $reject) { + $adapter = $this->getPromiseTestAdapter(static function ($resolve, $reject): void { $reject(1); }); @@ -78,12 +80,12 @@ public function cancelShouldRejectPromiseIfCancellerRejects() $adapter->promise()->cancel(); } - /** @test */ - public function cancelShouldRejectPromiseWithExceptionIfCancellerThrows() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldRejectPromiseWithExceptionIfCancellerThrows(): void { $e = new \Exception(); - $adapter = $this->getPromiseTestAdapter(function () use ($e) { + $adapter = $this->getPromiseTestAdapter(static function () use ($e): void { throw $e; }); @@ -99,10 +101,10 @@ public function cancelShouldRejectPromiseWithExceptionIfCancellerThrows() $adapter->promise()->cancel(); } - /** @test */ - public function cancelShouldProgressPromiseIfCancellerNotifies() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldProgressPromiseIfCancellerNotifies(): void { - $adapter = $this->getPromiseTestAdapter(function ($resolve, $reject, $progress) { + $adapter = $this->getPromiseTestAdapter(static function ($resolve, $reject, $progress): void { $progress(1); }); @@ -118,14 +120,14 @@ public function cancelShouldProgressPromiseIfCancellerNotifies() $adapter->promise()->cancel(); } - /** @test */ - public function cancelShouldCallCancellerOnlyOnceIfCancellerResolves() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldCallCancellerOnlyOnceIfCancellerResolves(): void { $mock = $this->createCallableMock(); $mock ->expects($this->once()) ->method('__invoke') - ->will($this->returnCallback(function ($resolve) { + ->will($this->returnCallback(static function ($resolve): void { $resolve(); })); @@ -135,10 +137,10 @@ public function cancelShouldCallCancellerOnlyOnceIfCancellerResolves() $adapter->promise()->cancel(); } - /** @test */ - public function cancelShouldHaveNoEffectIfCancellerDoesNothing() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldHaveNoEffectIfCancellerDoesNothing(): void { - $adapter = $this->getPromiseTestAdapter(function () {}); + $adapter = $this->getPromiseTestAdapter(static function (): void {}); $adapter->promise() ->then($this->expectCallableNever(), $this->expectCallableNever()); @@ -147,8 +149,8 @@ public function cancelShouldHaveNoEffectIfCancellerDoesNothing() $adapter->promise()->cancel(); } - /** @test */ - public function cancelShouldCallCancellerFromDeepNestedPromiseChain() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldCallCancellerFromDeepNestedPromiseChain(): void { $mock = $this->createCallableMock(); $mock @@ -158,23 +160,23 @@ public function cancelShouldCallCancellerFromDeepNestedPromiseChain() $adapter = $this->getPromiseTestAdapter($mock); $promise = $adapter->promise() - ->then(function () { - return new Promise\Promise(function () {}); + ->then(static function () { + return new Promise\Promise(static function (): void {}); }) - ->then(function () { + ->then(static function () { $d = new Promise\Deferred(); return $d->promise(); }) - ->then(function () { - return new Promise\Promise(function () {}); + ->then(static function () { + return new Promise\Promise(static function (): void {}); }); $promise->cancel(); } - /** @test */ - public function cancelCalledOnChildrenSouldOnlyCancelWhenAllChildrenCancelled() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelCalledOnChildrenSouldOnlyCancelWhenAllChildrenCancelled(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableNever()); @@ -188,8 +190,8 @@ public function cancelCalledOnChildrenSouldOnlyCancelWhenAllChildrenCancelled() $child1->cancel(); } - /** @test */ - public function cancelShouldTriggerCancellerWhenAllChildrenCancel() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldTriggerCancellerWhenAllChildrenCancel(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableOnce()); @@ -204,8 +206,8 @@ public function cancelShouldTriggerCancellerWhenAllChildrenCancel() $child2->cancel(); } - /** @test */ - public function cancelShouldNotTriggerCancellerWhenCancellingOneChildrenMultipleTimes() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldNotTriggerCancellerWhenCancellingOneChildrenMultipleTimes(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableNever()); @@ -220,8 +222,8 @@ public function cancelShouldNotTriggerCancellerWhenCancellingOneChildrenMultiple $child1->cancel(); } - /** @test */ - public function cancelShouldTriggerCancellerOnlyOnceWhenCancellingMultipleTimes() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldTriggerCancellerOnlyOnceWhenCancellingMultipleTimes(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableOnce()); @@ -229,8 +231,8 @@ public function cancelShouldTriggerCancellerOnlyOnceWhenCancellingMultipleTimes( $adapter->promise()->cancel(); } - /** @test */ - public function cancelShouldAlwaysTriggerCancellerWhenCalledOnRootPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldAlwaysTriggerCancellerWhenCalledOnRootPromise(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableOnce()); diff --git a/tests/PromiseTest/FullTestTrait.php b/tests/PromiseTest/FullTestTrait.php index 3ce45d6..8143541 100644 --- a/tests/PromiseTest/FullTestTrait.php +++ b/tests/PromiseTest/FullTestTrait.php @@ -1,15 +1,17 @@ getPromiseTestAdapter(); @@ -28,8 +30,8 @@ public function notifyShouldProgress() $adapter->notify($sentinel); } - /** @test */ - public function notifyShouldPropagateProgressToDownstreamPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldPropagateProgressToDownstreamPromises(): void { $adapter = $this->getPromiseTestAdapter(); @@ -51,19 +53,19 @@ public function notifyShouldPropagateProgressToDownstreamPromises() ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock + $mock, ) ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock2 + $mock2, ); $adapter->notify($sentinel); } - /** @test */ - public function notifyShouldPropagateTransformedProgressToDownstreamPromises() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldPropagateTransformedProgressToDownstreamPromises(): void { $adapter = $this->getPromiseTestAdapter(); @@ -85,19 +87,19 @@ public function notifyShouldPropagateTransformedProgressToDownstreamPromises() ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock + $mock, ) ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock2 + $mock2, ); $adapter->notify(1); } - /** @test */ - public function notifyShouldPropagateCaughtExceptionValueAsProgress() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldPropagateCaughtExceptionValueAsProgress(): void { $adapter = $this->getPromiseTestAdapter(); @@ -119,19 +121,19 @@ public function notifyShouldPropagateCaughtExceptionValueAsProgress() ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock + $mock, ) ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock2 + $mock2, ); $adapter->notify(1); } - /** @test */ - public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter2 = $this->getPromiseTestAdapter(); @@ -150,20 +152,20 @@ public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToA $adapter->resolve(); $adapter->promise() - ->then(function () use ($promise2) { + ->then(static function () use ($promise2) { return $promise2; }) ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock + $mock, ); $adapter2->notify($sentinel); } - /** @test */ - public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter2 = $this->getPromiseTestAdapter(); @@ -179,13 +181,13 @@ public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToA ->with($sentinel); $adapter->promise() - ->then(function () use ($promise2) { + ->then(static function () use ($promise2) { return $promise2; }) ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock + $mock, ); // resolve AFTER attaching progress handler @@ -193,8 +195,8 @@ public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToA $adapter2->notify($sentinel); } - /** @test */ - public function notifyShouldForwardProgressWhenResolvedWithAnotherPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldForwardProgressWhenResolvedWithAnotherPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter2 = $this->getPromiseTestAdapter(); @@ -217,64 +219,80 @@ public function notifyShouldForwardProgressWhenResolvedWithAnotherPromise() ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock + $mock, ) ->then( $this->expectCallableNever(), $this->expectCallableNever(), - $mock2 + $mock2, ); $adapter->resolve($adapter2->promise()); $adapter2->notify($sentinel); } - /** @test */ - public function notifyShouldAllowResolveAfterProgress() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldAllowResolveAfterProgress(): void { $adapter = $this->getPromiseTestAdapter(); $mock = $this->createCallableMock(); - $mock->expects($this->exactly(2))->method('__invoke')->withConsecutive( - array($this->identicalTo(1)), - array($this->identicalTo(2)) - ); + $mock->expects($this->exactly(2))->method('__invoke') + ->with($this->callback(static function ($arg) { + static $calls = 0; + $calls++; + if ($calls === 1) { + return $arg === 1; + } + if ($calls === 2) { + return $arg === 2; + } + return false; + })); $adapter->promise() ->then( $mock, $this->expectCallableNever(), - $mock + $mock, ); $adapter->notify(1); $adapter->resolve(2); } - /** @test */ - public function notifyShouldAllowRejectAfterProgress() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldAllowRejectAfterProgress(): void { $adapter = $this->getPromiseTestAdapter(); $mock = $this->createCallableMock(); - $mock->expects($this->exactly(2))->method('__invoke')->withConsecutive( - array($this->identicalTo(1)), - array($this->identicalTo(2)) - ); + $mock->expects($this->exactly(2))->method('__invoke') + ->with($this->callback(static function ($arg) { + static $calls = 0; + $calls++; + if ($calls === 1) { + return $arg === 1; + } + if ($calls === 2) { + return $arg === 2; + } + return false; + })); $adapter->promise() ->then( $this->expectCallableNever(), $mock, - $mock + $mock, ); $adapter->notify(1); $adapter->reject(2); } - /** @test */ - public function notifyShouldReturnSilentlyOnProgressWhenAlreadyRejected() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldReturnSilentlyOnProgressWhenAlreadyRejected(): void { $adapter = $this->getPromiseTestAdapter(); @@ -283,8 +301,8 @@ public function notifyShouldReturnSilentlyOnProgressWhenAlreadyRejected() $this->assertNull($adapter->notify()); } - /** @test */ - public function notifyShouldInvokeProgressHandler() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldInvokeProgressHandler(): void { $adapter = $this->getPromiseTestAdapter(); @@ -298,8 +316,8 @@ public function notifyShouldInvokeProgressHandler() $adapter->notify(1); } - /** @test */ - public function notifyShouldInvokeProgressHandlerFromDone() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldInvokeProgressHandlerFromDone(): void { $adapter = $this->getPromiseTestAdapter(); @@ -313,14 +331,14 @@ public function notifyShouldInvokeProgressHandlerFromDone() $adapter->notify(1); } - /** @test */ - public function notifyShouldThrowExceptionThrownProgressHandlerFromDone() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldThrowExceptionThrownProgressHandlerFromDone(): void { $adapter = $this->getPromiseTestAdapter(); $this->setExpectedException('\Exception', 'UnhandledRejectionException'); - $this->assertNull($adapter->promise()->done(null, null, function () { + $this->assertNull($adapter->promise()->done(null, null, static function (): void { throw new \Exception('UnhandledRejectionException'); })); $adapter->notify(1); diff --git a/tests/PromiseTest/PromiseFulfilledTestTrait.php b/tests/PromiseTest/PromiseFulfilledTestTrait.php index 428230b..55191eb 100644 --- a/tests/PromiseTest/PromiseFulfilledTestTrait.php +++ b/tests/PromiseTest/PromiseFulfilledTestTrait.php @@ -1,5 +1,7 @@ getPromiseTestAdapter(); @@ -26,12 +28,12 @@ public function fulfilledPromiseShouldBeImmutable() $adapter->promise() ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function fulfilledPromiseShouldInvokeNewlyAddedCallback() + #[\PHPUnit\Framework\Attributes\Test] + public function fulfilledPromiseShouldInvokeNewlyAddedCallback(): void { $adapter = $this->getPromiseTestAdapter(); @@ -47,8 +49,8 @@ public function fulfilledPromiseShouldInvokeNewlyAddedCallback() ->then($mock, $this->expectCallableNever()); } - /** @test */ - public function thenShouldForwardResultWhenCallbackIsNull() + #[\PHPUnit\Framework\Attributes\Test] + public function thenShouldForwardResultWhenCallbackIsNull(): void { $adapter = $this->getPromiseTestAdapter(); @@ -62,16 +64,16 @@ public function thenShouldForwardResultWhenCallbackIsNull() $adapter->promise() ->then( null, - $this->expectCallableNever() + $this->expectCallableNever(), ) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function thenShouldForwardCallbackResultToNextCallback() + #[\PHPUnit\Framework\Attributes\Test] + public function thenShouldForwardCallbackResultToNextCallback(): void { $adapter = $this->getPromiseTestAdapter(); @@ -84,19 +86,19 @@ public function thenShouldForwardCallbackResultToNextCallback() $adapter->resolve(1); $adapter->promise() ->then( - function ($val) { + static function ($val) { return $val + 1; }, - $this->expectCallableNever() + $this->expectCallableNever(), ) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function thenShouldForwardPromisedCallbackResultValueToNextCallback() + #[\PHPUnit\Framework\Attributes\Test] + public function thenShouldForwardPromisedCallbackResultValueToNextCallback(): void { $adapter = $this->getPromiseTestAdapter(); @@ -109,19 +111,19 @@ public function thenShouldForwardPromisedCallbackResultValueToNextCallback() $adapter->resolve(1); $adapter->promise() ->then( - function ($val) { + static function ($val) { return \React\Promise\resolve($val + 1); }, - $this->expectCallableNever() + $this->expectCallableNever(), ) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackReturnsARejection() + #[\PHPUnit\Framework\Attributes\Test] + public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackReturnsARejection(): void { $adapter = $this->getPromiseTestAdapter(); @@ -134,19 +136,19 @@ public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackReturnsARejec $adapter->resolve(1); $adapter->promise() ->then( - function ($val) { + static function ($val) { return \React\Promise\reject($val + 1); }, - $this->expectCallableNever() + $this->expectCallableNever(), ) ->then( $this->expectCallableNever(), - $mock + $mock, ); } - /** @test */ - public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackThrows() + #[\PHPUnit\Framework\Attributes\Test] + public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackThrows(): void { $adapter = $this->getPromiseTestAdapter(); @@ -168,16 +170,16 @@ public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackThrows() $adapter->promise() ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ) ->then( $this->expectCallableNever(), - $mock2 + $mock2, ); } - /** @test */ - public function cancelShouldReturnNullForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldReturnNullForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -186,8 +188,8 @@ public function cancelShouldReturnNullForFulfilledPromise() $this->assertNull($adapter->promise()->cancel()); } - /** @test */ - public function cancelShouldHaveNoEffectForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldHaveNoEffectForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableNever()); @@ -196,8 +198,8 @@ public function cancelShouldHaveNoEffectForFulfilledPromise() $adapter->promise()->cancel(); } - /** @test */ - public function doneShouldInvokeFulfillmentHandlerForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldInvokeFulfillmentHandlerForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -211,34 +213,34 @@ public function doneShouldInvokeFulfillmentHandlerForFulfilledPromise() $this->assertNull($adapter->promise()->done($mock)); } - /** @test */ - public function doneShouldThrowExceptionThrownFulfillmentHandlerForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowExceptionThrownFulfillmentHandlerForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); $this->setExpectedException('\Exception', 'UnhandledRejectionException'); $adapter->resolve(1); - $this->assertNull($adapter->promise()->done(function () { + $this->assertNull($adapter->promise()->done(static function (): void { throw new \Exception('UnhandledRejectionException'); })); } - /** @test */ - public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandlerRejectsForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandlerRejectsForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); - $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); + $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); $adapter->resolve(1); - $this->assertNull($adapter->promise()->done(function () { + $this->assertNull($adapter->promise()->done(static function () { return \React\Promise\reject(); })); } - /** @test */ - public function otherwiseShouldNotInvokeRejectionHandlerForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function otherwiseShouldNotInvokeRejectionHandlerForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -246,8 +248,8 @@ public function otherwiseShouldNotInvokeRejectionHandlerForFulfilledPromise() $adapter->promise()->otherwise($this->expectCallableNever()); } - /** @test */ - public function alwaysShouldNotSuppressValueForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressValueForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -261,12 +263,12 @@ public function alwaysShouldNotSuppressValueForFulfilledPromise() $adapter->resolve($value); $adapter->promise() - ->always(function () {}) + ->always(static function (): void {}) ->then($mock); } - /** @test */ - public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -280,14 +282,14 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulf $adapter->resolve($value); $adapter->promise() - ->always(function () { + ->always(static function () { return 1; }) ->then($mock); } - /** @test */ - public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -301,14 +303,14 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfill $adapter->resolve($value); $adapter->promise() - ->always(function () { + ->always(static function () { return \React\Promise\resolve(1); }) ->then($mock); } - /** @test */ - public function alwaysShouldRejectWhenHandlerThrowsForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerThrowsForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -322,14 +324,14 @@ public function alwaysShouldRejectWhenHandlerThrowsForFulfilledPromise() $adapter->resolve(1); $adapter->promise() - ->always(function () use ($exception) { + ->always(static function () use ($exception): void { throw $exception; }) ->then(null, $mock); } - /** @test */ - public function alwaysShouldRejectWhenHandlerRejectsForFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerRejectsForFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -343,7 +345,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForFulfilledPromise() $adapter->resolve(1); $adapter->promise() - ->always(function () use ($exception) { + ->always(static function () use ($exception) { return \React\Promise\reject($exception); }) ->then(null, $mock); diff --git a/tests/PromiseTest/PromisePendingTestTrait.php b/tests/PromiseTest/PromisePendingTestTrait.php index a4f48ee..43168fc 100644 --- a/tests/PromiseTest/PromisePendingTestTrait.php +++ b/tests/PromiseTest/PromisePendingTestTrait.php @@ -1,5 +1,7 @@ getPromiseTestAdapter(); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->then()); + $this->assertInstanceOf(\React\Promise\PromiseInterface::class, $adapter->promise()->then()); } - /** @test */ - public function thenShouldReturnAllowNullForPendingPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function thenShouldReturnAllowNullForPendingPromise(): void { $adapter = $this->getPromiseTestAdapter(); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->then(null, null, null)); + $this->assertInstanceOf(\React\Promise\PromiseInterface::class, $adapter->promise()->then(null, null, null)); } - /** @test */ - public function cancelShouldReturnNullForPendingPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldReturnNullForPendingPromise(): void { $adapter = $this->getPromiseTestAdapter(); $this->assertNull($adapter->promise()->cancel()); } - /** @test */ - public function doneShouldReturnNullForPendingPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldReturnNullForPendingPromise(): void { $adapter = $this->getPromiseTestAdapter(); $this->assertNull($adapter->promise()->done()); } - /** @test */ - public function doneShouldReturnAllowNullForPendingPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldReturnAllowNullForPendingPromise(): void { $adapter = $this->getPromiseTestAdapter(); $this->assertNull($adapter->promise()->done(null, null, null)); } - /** @test */ - public function otherwiseShouldNotInvokeRejectionHandlerForPendingPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function otherwiseShouldNotInvokeRejectionHandlerForPendingPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -58,11 +60,11 @@ public function otherwiseShouldNotInvokeRejectionHandlerForPendingPromise() $adapter->promise()->otherwise($this->expectCallableNever()); } - /** @test */ - public function alwaysShouldReturnAPromiseForPendingPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldReturnAPromiseForPendingPromise(): void { $adapter = $this->getPromiseTestAdapter(); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->always(function () {})); + $this->assertInstanceOf(\React\Promise\PromiseInterface::class, $adapter->promise()->always(static function (): void {})); } } diff --git a/tests/PromiseTest/PromiseRejectedTestTrait.php b/tests/PromiseTest/PromiseRejectedTestTrait.php index 98d1dcf..f76d160 100644 --- a/tests/PromiseTest/PromiseRejectedTestTrait.php +++ b/tests/PromiseTest/PromiseRejectedTestTrait.php @@ -1,5 +1,7 @@ getPromiseTestAdapter(); @@ -29,12 +31,12 @@ public function rejectedPromiseShouldBeImmutable() $adapter->promise() ->then( $this->expectCallableNever(), - $mock + $mock, ); } - /** @test */ - public function rejectedPromiseShouldInvokeNewlyAddedCallback() + #[\PHPUnit\Framework\Attributes\Test] + public function rejectedPromiseShouldInvokeNewlyAddedCallback(): void { $adapter = $this->getPromiseTestAdapter(); @@ -50,8 +52,8 @@ public function rejectedPromiseShouldInvokeNewlyAddedCallback() ->then($this->expectCallableNever(), $mock); } - /** @test */ - public function shouldForwardUndefinedRejectionValue() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldForwardUndefinedRejectionValue(): void { $adapter = $this->getPromiseTestAdapter(); @@ -65,21 +67,21 @@ public function shouldForwardUndefinedRejectionValue() $adapter->promise() ->then( $this->expectCallableNever(), - function () { + static function (): void { // Presence of rejection handler is enough to switch back // to resolve mode, even though it returns undefined. // The ONLY way to propagate a rejection is to re-throw or // return a rejected promise; - } + }, ) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function shouldSwitchFromErrbacksToCallbacksWhenErrbackDoesNotExplicitlyPropagate() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldSwitchFromErrbacksToCallbacksWhenErrbackDoesNotExplicitlyPropagate(): void { $adapter = $this->getPromiseTestAdapter(); @@ -93,18 +95,18 @@ public function shouldSwitchFromErrbacksToCallbacksWhenErrbackDoesNotExplicitlyP $adapter->promise() ->then( $this->expectCallableNever(), - function ($val) { + static function ($val) { return $val + 1; - } + }, ) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function shouldSwitchFromErrbacksToCallbacksWhenErrbackReturnsAResolution() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldSwitchFromErrbacksToCallbacksWhenErrbackReturnsAResolution(): void { $adapter = $this->getPromiseTestAdapter(); @@ -118,18 +120,18 @@ public function shouldSwitchFromErrbacksToCallbacksWhenErrbackReturnsAResolution $adapter->promise() ->then( $this->expectCallableNever(), - function ($val) { + static function ($val) { return \React\Promise\resolve($val + 1); - } + }, ) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); } - /** @test */ - public function shouldPropagateRejectionsWhenErrbackThrows() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldPropagateRejectionsWhenErrbackThrows(): void { $adapter = $this->getPromiseTestAdapter(); @@ -151,16 +153,16 @@ public function shouldPropagateRejectionsWhenErrbackThrows() $adapter->promise() ->then( $this->expectCallableNever(), - $mock + $mock, ) ->then( $this->expectCallableNever(), - $mock2 + $mock2, ); } - /** @test */ - public function shouldPropagateRejectionsWhenErrbackReturnsARejection() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldPropagateRejectionsWhenErrbackReturnsARejection(): void { $adapter = $this->getPromiseTestAdapter(); @@ -174,18 +176,18 @@ public function shouldPropagateRejectionsWhenErrbackReturnsARejection() $adapter->promise() ->then( $this->expectCallableNever(), - function ($val) { + static function ($val) { return \React\Promise\reject($val + 1); - } + }, ) ->then( $this->expectCallableNever(), - $mock + $mock, ); } - /** @test */ - public function doneShouldInvokeRejectionHandlerForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldInvokeRejectionHandlerForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -199,32 +201,32 @@ public function doneShouldInvokeRejectionHandlerForRejectedPromise() $this->assertNull($adapter->promise()->done(null, $mock)); } - /** @test */ - public function doneShouldThrowExceptionThrownByRejectionHandlerForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowExceptionThrownByRejectionHandlerForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); $this->setExpectedException('\Exception', 'UnhandledRejectionException'); $adapter->reject(1); - $this->assertNull($adapter->promise()->done(null, function () { + $this->assertNull($adapter->promise()->done(null, static function (): void { throw new \Exception('UnhandledRejectionException'); })); } - /** @test */ - public function doneShouldThrowUnhandledRejectionExceptionWhenRejectedWithNonExceptionForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowUnhandledRejectionExceptionWhenRejectedWithNonExceptionForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); - $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); + $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); $adapter->reject(1); $this->assertNull($adapter->promise()->done()); } - /** @test */ - public function unhandledRejectionExceptionThrownByDoneHoldsRejectionValue() + #[\PHPUnit\Framework\Attributes\Test] + public function unhandledRejectionExceptionThrownByDoneHoldsRejectionValue(): void { $adapter = $this->getPromiseTestAdapter(); @@ -242,34 +244,34 @@ public function unhandledRejectionExceptionThrownByDoneHoldsRejectionValue() $this->fail(); } - /** @test */ - public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRejectsForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRejectsForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); - $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); + $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); $adapter->reject(1); - $this->assertNull($adapter->promise()->done(null, function () { + $this->assertNull($adapter->promise()->done(null, static function () { return \React\Promise\reject(); })); } - /** @test */ - public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWithExceptionForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWithExceptionForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); $this->setExpectedException('\Exception', 'UnhandledRejectionException'); $adapter->reject(1); - $this->assertNull($adapter->promise()->done(null, function () { + $this->assertNull($adapter->promise()->done(null, static function () { return \React\Promise\reject(new \Exception('UnhandledRejectionException')); })); } - /** @test */ - public function doneShouldThrowExceptionProvidedAsRejectionValueForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowExceptionProvidedAsRejectionValueForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -279,8 +281,8 @@ public function doneShouldThrowExceptionProvidedAsRejectionValueForRejectedPromi $this->assertNull($adapter->promise()->done()); } - /** @test */ - public function doneShouldThrowWithDeepNestingPromiseChainsForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowWithDeepNestingPromiseChainsForRejectedPromise(): void { $this->setExpectedException('\Exception', 'UnhandledRejectionException'); @@ -289,33 +291,31 @@ public function doneShouldThrowWithDeepNestingPromiseChainsForRejectedPromise() $d = new Deferred(); $d->resolve(); - $result = \React\Promise\resolve(\React\Promise\resolve($d->promise()->then(function () use ($exception) { + $result = \React\Promise\resolve(\React\Promise\resolve($d->promise()->then(static function () use ($exception) { $d = new Deferred(); $d->resolve(); - return \React\Promise\resolve($d->promise()->then(function () {}))->then( - function () use ($exception) { + return \React\Promise\resolve($d->promise()->then(static function (): void {}))->then( + static function () use ($exception): void { throw $exception; - } + }, ); }))); $result->done(); } - /** @test */ - public function doneShouldRecoverWhenRejectionHandlerCatchesExceptionForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldRecoverWhenRejectionHandlerCatchesExceptionForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter->reject(new \Exception('UnhandledRejectionException')); - $this->assertNull($adapter->promise()->done(null, function (\Exception $e) { - - })); + $this->assertNull($adapter->promise()->done(null, static function (\Exception $e): void {})); } - /** @test */ - public function otherwiseShouldInvokeRejectionHandlerForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function otherwiseShouldInvokeRejectionHandlerForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -329,8 +329,8 @@ public function otherwiseShouldInvokeRejectionHandlerForRejectedPromise() $adapter->promise()->otherwise($mock); } - /** @test */ - public function otherwiseShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnExceptionForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function otherwiseShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnExceptionForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -344,13 +344,13 @@ public function otherwiseShouldInvokeNonTypeHintedRejectionHandlerIfReasonIsAnEx $adapter->reject($exception); $adapter->promise() - ->otherwise(function ($reason) use ($mock) { + ->otherwise(static function ($reason) use ($mock): void { $mock($reason); }); } - /** @test */ - public function otherwiseShouldInvokeRejectionHandlerIfReasonMatchesTypehintForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function otherwiseShouldInvokeRejectionHandlerIfReasonMatchesTypehintForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -364,13 +364,13 @@ public function otherwiseShouldInvokeRejectionHandlerIfReasonMatchesTypehintForR $adapter->reject($exception); $adapter->promise() - ->otherwise(function (\InvalidArgumentException $reason) use ($mock) { + ->otherwise(static function (\InvalidArgumentException $reason) use ($mock): void { $mock($reason); }); } - /** @test */ - public function otherwiseShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchTypehintForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function otherwiseShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchTypehintForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -380,13 +380,13 @@ public function otherwiseShouldNotInvokeRejectionHandlerIfReaonsDoesNotMatchType $adapter->reject($exception); $adapter->promise() - ->otherwise(function (\InvalidArgumentException $reason) use ($mock) { + ->otherwise(static function (\InvalidArgumentException $reason) use ($mock): void { $mock($reason); }); } - /** @test */ - public function alwaysShouldNotSuppressRejectionForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressRejectionForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -400,12 +400,12 @@ public function alwaysShouldNotSuppressRejectionForRejectedPromise() $adapter->reject($exception); $adapter->promise() - ->always(function () {}) + ->always(static function (): void {}) ->then(null, $mock); } - /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -419,14 +419,14 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseFor $adapter->reject($exception); $adapter->promise() - ->always(function () { + ->always(static function () { return 1; }) ->then(null, $mock); } - /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -440,14 +440,14 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRej $adapter->reject($exception); $adapter->promise() - ->always(function () { + ->always(static function () { return \React\Promise\resolve(1); }) ->then(null, $mock); } - /** @test */ - public function alwaysShouldRejectWhenHandlerThrowsForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerThrowsForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -462,14 +462,14 @@ public function alwaysShouldRejectWhenHandlerThrowsForRejectedPromise() $adapter->reject($exception1); $adapter->promise() - ->always(function () use ($exception2) { + ->always(static function () use ($exception2): void { throw $exception2; }) ->then(null, $mock); } - /** @test */ - public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -484,14 +484,14 @@ public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise() $adapter->reject($exception1); $adapter->promise() - ->always(function () use ($exception2) { + ->always(static function () use ($exception2) { return \React\Promise\reject($exception2); }) ->then(null, $mock); } - /** @test */ - public function cancelShouldReturnNullForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldReturnNullForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -500,8 +500,8 @@ public function cancelShouldReturnNullForRejectedPromise() $this->assertNull($adapter->promise()->cancel()); } - /** @test */ - public function cancelShouldHaveNoEffectForRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldHaveNoEffectForRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableNever()); diff --git a/tests/PromiseTest/PromiseSettledTestTrait.php b/tests/PromiseTest/PromiseSettledTestTrait.php index e363b6d..25176a3 100644 --- a/tests/PromiseTest/PromiseSettledTestTrait.php +++ b/tests/PromiseTest/PromiseSettledTestTrait.php @@ -1,5 +1,7 @@ getPromiseTestAdapter(); $adapter->settle(); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->then()); + $this->assertInstanceOf(\React\Promise\PromiseInterface::class, $adapter->promise()->then()); } - /** @test */ - public function thenShouldReturnAllowNullForSettledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function thenShouldReturnAllowNullForSettledPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter->settle(); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->then(null, null, null)); + $this->assertInstanceOf(\React\Promise\PromiseInterface::class, $adapter->promise()->then(null, null, null)); } - /** @test */ - public function cancelShouldReturnNullForSettledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldReturnNullForSettledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -37,8 +39,8 @@ public function cancelShouldReturnNullForSettledPromise() $this->assertNull($adapter->promise()->cancel()); } - /** @test */ - public function cancelShouldHaveNoEffectForSettledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function cancelShouldHaveNoEffectForSettledPromise(): void { $adapter = $this->getPromiseTestAdapter($this->expectCallableNever()); @@ -47,26 +49,26 @@ public function cancelShouldHaveNoEffectForSettledPromise() $adapter->promise()->cancel(); } - /** @test */ - public function doneShouldReturnNullForSettledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldReturnNullForSettledPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter->settle(); - $this->assertNull($adapter->promise()->done(null, function () {})); + $this->assertNull($adapter->promise()->done(null, static function (): void {})); } - /** @test */ - public function doneShouldReturnAllowNullForSettledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldReturnAllowNullForSettledPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter->settle(); - $this->assertNull($adapter->promise()->done(null, function () {}, null)); + $this->assertNull($adapter->promise()->done(null, static function (): void {}, null)); } - /** @test */ - public function progressShouldNotInvokeProgressHandlerForSettledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function progressShouldNotInvokeProgressHandlerForSettledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -75,12 +77,12 @@ public function progressShouldNotInvokeProgressHandlerForSettledPromise() $adapter->notify(); } - /** @test */ - public function alwaysShouldReturnAPromiseForSettledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldReturnAPromiseForSettledPromise(): void { $adapter = $this->getPromiseTestAdapter(); $adapter->settle(); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $adapter->promise()->always(function () {})); + $this->assertInstanceOf(\React\Promise\PromiseInterface::class, $adapter->promise()->always(static function (): void {})); } } diff --git a/tests/PromiseTest/RejectTestTrait.php b/tests/PromiseTest/RejectTestTrait.php index 063f178..4854209 100644 --- a/tests/PromiseTest/RejectTestTrait.php +++ b/tests/PromiseTest/RejectTestTrait.php @@ -1,5 +1,7 @@ getPromiseTestAdapter(); @@ -29,8 +31,8 @@ public function rejectShouldRejectWithAnImmediateValue() $adapter->reject(1); } - /** @test */ - public function rejectShouldRejectWithFulfilledPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function rejectShouldRejectWithFulfilledPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -46,8 +48,8 @@ public function rejectShouldRejectWithFulfilledPromise() $adapter->reject(Promise\resolve(1)); } - /** @test */ - public function rejectShouldRejectWithRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function rejectShouldRejectWithRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -63,8 +65,8 @@ public function rejectShouldRejectWithRejectedPromise() $adapter->reject(Promise\reject(1)); } - /** @test */ - public function rejectShouldForwardReasonWhenCallbackIsNull() + #[\PHPUnit\Framework\Attributes\Test] + public function rejectShouldForwardReasonWhenCallbackIsNull(): void { $adapter = $this->getPromiseTestAdapter(); @@ -76,18 +78,18 @@ public function rejectShouldForwardReasonWhenCallbackIsNull() $adapter->promise() ->then( - $this->expectCallableNever() + $this->expectCallableNever(), ) ->then( $this->expectCallableNever(), - $mock + $mock, ); $adapter->reject(1); } - /** @test */ - public function rejectShouldMakePromiseImmutable() + #[\PHPUnit\Framework\Attributes\Test] + public function rejectShouldMakePromiseImmutable(): void { $adapter = $this->getPromiseTestAdapter(); @@ -98,22 +100,22 @@ public function rejectShouldMakePromiseImmutable() ->with($this->identicalTo(1)); $adapter->promise() - ->then(null, function ($value) use ($adapter) { + ->then(null, static function ($value) use ($adapter) { $adapter->reject(3); return Promise\reject($value); }) ->then( $this->expectCallableNever(), - $mock + $mock, ); $adapter->reject(1); $adapter->reject(2); } - /** @test */ - public function notifyShouldInvokeOtherwiseHandler() + #[\PHPUnit\Framework\Attributes\Test] + public function notifyShouldInvokeOtherwiseHandler(): void { $adapter = $this->getPromiseTestAdapter(); @@ -129,8 +131,8 @@ public function notifyShouldInvokeOtherwiseHandler() $adapter->reject(1); } - /** @test */ - public function doneShouldInvokeRejectionHandler() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldInvokeRejectionHandler(): void { $adapter = $this->getPromiseTestAdapter(); @@ -144,75 +146,75 @@ public function doneShouldInvokeRejectionHandler() $adapter->reject(1); } - /** @test */ - public function doneShouldThrowExceptionThrownByRejectionHandler() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowExceptionThrownByRejectionHandler(): void { $adapter = $this->getPromiseTestAdapter(); $this->setExpectedException('\Exception', 'UnhandledRejectionException'); - $this->assertNull($adapter->promise()->done(null, function () { + $this->assertNull($adapter->promise()->done(null, static function (): void { throw new \Exception('UnhandledRejectionException'); })); $adapter->reject(1); } - /** @test */ - public function doneShouldThrowUnhandledRejectionExceptionWhenRejectedWithNonException() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowUnhandledRejectionExceptionWhenRejectedWithNonException(): void { $adapter = $this->getPromiseTestAdapter(); - $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); + $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); $this->assertNull($adapter->promise()->done()); $adapter->reject(1); } - /** @test */ - public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRejects(): void { $adapter = $this->getPromiseTestAdapter(); - $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); + $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); - $this->assertNull($adapter->promise()->done(null, function () { + $this->assertNull($adapter->promise()->done(null, static function () { return \React\Promise\reject(); })); $adapter->reject(1); } - /** @test */ - public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWithException() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWithException(): void { $adapter = $this->getPromiseTestAdapter(); $this->setExpectedException('\Exception', 'UnhandledRejectionException'); - $this->assertNull($adapter->promise()->done(null, function () { + $this->assertNull($adapter->promise()->done(null, static function () { return \React\Promise\reject(new \Exception('UnhandledRejectionException')); })); $adapter->reject(1); } - /** @test */ - public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRetunsPendingPromiseWhichRejectsLater() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRetunsPendingPromiseWhichRejectsLater(): void { $adapter = $this->getPromiseTestAdapter(); - $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); + $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); $d = new Deferred(); $promise = $d->promise(); - $this->assertNull($adapter->promise()->done(null, function () use ($promise) { + $this->assertNull($adapter->promise()->done(null, static function () use ($promise) { return $promise; })); $adapter->reject(1); $d->reject(1); } - /** @test */ - public function doneShouldThrowExceptionProvidedAsRejectionValue() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowExceptionProvidedAsRejectionValue(): void { $adapter = $this->getPromiseTestAdapter(); @@ -222,8 +224,8 @@ public function doneShouldThrowExceptionProvidedAsRejectionValue() $adapter->reject(new \Exception('UnhandledRejectionException')); } - /** @test */ - public function doneShouldThrowWithDeepNestingPromiseChains() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowWithDeepNestingPromiseChains(): void { $this->setExpectedException('\Exception', 'UnhandledRejectionException'); @@ -231,14 +233,14 @@ public function doneShouldThrowWithDeepNestingPromiseChains() $d = new Deferred(); - $result = \React\Promise\resolve(\React\Promise\resolve($d->promise()->then(function () use ($exception) { + $result = \React\Promise\resolve(\React\Promise\resolve($d->promise()->then(static function () use ($exception) { $d = new Deferred(); $d->resolve(); - return \React\Promise\resolve($d->promise()->then(function () {}))->then( - function () use ($exception) { + return \React\Promise\resolve($d->promise()->then(static function (): void {}))->then( + static function () use ($exception): void { throw $exception; - } + }, ); }))); @@ -247,19 +249,17 @@ function () use ($exception) { $d->resolve(); } - /** @test */ - public function doneShouldRecoverWhenRejectionHandlerCatchesException() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldRecoverWhenRejectionHandlerCatchesException(): void { $adapter = $this->getPromiseTestAdapter(); - $this->assertNull($adapter->promise()->done(null, function (\Exception $e) { - - })); + $this->assertNull($adapter->promise()->done(null, static function (\Exception $e): void {})); $adapter->reject(new \Exception('UnhandledRejectionException')); } - /** @test */ - public function alwaysShouldNotSuppressRejection() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressRejection(): void { $adapter = $this->getPromiseTestAdapter(); @@ -272,14 +272,14 @@ public function alwaysShouldNotSuppressRejection() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () {}) + ->always(static function (): void {}) ->then(null, $mock); $adapter->reject($exception); } - /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -292,7 +292,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () { + ->always(static function () { return 1; }) ->then(null, $mock); @@ -300,8 +300,8 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise() $adapter->reject($exception); } - /** @test */ - public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -314,7 +314,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () { + ->always(static function () { return \React\Promise\resolve(1); }) ->then(null, $mock); @@ -322,8 +322,8 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise() $adapter->reject($exception); } - /** @test */ - public function alwaysShouldRejectWhenHandlerThrowsForRejection() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerThrowsForRejection(): void { $adapter = $this->getPromiseTestAdapter(); @@ -336,7 +336,7 @@ public function alwaysShouldRejectWhenHandlerThrowsForRejection() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->always(static function () use ($exception): void { throw $exception; }) ->then(null, $mock); @@ -344,8 +344,8 @@ public function alwaysShouldRejectWhenHandlerThrowsForRejection() $adapter->reject($exception); } - /** @test */ - public function alwaysShouldRejectWhenHandlerRejectsForRejection() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerRejectsForRejection(): void { $adapter = $this->getPromiseTestAdapter(); @@ -358,7 +358,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForRejection() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->always(static function () use ($exception) { return \React\Promise\reject($exception); }) ->then(null, $mock); diff --git a/tests/PromiseTest/ResolveTestTrait.php b/tests/PromiseTest/ResolveTestTrait.php index 0736d35..d61df14 100644 --- a/tests/PromiseTest/ResolveTestTrait.php +++ b/tests/PromiseTest/ResolveTestTrait.php @@ -1,5 +1,7 @@ getPromiseTestAdapter(); @@ -28,8 +30,8 @@ public function resolveShouldResolve() $adapter->resolve(1); } - /** @test */ - public function resolveShouldResolveWithPromisedValue() + #[\PHPUnit\Framework\Attributes\Test] + public function resolveShouldResolveWithPromisedValue(): void { $adapter = $this->getPromiseTestAdapter(); @@ -45,8 +47,8 @@ public function resolveShouldResolveWithPromisedValue() $adapter->resolve(Promise\resolve(1)); } - /** @test */ - public function resolveShouldRejectWhenResolvedWithRejectedPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function resolveShouldRejectWhenResolvedWithRejectedPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -62,8 +64,8 @@ public function resolveShouldRejectWhenResolvedWithRejectedPromise() $adapter->resolve(Promise\reject(1)); } - /** @test */ - public function resolveShouldForwardValueWhenCallbackIsNull() + #[\PHPUnit\Framework\Attributes\Test] + public function resolveShouldForwardValueWhenCallbackIsNull(): void { $adapter = $this->getPromiseTestAdapter(); @@ -76,18 +78,18 @@ public function resolveShouldForwardValueWhenCallbackIsNull() $adapter->promise() ->then( null, - $this->expectCallableNever() + $this->expectCallableNever(), ) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); $adapter->resolve(1); } - /** @test */ - public function resolveShouldMakePromiseImmutable() + #[\PHPUnit\Framework\Attributes\Test] + public function resolveShouldMakePromiseImmutable(): void { $adapter = $this->getPromiseTestAdapter(); @@ -98,24 +100,22 @@ public function resolveShouldMakePromiseImmutable() ->with($this->identicalTo(1)); $adapter->promise() - ->then(function ($value) use ($adapter) { + ->then(static function ($value) use ($adapter) { $adapter->resolve(3); return $value; }) ->then( $mock, - $this->expectCallableNever() + $this->expectCallableNever(), ); $adapter->resolve(1); $adapter->resolve(2); } - /** - * @test - */ - public function resolveShouldRejectWhenResolvedWithItself() + #[\PHPUnit\Framework\Attributes\Test] + public function resolveShouldRejectWhenResolvedWithItself(): void { $adapter = $this->getPromiseTestAdapter(); @@ -128,16 +128,14 @@ public function resolveShouldRejectWhenResolvedWithItself() $adapter->promise() ->then( $this->expectCallableNever(), - $mock + $mock, ); $adapter->resolve($adapter->promise()); } - /** - * @test - */ - public function resolveShouldRejectWhenResolvedWithAPromiseWhichFollowsItself() + #[\PHPUnit\Framework\Attributes\Test] + public function resolveShouldRejectWhenResolvedWithAPromiseWhichFollowsItself(): void { $adapter1 = $this->getPromiseTestAdapter(); $adapter2 = $this->getPromiseTestAdapter(); @@ -154,15 +152,15 @@ public function resolveShouldRejectWhenResolvedWithAPromiseWhichFollowsItself() $promise2->then( $this->expectCallableNever(), - $mock + $mock, ); $adapter1->resolve($promise2); $adapter2->resolve($promise1); } - /** @test */ - public function doneShouldInvokeFulfillmentHandler() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldInvokeFulfillmentHandler(): void { $adapter = $this->getPromiseTestAdapter(); @@ -176,34 +174,34 @@ public function doneShouldInvokeFulfillmentHandler() $adapter->resolve(1); } - /** @test */ - public function doneShouldThrowExceptionThrownFulfillmentHandler() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowExceptionThrownFulfillmentHandler(): void { $adapter = $this->getPromiseTestAdapter(); $this->setExpectedException('\Exception', 'UnhandledRejectionException'); - $this->assertNull($adapter->promise()->done(function () { + $this->assertNull($adapter->promise()->done(static function (): void { throw new \Exception('UnhandledRejectionException'); })); $adapter->resolve(1); } - /** @test */ - public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandlerRejects() + #[\PHPUnit\Framework\Attributes\Test] + public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandlerRejects(): void { $adapter = $this->getPromiseTestAdapter(); - $this->setExpectedException('React\\Promise\\UnhandledRejectionException'); + $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); - $this->assertNull($adapter->promise()->done(function () { + $this->assertNull($adapter->promise()->done(static function () { return \React\Promise\reject(); })); $adapter->resolve(1); } - /** @test */ - public function alwaysShouldNotSuppressValue() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressValue(): void { $adapter = $this->getPromiseTestAdapter(); @@ -216,14 +214,14 @@ public function alwaysShouldNotSuppressValue() ->with($this->identicalTo($value)); $adapter->promise() - ->always(function () {}) + ->always(static function (): void {}) ->then($mock); $adapter->resolve($value); } - /** @test */ - public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -236,7 +234,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise() ->with($this->identicalTo($value)); $adapter->promise() - ->always(function () { + ->always(static function () { return 1; }) ->then($mock); @@ -244,8 +242,8 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise() $adapter->resolve($value); } - /** @test */ - public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise(): void { $adapter = $this->getPromiseTestAdapter(); @@ -258,7 +256,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise() ->with($this->identicalTo($value)); $adapter->promise() - ->always(function () { + ->always(static function () { return \React\Promise\resolve(1); }) ->then($mock); @@ -266,8 +264,8 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise() $adapter->resolve($value); } - /** @test */ - public function alwaysShouldRejectWhenHandlerThrowsForFulfillment() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerThrowsForFulfillment(): void { $adapter = $this->getPromiseTestAdapter(); @@ -280,7 +278,7 @@ public function alwaysShouldRejectWhenHandlerThrowsForFulfillment() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->always(static function () use ($exception): void { throw $exception; }) ->then(null, $mock); @@ -288,8 +286,8 @@ public function alwaysShouldRejectWhenHandlerThrowsForFulfillment() $adapter->resolve(1); } - /** @test */ - public function alwaysShouldRejectWhenHandlerRejectsForFulfillment() + #[\PHPUnit\Framework\Attributes\Test] + public function alwaysShouldRejectWhenHandlerRejectsForFulfillment(): void { $adapter = $this->getPromiseTestAdapter(); @@ -302,7 +300,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForFulfillment() ->with($this->identicalTo($exception)); $adapter->promise() - ->always(function () use ($exception) { + ->always(static function () use ($exception) { return \React\Promise\reject($exception); }) ->then(null, $mock); diff --git a/tests/RejectedPromiseTest.php b/tests/RejectedPromiseTest.php index 825f56c..f426c88 100644 --- a/tests/RejectedPromiseTest.php +++ b/tests/RejectedPromiseTest.php @@ -1,38 +1,40 @@ function () use (&$promise) { + 'promise' => static function () use (&$promise) { if (!$promise) { throw new \LogicException('RejectedPromise must be rejected before obtaining the promise'); } return $promise; }, - 'resolve' => function () { + 'resolve' => static function (): void { throw new \LogicException('You cannot call resolve() for React\Promise\RejectedPromise'); }, - 'reject' => function ($reason = null) use (&$promise) { + 'reject' => static function ($reason = null) use (&$promise): void { if (!$promise) { $promise = new RejectedPromise($reason); } }, - 'notify' => function () { + 'notify' => static function (): void { // no-op }, - 'settle' => function ($reason = null) use (&$promise) { + 'settle' => static function ($reason = null) use (&$promise): void { if (!$promise) { $promise = new RejectedPromise($reason); } @@ -40,7 +42,7 @@ public function getPromiseTestAdapter(callable $canceller = null) ]); } - /** @test */ + #[\PHPUnit\Framework\Attributes\Test] public function shouldThrowExceptionIfConstructedWithAPromise() { $this->setExpectedException('\InvalidArgumentException'); @@ -48,29 +50,29 @@ public function shouldThrowExceptionIfConstructedWithAPromise() return new RejectedPromise(new RejectedPromise()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToRejectedPromiseWithAlwaysFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToRejectedPromiseWithAlwaysFollowers(): void { - gc_collect_cycles(); + \gc_collect_cycles(); $promise = new RejectedPromise(1); - $promise->always(function () { + $promise->always(static function (): void { throw new \RuntimeException(); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } - /** @test */ - public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToRejectedPromiseWithThenFollowers() + #[\PHPUnit\Framework\Attributes\Test] + public function shouldNotLeaveGarbageCyclesWhenRemovingLastReferenceToRejectedPromiseWithThenFollowers(): void { - gc_collect_cycles(); + \gc_collect_cycles(); $promise = new RejectedPromise(1); - $promise = $promise->then(null, function () { + $promise = $promise->then(null, static function (): void { throw new \RuntimeException(); }); unset($promise); - $this->assertSame(0, gc_collect_cycles()); + $this->assertSame(0, \gc_collect_cycles()); } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 30230a4..a857900 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,5 +1,7 @@ getMockBuilder('stdClass')->addMethods(array('__invoke'))->getMock(); - } else { - // legacy PHPUnit 4 - PHPUnit 9 - return $this->getMockBuilder('stdClass')->setMethods(array('__invoke'))->getMock(); + return $this->getMockBuilder('stdClass')->addMethods(['__invoke'])->getMock(); } + // legacy PHPUnit 4 - PHPUnit 9 + return $this->getMockBuilder('stdClass')->getMock(); + } - public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null) + public function setExpectedException($exception, $exceptionMessage = '', $exceptionCode = null): void { - if (method_exists($this, 'expectException')) { + if (\method_exists($this, 'expectException')) { // PHPUnit 5+ $this->expectException($exception); if ($exceptionMessage !== '') { diff --git a/tests/fixtures/ArrayAccessibleException.php b/tests/fixtures/ArrayAccessibleException.php index 71b7ad2..d98d401 100644 --- a/tests/fixtures/ArrayAccessibleException.php +++ b/tests/fixtures/ArrayAccessibleException.php @@ -1,10 +1,10 @@ cancelCalled = true; } diff --git a/tests/fixtures/SimpleTestCancellableThenable.php b/tests/fixtures/SimpleTestCancellableThenable.php index c0f1593..6a0e168 100644 --- a/tests/fixtures/SimpleTestCancellableThenable.php +++ b/tests/fixtures/SimpleTestCancellableThenable.php @@ -1,17 +1,19 @@ cancelCalled = true; } From 20231f0199a20aa6b325dddd08958bca93d5d573 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 19:20:12 +0400 Subject: [PATCH 04/15] style: Normalize code style --- src/CancellationQueue.php | 22 ++++++------ src/Deferred.php | 9 +++-- src/Exception/LengthException.php | 4 +-- src/ExtendedPromiseInterface.php | 7 +--- src/FulfilledPromise.php | 12 +++---- src/LazyPromise.php | 6 ++-- src/Promise.php | 32 ++++++++--------- src/PromiseInterface.php | 4 +-- src/RejectedPromise.php | 12 +++---- src/UnhandledRejectionException.php | 18 +++++----- src/functions.php | 18 +++++----- src/functions_include.php | 2 +- tests/PromiseTest.php | 56 ----------------------------- 13 files changed, 65 insertions(+), 137 deletions(-) diff --git a/src/CancellationQueue.php b/src/CancellationQueue.php index a381e97..c2624c1 100644 --- a/src/CancellationQueue.php +++ b/src/CancellationQueue.php @@ -7,16 +7,6 @@ class CancellationQueue private $started = false; private $queue = []; - public function __invoke() - { - if ($this->started) { - return; - } - - $this->started = true; - $this->drain(); - } - public function enqueue($cancellable) { if (!\is_object($cancellable) || !\method_exists($cancellable, 'then') || !\method_exists($cancellable, 'cancel')) { @@ -25,11 +15,21 @@ public function enqueue($cancellable) $length = \array_push($this->queue, $cancellable); - if ($this->started && 1 === $length) { + if ($this->started && $length === 1) { $this->drain(); } } + public function __invoke() + { + if ($this->started) { + return; + } + + $this->started = true; + $this->drain(); + } + private function drain() { for ($i = key($this->queue); isset($this->queue[$i]); $i++) { diff --git a/src/Deferred.php b/src/Deferred.php index 3ca034b..df5e122 100644 --- a/src/Deferred.php +++ b/src/Deferred.php @@ -10,14 +10,14 @@ class Deferred implements PromisorInterface private $notifyCallback; private $canceller; - public function __construct(callable $canceller = null) + public function __construct(?callable $canceller = null) { $this->canceller = $canceller; } public function promise() { - if (null === $this->promise) { + if ($this->promise === null) { $this->promise = new Promise(function ($resolve, $reject, $notify) { $this->resolveCallback = $resolve; $this->rejectCallback = $reject; @@ -45,9 +45,8 @@ public function reject($reason = null) /** * @deprecated 2.6.0 Progress support is deprecated and should not be used anymore. - * @param mixed $update */ - public function notify($update = null) + public function notify(mixed $update = null) { $this->promise(); @@ -58,7 +57,7 @@ public function notify($update = null) * @deprecated 2.2.0 * @see Deferred::notify() */ - public function progress($update = null) + public function progress(mixed $update = null) { $this->notify($update); } diff --git a/src/Exception/LengthException.php b/src/Exception/LengthException.php index 775c48d..363d572 100644 --- a/src/Exception/LengthException.php +++ b/src/Exception/LengthException.php @@ -2,6 +2,4 @@ namespace React\Promise\Exception; -class LengthException extends \LengthException -{ -} +class LengthException extends \LengthException {} diff --git a/src/ExtendedPromiseInterface.php b/src/ExtendedPromiseInterface.php index 13b6369..054b362 100644 --- a/src/ExtendedPromiseInterface.php +++ b/src/ExtendedPromiseInterface.php @@ -14,12 +14,10 @@ interface ExtendedPromiseInterface extends PromiseInterface * Since the purpose of `done()` is consumption rather than transformation, * `done()` always returns `null`. * - * @param callable|null $onFulfilled - * @param callable|null $onRejected * @param callable|null $onProgress This argument is deprecated and should not be used anymore. * @return void */ - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); + public function done(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null); /** * Registers a rejection handler for promise. It is a shortcut for: @@ -31,7 +29,6 @@ public function done(callable $onFulfilled = null, callable $onRejected = null, * Additionally, you can type hint the `$reason` argument of `$onRejected` to catch * only specific errors. * - * @param callable $onRejected * @return ExtendedPromiseInterface */ public function otherwise(callable $onRejected); @@ -78,7 +75,6 @@ public function otherwise(callable $onRejected); * ->always('cleanup'); * ``` * - * @param callable $onFulfilledOrRejected * @return ExtendedPromiseInterface */ public function always(callable $onFulfilledOrRejected); @@ -90,7 +86,6 @@ public function always(callable $onFulfilledOrRejected); * $promise->then(null, null, $onProgress); * ``` * - * @param callable $onProgress * @return ExtendedPromiseInterface * @deprecated 2.6.0 Progress support is deprecated and should not be used anymore. */ diff --git a/src/FulfilledPromise.php b/src/FulfilledPromise.php index 1472752..1111e92 100644 --- a/src/FulfilledPromise.php +++ b/src/FulfilledPromise.php @@ -18,9 +18,9 @@ public function __construct($value = null) $this->value = $value; } - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function then(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { - if (null === $onFulfilled) { + if ($onFulfilled === null) { return $this; } @@ -33,9 +33,9 @@ public function then(callable $onFulfilled = null, callable $onRejected = null, } } - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function done(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { - if (null === $onFulfilled) { + if ($onFulfilled === null) { return; } @@ -65,7 +65,5 @@ public function progress(callable $onProgress) return $this; } - public function cancel() - { - } + public function cancel() {} } diff --git a/src/LazyPromise.php b/src/LazyPromise.php index bbe9293..827a0a6 100644 --- a/src/LazyPromise.php +++ b/src/LazyPromise.php @@ -15,12 +15,12 @@ public function __construct(callable $factory) $this->factory = $factory; } - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function then(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { return $this->promise()->then($onFulfilled, $onRejected, $onProgress); } - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function done(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { return $this->promise()->done($onFulfilled, $onRejected, $onProgress); } @@ -51,7 +51,7 @@ public function cancel() */ public function promise() { - if (null === $this->promise) { + if ($this->promise === null) { try { $this->promise = resolve(\call_user_func($this->factory)); } catch (\Throwable $exception) { diff --git a/src/Promise.php b/src/Promise.php index 33759e6..aff441e 100644 --- a/src/Promise.php +++ b/src/Promise.php @@ -6,14 +6,12 @@ class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface { private $canceller; private $result; - private $handlers = []; private $progressHandlers = []; - private $requiredCancelRequests = 0; private $cancelRequests = 0; - public function __construct(callable $resolver, callable $canceller = null) + public function __construct(callable $resolver, ?callable $canceller = null) { $this->canceller = $canceller; @@ -25,13 +23,13 @@ public function __construct(callable $resolver, callable $canceller = null) $this->call($cb); } - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function then(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { - if (null !== $this->result) { + if ($this->result !== null) { return $this->result->then($onFulfilled, $onRejected, $onProgress); } - if (null === $this->canceller) { + if ($this->canceller === null) { return new static($this->resolver($onFulfilled, $onRejected, $onProgress)); } @@ -51,13 +49,13 @@ static function () use (&$parent) { } $parent = null; - } + }, ); } - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function done(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { - if (null !== $this->result) { + if ($this->result !== null) { return $this->result->done($onFulfilled, $onRejected, $onProgress); } @@ -102,7 +100,7 @@ public function progress(callable $onProgress) public function cancel() { - if (null === $this->canceller || null !== $this->result) { + if ($this->canceller === null || $this->result !== null) { return; } @@ -112,7 +110,7 @@ public function cancel() $this->call($canceller); } - private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + private function resolver(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) { if ($onProgress) { @@ -141,7 +139,7 @@ private function resolver(callable $onFulfilled = null, callable $onRejected = n private function reject($reason = null) { - if (null !== $this->result) { + if ($this->result !== null) { return; } @@ -154,7 +152,7 @@ private function settle(ExtendedPromiseInterface $promise) if ($promise === $this) { $promise = new RejectedPromise( - new \LogicException('Cannot resolve a promise with itself.') + new \LogicException('Cannot resolve a promise with itself.'), ); } @@ -173,7 +171,7 @@ private function unwrap($promise) { $promise = $this->extract($promise); - while ($promise instanceof self && null !== $promise->result) { + while ($promise instanceof self && $promise->result !== null) { $promise = $this->extract($promise->result); } @@ -222,8 +220,8 @@ private function call(callable $cb) // garbage cycles if any callback creates an Exception. // These assumptions are covered by the test suite, so if you ever feel like // refactoring this, go ahead, any alternative suggestions are welcome! - $target =& $this; - $progressHandlers =& $this->progressHandlers; + $target = & $this; + $progressHandlers = & $this->progressHandlers; $callback( static function ($value = null) use (&$target) { @@ -242,7 +240,7 @@ static function ($update = null) use (&$progressHandlers) { foreach ($progressHandlers as $handler) { $handler($update); } - } + }, ); } } catch (\Throwable $e) { diff --git a/src/PromiseInterface.php b/src/PromiseInterface.php index edcb007..dfaf436 100644 --- a/src/PromiseInterface.php +++ b/src/PromiseInterface.php @@ -32,10 +32,8 @@ interface PromiseInterface * than once. * 3. `$onProgress` (deprecated) may be called multiple times. * - * @param callable|null $onFulfilled - * @param callable|null $onRejected * @param callable|null $onProgress This argument is deprecated and should not be used anymore. * @return PromiseInterface */ - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); + public function then(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null); } diff --git a/src/RejectedPromise.php b/src/RejectedPromise.php index 09cd4ab..65a0515 100644 --- a/src/RejectedPromise.php +++ b/src/RejectedPromise.php @@ -18,9 +18,9 @@ public function __construct($reason = null) $this->reason = $reason; } - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function then(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { - if (null === $onRejected) { + if ($onRejected === null) { return $this; } @@ -33,9 +33,9 @@ public function then(callable $onFulfilled = null, callable $onRejected = null, } } - public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + public function done(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { - if (null === $onRejected) { + if ($onRejected === null) { throw UnhandledRejectionException::resolve($this->reason); } @@ -73,7 +73,5 @@ public function progress(callable $onProgress) return $this; } - public function cancel() - { - } + public function cancel() {} } diff --git a/src/UnhandledRejectionException.php b/src/UnhandledRejectionException.php index e7fe2f7..c224aef 100644 --- a/src/UnhandledRejectionException.php +++ b/src/UnhandledRejectionException.php @@ -6,15 +6,6 @@ class UnhandledRejectionException extends \RuntimeException { private $reason; - public static function resolve($reason) - { - if ($reason instanceof \Exception || $reason instanceof \Throwable) { - return $reason; - } - - return new static($reason); - } - public function __construct($reason) { $this->reason = $reason; @@ -24,6 +15,15 @@ public function __construct($reason) parent::__construct($message, 0); } + public static function resolve($reason) + { + if ($reason instanceof \Exception || $reason instanceof \Throwable) { + return $reason; + } + + return new static($reason); + } + public function getReason() { return $this->reason; diff --git a/src/functions.php b/src/functions.php index d4bab05..01df133 100644 --- a/src/functions.php +++ b/src/functions.php @@ -175,10 +175,10 @@ function some($promisesOrValues, $howMany) \sprintf( 'Input array must contain at least %d item%s but contains only %s item%s.', $howMany, - 1 === $howMany ? '' : 's', + $howMany === 1 ? '' : 's', $len, - 1 === $len ? '' : 's' - ) + $len === 1 ? '' : 's', + ), ); } @@ -195,7 +195,7 @@ function some($promisesOrValues, $howMany) $values[$i] = $val; - if (0 === --$toResolve) { + if (--$toResolve === 0) { $resolve($values); } }; @@ -207,7 +207,7 @@ function some($promisesOrValues, $howMany) $reasons[$i] = $reason; - if (0 === --$toReject) { + if (--$toReject === 0) { $reject($reasons); } }; @@ -229,7 +229,6 @@ function some($promisesOrValues, $howMany) * value of a promise or value in `$promisesOrValues`. * * @param array $promisesOrValues - * @param callable $mapFunc * @return PromiseInterface */ function map($promisesOrValues, callable $mapFunc) @@ -258,12 +257,12 @@ function map($promisesOrValues, callable $mapFunc) function ($mapped) use ($i, &$values, &$toResolve, $resolve) { $values[$i] = $mapped; - if (0 === --$toResolve) { + if (--$toResolve === 0) { $resolve($values); } }, $reject, - $notify + $notify, ); } }, $reject, $notify); @@ -277,7 +276,6 @@ function ($mapped) use ($i, &$values, &$toResolve, $resolve) { * value. * * @param array $promisesOrValues - * @param callable $reduceFunc * @param mixed $initialValue * @return PromiseInterface */ @@ -320,6 +318,7 @@ function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) /** * @internal + * @param mixed $object */ function _checkTypehint(callable $callback, $object) { @@ -366,6 +365,7 @@ function _checkTypehint(callable $callback, $object) break; case $type instanceof \ReflectionIntersectionType: $isTypeUnion = false; + // no break case $type instanceof \ReflectionUnionType: $types = $type->getTypes(); break; diff --git a/src/functions_include.php b/src/functions_include.php index bd0c54f..750fe6a 100644 --- a/src/functions_include.php +++ b/src/functions_include.php @@ -1,5 +1,5 @@ assertSame(0, \gc_collect_cycles()); } - /** - * Test that checks number of garbage cycles after throwing from a canceller - * that explicitly uses a reference to the promise. This is rather synthetic, - * actual use cases often have implicit (hidden) references which ought not - * to be stored in the stack trace. - * - * Reassigned arguments only show up in the stack trace in PHP 7, so we can't - * avoid this on legacy PHP. As an alternative, consider explicitly unsetting - * any references before throwing. - */ - #[\PHPUnit\Framework\Attributes\RequiresPhp('7')] - #[\PHPUnit\Framework\Attributes\Test] - public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerWithReferenceThrowsException(): void - { - \gc_collect_cycles(); - $promise = new Promise(static function (): void {}, static function () use (&$promise): void { - throw new \Exception('foo'); - }); - $promise->cancel(); - unset($promise); - - $this->assertSame(0, \gc_collect_cycles()); - } - - /** - * @see self::shouldRejectWithoutCreatingGarbageCyclesIfCancellerWithReferenceThrowsException - */ - #[\PHPUnit\Framework\Attributes\RequiresPhp('7')] - #[\PHPUnit\Framework\Attributes\Test] - public function shouldRejectWithoutCreatingGarbageCyclesIfResolverWithReferenceThrowsException(): void - { - \gc_collect_cycles(); - $promise = new Promise(static function () use (&$promise): void { - throw new \Exception('foo'); - }); - unset($promise); - - $this->assertSame(0, \gc_collect_cycles()); - } - - /** - * @see self::shouldRejectWithoutCreatingGarbageCyclesIfCancellerWithReferenceThrowsException - */ - #[\PHPUnit\Framework\Attributes\RequiresPhp('7')] - #[\PHPUnit\Framework\Attributes\Test] - public function shouldRejectWithoutCreatingGarbageCyclesIfCancellerHoldsReferenceAndResolverThrowsException(): void - { - \gc_collect_cycles(); - $promise = new Promise(static function (): void { - throw new \Exception('foo'); - }, static function () use (&$promise): void {}); - unset($promise); - - $this->assertSame(0, \gc_collect_cycles()); - } - #[\PHPUnit\Framework\Attributes\Test] public function shouldIgnoreNotifyAfterReject(): void { From 588c0d2d8ad1a1663f581a7dafd0be783f3e120d Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 19:29:15 +0400 Subject: [PATCH 05/15] refactor: Migrate codebase to PHP 8.1 --- src/CancellationQueue.php | 3 +- src/Deferred.php | 2 +- src/FulfilledPromise.php | 10 ++---- src/LazyPromise.php | 4 +-- src/Promise.php | 35 ++++++------------ src/RejectedPromise.php | 10 ++---- src/UnhandledRejectionException.php | 6 +--- src/functions.php | 36 ++++++++----------- tests/CancellationQueueTest.php | 2 +- tests/DeferredTest.php | 10 +++--- tests/FunctionAnyTest.php | 6 ++-- tests/FunctionCheckTypehintTest.php | 18 +++++----- tests/FunctionMapTest.php | 8 ++--- tests/FunctionReduceTest.php | 8 ++--- tests/FunctionResolveTest.php | 12 ++----- tests/FunctionSomeTest.php | 22 +++++------- tests/LazyPromiseTest.php | 18 ++++------ .../PromiseAdapter/CallbackPromiseAdapter.php | 7 +--- tests/PromiseTest.php | 4 +-- tests/PromiseTest/CancelTestTrait.php | 8 ++--- tests/PromiseTest/NotifyTestTrait.php | 8 ++--- .../PromiseTest/PromiseFulfilledTestTrait.php | 28 ++++----------- .../PromiseTest/PromiseRejectedTestTrait.php | 32 +++++------------ tests/PromiseTest/RejectTestTrait.php | 24 ++++--------- tests/PromiseTest/ResolveTestTrait.php | 16 +++------ tests/fixtures/SimpleFulfilledTestPromise.php | 4 +-- .../fixtures/SimpleFulfilledTestThenable.php | 4 +-- tests/fixtures/SimpleRejectedTestPromise.php | 4 +-- 28 files changed, 108 insertions(+), 241 deletions(-) diff --git a/src/CancellationQueue.php b/src/CancellationQueue.php index c2624c1..1a9e6fc 100644 --- a/src/CancellationQueue.php +++ b/src/CancellationQueue.php @@ -39,8 +39,7 @@ private function drain() try { $cancellable->cancel(); - } catch (\Throwable $exception) { - } catch (\Exception $exception) { + } catch (\Throwable|\Exception $exception) { } unset($this->queue[$i]); diff --git a/src/Deferred.php b/src/Deferred.php index df5e122..93786d5 100644 --- a/src/Deferred.php +++ b/src/Deferred.php @@ -18,7 +18,7 @@ public function __construct(?callable $canceller = null) public function promise() { if ($this->promise === null) { - $this->promise = new Promise(function ($resolve, $reject, $notify) { + $this->promise = new Promise(function ($resolve, $reject, $notify): void { $this->resolveCallback = $resolve; $this->rejectCallback = $reject; $this->notifyCallback = $notify; diff --git a/src/FulfilledPromise.php b/src/FulfilledPromise.php index 1111e92..72a7779 100644 --- a/src/FulfilledPromise.php +++ b/src/FulfilledPromise.php @@ -26,9 +26,7 @@ public function then(?callable $onFulfilled = null, ?callable $onRejected = null try { return resolve($onFulfilled($this->value)); - } catch (\Throwable $exception) { - return new RejectedPromise($exception); - } catch (\Exception $exception) { + } catch (\Throwable|\Exception $exception) { return new RejectedPromise($exception); } } @@ -53,11 +51,7 @@ public function otherwise(callable $onRejected) public function always(callable $onFulfilledOrRejected) { - return $this->then(function ($value) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($value) { - return $value; - }); - }); + return $this->then(fn($value) => resolve($onFulfilledOrRejected())->then(fn() => $value)); } public function progress(callable $onProgress) diff --git a/src/LazyPromise.php b/src/LazyPromise.php index 827a0a6..59f6f5c 100644 --- a/src/LazyPromise.php +++ b/src/LazyPromise.php @@ -54,9 +54,7 @@ public function promise() if ($this->promise === null) { try { $this->promise = resolve(\call_user_func($this->factory)); - } catch (\Throwable $exception) { - $this->promise = new RejectedPromise($exception); - } catch (\Exception $exception) { + } catch (\Throwable|\Exception $exception) { $this->promise = new RejectedPromise($exception); } } diff --git a/src/Promise.php b/src/Promise.php index aff441e..14d3511 100644 --- a/src/Promise.php +++ b/src/Promise.php @@ -43,7 +43,7 @@ public function then(?callable $onFulfilled = null, ?callable $onRejected = null return new static( $this->resolver($onFulfilled, $onRejected, $onProgress), - static function () use (&$parent) { + static function () use (&$parent): void { if (++$parent->cancelRequests >= $parent->requiredCancelRequests) { $parent->cancel(); } @@ -59,7 +59,7 @@ public function done(?callable $onFulfilled = null, ?callable $onRejected = null return $this->result->done($onFulfilled, $onRejected, $onProgress); } - $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) { + $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected): void { $promise ->done($onFulfilled, $onRejected); }; @@ -82,15 +82,7 @@ public function otherwise(callable $onRejected) public function always(callable $onFulfilledOrRejected) { - return $this->then(static function ($value) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($value) { - return $value; - }); - }, static function ($reason) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($reason) { - return new RejectedPromise($reason); - }); - }); + return $this->then(static fn($value) => resolve($onFulfilledOrRejected())->then(fn() => $value), static fn($reason) => resolve($onFulfilledOrRejected())->then(fn() => new RejectedPromise($reason))); } public function progress(callable $onProgress) @@ -112,14 +104,12 @@ public function cancel() private function resolver(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null) { - return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) { + return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress): void { if ($onProgress) { - $progressHandler = static function ($update) use ($notify, $onProgress) { + $progressHandler = static function ($update) use ($notify, $onProgress): void { try { $notify($onProgress($update)); - } catch (\Throwable $e) { - $notify($e); - } catch (\Exception $e) { + } catch (\Throwable|\Exception $e) { $notify($e); } }; @@ -127,7 +117,7 @@ private function resolver(?callable $onFulfilled = null, ?callable $onRejected = $progressHandler = $notify; } - $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) { + $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler): void { $promise ->then($onFulfilled, $onRejected) ->done($resolve, $reject, $progressHandler); @@ -224,29 +214,26 @@ private function call(callable $cb) $progressHandlers = & $this->progressHandlers; $callback( - static function ($value = null) use (&$target) { + static function ($value = null) use (&$target): void { if ($target !== null) { $target->settle(resolve($value)); $target = null; } }, - static function ($reason = null) use (&$target) { + static function ($reason = null) use (&$target): void { if ($target !== null) { $target->reject($reason); $target = null; } }, - static function ($update = null) use (&$progressHandlers) { + static function ($update = null) use (&$progressHandlers): void { foreach ($progressHandlers as $handler) { $handler($update); } }, ); } - } catch (\Throwable $e) { - $target = null; - $this->reject($e); - } catch (\Exception $e) { + } catch (\Throwable|\Exception $e) { $target = null; $this->reject($e); } diff --git a/src/RejectedPromise.php b/src/RejectedPromise.php index 65a0515..f2a07a6 100644 --- a/src/RejectedPromise.php +++ b/src/RejectedPromise.php @@ -26,9 +26,7 @@ public function then(?callable $onFulfilled = null, ?callable $onRejected = null try { return resolve($onRejected($this->reason)); - } catch (\Throwable $exception) { - return new RejectedPromise($exception); - } catch (\Exception $exception) { + } catch (\Throwable|\Exception $exception) { return new RejectedPromise($exception); } } @@ -61,11 +59,7 @@ public function otherwise(callable $onRejected) public function always(callable $onFulfilledOrRejected) { - return $this->then(null, function ($reason) use ($onFulfilledOrRejected) { - return resolve($onFulfilledOrRejected())->then(function () use ($reason) { - return new RejectedPromise($reason); - }); - }); + return $this->then(null, fn($reason) => resolve($onFulfilledOrRejected())->then(fn() => new RejectedPromise($reason))); } public function progress(callable $onProgress) diff --git a/src/UnhandledRejectionException.php b/src/UnhandledRejectionException.php index c224aef..55c3f96 100644 --- a/src/UnhandledRejectionException.php +++ b/src/UnhandledRejectionException.php @@ -4,12 +4,8 @@ class UnhandledRejectionException extends \RuntimeException { - private $reason; - - public function __construct($reason) + public function __construct(private $reason) { - $this->reason = $reason; - $message = \sprintf('Unhandled Rejection: %s', \json_encode($reason)); parent::__construct($message, 0); diff --git a/src/functions.php b/src/functions.php index 01df133..908c64e 100644 --- a/src/functions.php +++ b/src/functions.php @@ -31,7 +31,7 @@ function resolve($promiseOrValue = null) $canceller = [$promiseOrValue, 'cancel']; } - return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) { + return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue): void { $promiseOrValue->then($resolve, $reject, $notify); }, $canceller); } @@ -58,9 +58,7 @@ function resolve($promiseOrValue = null) function reject($promiseOrValue = null) { if ($promiseOrValue instanceof PromiseInterface) { - return resolve($promiseOrValue)->then(function ($value) { - return new RejectedPromise($value); - }); + return resolve($promiseOrValue)->then(fn($value) => new RejectedPromise($value)); } return new RejectedPromise($promiseOrValue); @@ -77,9 +75,7 @@ function reject($promiseOrValue = null) */ function all($promisesOrValues) { - return map($promisesOrValues, function ($val) { - return $val; - }); + return map($promisesOrValues, fn($val) => $val); } /** @@ -97,9 +93,9 @@ function race($promisesOrValues) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue) { + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify) { + ->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify): void { if (!is_array($array) || !$array) { $resolve(); return; @@ -132,9 +128,7 @@ function race($promisesOrValues) function any($promisesOrValues) { return some($promisesOrValues, 1) - ->then(function ($val) { - return \array_shift($val); - }); + ->then(fn($val) => \array_shift($val)); } /** @@ -160,9 +154,9 @@ function some($promisesOrValues, $howMany) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) { + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) { + ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify): void { if (!\is_array($array) || $howMany < 1) { $resolve([]); return; @@ -188,7 +182,7 @@ function some($promisesOrValues, $howMany) $reasons = []; foreach ($array as $i => $promiseOrValue) { - $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) { + $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve): void { if ($toResolve < 1 || $toReject < 1) { return; } @@ -200,7 +194,7 @@ function some($promisesOrValues, $howMany) } }; - $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) { + $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject): void { if ($toResolve < 1 || $toReject < 1) { return; } @@ -236,9 +230,9 @@ function map($promisesOrValues, callable $mapFunc) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue) { + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify) { + ->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify): void { if (!\is_array($array) || !$array) { $resolve([]); return; @@ -254,7 +248,7 @@ function map($promisesOrValues, callable $mapFunc) resolve($promiseOrValue) ->then($mapFunc) ->done( - function ($mapped) use ($i, &$values, &$toResolve, $resolve) { + function ($mapped) use ($i, &$values, &$toResolve, $resolve): void { $values[$i] = $mapped; if (--$toResolve === 0) { @@ -284,9 +278,9 @@ function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue) { + return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify) { + ->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify): void { if (!\is_array($array)) { $array = []; } diff --git a/tests/CancellationQueueTest.php b/tests/CancellationQueueTest.php index 7899428..0d66248 100644 --- a/tests/CancellationQueueTest.php +++ b/tests/CancellationQueueTest.php @@ -77,7 +77,7 @@ public function rethrowsExceptionsThrownFromCancel(): void $this->setExpectedException('\Exception', 'test'); $mock = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock ->expects($this->once()) diff --git a/tests/DeferredTest.php b/tests/DeferredTest.php index ef05304..dd8055b 100644 --- a/tests/DeferredTest.php +++ b/tests/DeferredTest.php @@ -15,11 +15,11 @@ public function getPromiseTestAdapter(?callable $canceller = null) $d = new Deferred($canceller); return new CallbackPromiseAdapter([ - 'promise' => [$d, 'promise'], - 'resolve' => [$d, 'resolve'], - 'reject' => [$d, 'reject'], - 'notify' => [$d, 'progress'], - 'settle' => [$d, 'resolve'], + 'promise' => $d->promise(...), + 'resolve' => $d->resolve(...), + 'reject' => $d->reject(...), + 'notify' => $d->progress(...), + 'settle' => $d->resolve(...), ]); } diff --git a/tests/FunctionAnyTest.php b/tests/FunctionAnyTest.php index ed90ae6..4f292f0 100644 --- a/tests/FunctionAnyTest.php +++ b/tests/FunctionAnyTest.php @@ -16,10 +16,8 @@ public function shouldRejectWithLengthExceptionWithEmptyInputArray(): void ->expects($this->once()) ->method('__invoke') ->with( - $this->callback(static function ($exception) { - return $exception instanceof LengthException && - $exception->getMessage() === 'Input array must contain at least 1 item but contains only 0 items.'; - }), + $this->callback(static fn($exception) => $exception instanceof LengthException && + $exception->getMessage() === 'Input array must contain at least 1 item but contains only 0 items.'), ); any([]) diff --git a/tests/FunctionCheckTypehintTest.php b/tests/FunctionCheckTypehintTest.php index d8b8973..11226bf 100644 --- a/tests/FunctionCheckTypehintTest.php +++ b/tests/FunctionCheckTypehintTest.php @@ -72,8 +72,8 @@ public function shouldAcceptObjectMethodCallbackWithUnionTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithUnionTypehint(): void { - self::assertTrue(_checkTypehint([\React\Promise\CallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new \InvalidArgumentException())); - self::assertFalse(_checkTypehint([\React\Promise\CallbackWithUnionTypehintClass::class, 'testCallbackStatic'], new \Exception())); + self::assertTrue(_checkTypehint(\React\Promise\CallbackWithUnionTypehintClass::testCallbackStatic(...), new \InvalidArgumentException())); + self::assertFalse(_checkTypehint(\React\Promise\CallbackWithUnionTypehintClass::testCallbackStatic(...), new \Exception())); } #[\PHPUnit\Framework\Attributes\RequiresPhp('8.1')] @@ -98,9 +98,9 @@ public function shouldAcceptObjectMethodCallbackWithIntersectionTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithIntersectionTypehint(): void { - self::assertFalse(_checkTypehint([\React\Promise\CallbackWithIntersectionTypehintClass::class, 'testCallbackStatic'], new \RuntimeException())); - self::assertFalse(_checkTypehint([\React\Promise\CallbackWithIntersectionTypehintClass::class, 'testCallbackStatic'], new CountableNonException())); - self::assertTrue(_checkTypehint([\React\Promise\CallbackWithIntersectionTypehintClass::class, 'testCallbackStatic'], new CountableException())); + self::assertFalse(_checkTypehint(\React\Promise\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new \RuntimeException())); + self::assertFalse(_checkTypehint(\React\Promise\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new CountableNonException())); + self::assertTrue(_checkTypehint(\React\Promise\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new CountableException())); } #[\PHPUnit\Framework\Attributes\RequiresPhp('8.2')] @@ -125,9 +125,9 @@ public function shouldAcceptObjectMethodCallbackWithDNFTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithDNFTypehint(): void { - self::assertFalse(_checkTypehint([\React\Promise\CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new \RuntimeException())); - self::assertTrue(_checkTypehint([\React\Promise\CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new CountableException())); - self::assertTrue(_checkTypehint([\React\Promise\CallbackWithDNFTypehintClass::class, 'testCallbackStatic'], new ArrayAccessibleException())); + self::assertFalse(_checkTypehint(\React\Promise\CallbackWithDNFTypehintClass::testCallbackStatic(...), new \RuntimeException())); + self::assertTrue(_checkTypehint(\React\Promise\CallbackWithDNFTypehintClass::testCallbackStatic(...), new CountableException())); + self::assertTrue(_checkTypehint(\React\Promise\CallbackWithDNFTypehintClass::testCallbackStatic(...), new ArrayAccessibleException())); } #[\PHPUnit\Framework\Attributes\Test] @@ -157,7 +157,7 @@ public function shouldAcceptObjectMethodCallbackWithoutTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithoutTypehint(): void { - $this->assertTrue(_checkTypehint([\React\Promise\CallbackWithoutTypehintClass::class, 'testCallbackStatic'], new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint(\React\Promise\CallbackWithoutTypehintClass::testCallbackStatic(...), new \InvalidArgumentException())); } } diff --git a/tests/FunctionMapTest.php b/tests/FunctionMapTest.php index 7ff7ac9..187eaef 100644 --- a/tests/FunctionMapTest.php +++ b/tests/FunctionMapTest.php @@ -186,15 +186,11 @@ public function shouldCancelInputArrayPromises(): void protected function mapper() { - return static function ($val) { - return $val * 2; - }; + return static fn($val) => $val * 2; } protected function promiseMapper() { - return static function ($val) { - return resolve($val * 2); - }; + return static fn($val) => resolve($val * 2); } } diff --git a/tests/FunctionReduceTest.php b/tests/FunctionReduceTest.php index a15a743..9c3f966 100644 --- a/tests/FunctionReduceTest.php +++ b/tests/FunctionReduceTest.php @@ -335,15 +335,11 @@ public function shouldCancelInputArrayPromises(): void protected function plus() { - return static function ($sum, $val) { - return $sum + $val; - }; + return static fn($sum, $val) => $sum + $val; } protected function append() { - return static function ($sum, $val) { - return $sum . $val; - }; + return static fn($sum, $val) => $sum . $val; } } diff --git a/tests/FunctionResolveTest.php b/tests/FunctionResolveTest.php index eb5c0c7..e5ceed5 100644 --- a/tests/FunctionResolveTest.php +++ b/tests/FunctionResolveTest.php @@ -103,14 +103,10 @@ public function shouldSupportDeepNestingInPromiseChains(): void $d = new Deferred(); $d->resolve($val); - $identity = static function ($val) { - return $val; - }; + $identity = (static fn($val) => $val); return resolve($d->promise()->then($identity))->then( - static function ($val) { - return !$val; - }, + static fn($val) => !$val, ); }))); @@ -135,9 +131,7 @@ public function shouldSupportVeryDeepNestedPromises(): void $last = $p; for ($j = 0; $j < 10; $j++) { - $last = $last->then(static function ($result) { - return $result; - }); + $last = $last->then(static fn($result) => $result); } } diff --git a/tests/FunctionSomeTest.php b/tests/FunctionSomeTest.php index d3d9024..4a7b0e2 100644 --- a/tests/FunctionSomeTest.php +++ b/tests/FunctionSomeTest.php @@ -16,10 +16,8 @@ public function shouldRejectWithLengthExceptionWithEmptyInputArray(): void ->expects($this->once()) ->method('__invoke') ->with( - $this->callback(static function ($exception) { - return $exception instanceof LengthException && - $exception->getMessage() === 'Input array must contain at least 1 item but contains only 0 items.'; - }), + $this->callback(static fn($exception) => $exception instanceof LengthException && + $exception->getMessage() === 'Input array must contain at least 1 item but contains only 0 items.'), ); some( @@ -36,10 +34,8 @@ public function shouldRejectWithLengthExceptionWithInputArrayContainingNotEnough ->expects($this->once()) ->method('__invoke') ->with( - $this->callback(static function ($exception) { - return $exception instanceof LengthException && - $exception->getMessage() === 'Input array must contain at least 4 items but contains only 3 items.'; - }), + $this->callback(static fn($exception) => $exception instanceof LengthException && + $exception->getMessage() === 'Input array must contain at least 4 items but contains only 3 items.'), ); some( @@ -187,7 +183,7 @@ public function shouldRejectWhenInputPromiseRejects(): void public function shouldCancelInputPromise(): void { $mock = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock ->expects($this->once()) @@ -200,14 +196,14 @@ public function shouldCancelInputPromise(): void public function shouldCancelInputArrayPromises(): void { $mock1 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock1 ->expects($this->once()) ->method('cancel'); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->once()) @@ -228,7 +224,7 @@ public function shouldNotCancelOtherPendingInputArrayPromisesIfEnoughPromisesFul $deferred->resolve(); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->never()) @@ -249,7 +245,7 @@ public function shouldNotCancelOtherPendingInputArrayPromisesIfEnoughPromisesRej $deferred->reject(); $mock2 = $this - ->getMockBuilder('React\Promise\CancellablePromiseInterface') + ->getMockBuilder(\React\Promise\CancellablePromiseInterface::class) ->getMock(); $mock2 ->expects($this->never()) diff --git a/tests/LazyPromiseTest.php b/tests/LazyPromiseTest.php index 7542e39..c721fcc 100644 --- a/tests/LazyPromiseTest.php +++ b/tests/LazyPromiseTest.php @@ -14,18 +14,14 @@ public function getPromiseTestAdapter(?callable $canceller = null) { $d = new Deferred($canceller); - $factory = static function () use ($d) { - return $d->promise(); - }; + $factory = (static fn() => $d->promise()); return new CallbackPromiseAdapter([ - 'promise' => static function () use ($factory) { - return new LazyPromise($factory); - }, - 'resolve' => [$d, 'resolve'], - 'reject' => [$d, 'reject'], - 'notify' => [$d, 'progress'], - 'settle' => [$d, 'resolve'], + 'promise' => static fn() => new LazyPromise($factory), + 'resolve' => $d->resolve(...), + 'reject' => $d->reject(...), + 'notify' => $d->progress(...), + 'settle' => $d->resolve(...), ]); } @@ -82,7 +78,7 @@ public function shouldReturnPromiseIfFactoryReturnsNull(): void ->will($this->returnValue(null)); $p = new LazyPromise($factory); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $p->then()); + $this->assertInstanceOf(\React\Promise\PromiseInterface::class, $p->then()); } #[\PHPUnit\Framework\Attributes\Test] diff --git a/tests/PromiseAdapter/CallbackPromiseAdapter.php b/tests/PromiseAdapter/CallbackPromiseAdapter.php index bd85fc5..4d539ea 100644 --- a/tests/PromiseAdapter/CallbackPromiseAdapter.php +++ b/tests/PromiseAdapter/CallbackPromiseAdapter.php @@ -6,12 +6,7 @@ class CallbackPromiseAdapter implements PromiseAdapterInterface { - private $callbacks; - - public function __construct(array $callbacks) - { - $this->callbacks = $callbacks; - } + public function __construct(private array $callbacks) {} public function promise() { diff --git a/tests/PromiseTest.php b/tests/PromiseTest.php index 4365de4..e160dd0 100644 --- a/tests/PromiseTest.php +++ b/tests/PromiseTest.php @@ -21,9 +21,7 @@ public function getPromiseTestAdapter(?callable $canceller = null) }, $canceller); return new CallbackPromiseAdapter([ - 'promise' => static function () use ($promise) { - return $promise; - }, + 'promise' => static fn() => $promise, 'resolve' => $resolveCallback, 'reject' => $rejectCallback, 'notify' => $progressCallback, diff --git a/tests/PromiseTest/CancelTestTrait.php b/tests/PromiseTest/CancelTestTrait.php index 3792393..e7934c3 100644 --- a/tests/PromiseTest/CancelTestTrait.php +++ b/tests/PromiseTest/CancelTestTrait.php @@ -160,17 +160,13 @@ public function cancelShouldCallCancellerFromDeepNestedPromiseChain(): void $adapter = $this->getPromiseTestAdapter($mock); $promise = $adapter->promise() - ->then(static function () { - return new Promise\Promise(static function (): void {}); - }) + ->then(static fn() => new Promise\Promise(static function (): void {})) ->then(static function () { $d = new Promise\Deferred(); return $d->promise(); }) - ->then(static function () { - return new Promise\Promise(static function (): void {}); - }); + ->then(static fn() => new Promise\Promise(static function (): void {})); $promise->cancel(); } diff --git a/tests/PromiseTest/NotifyTestTrait.php b/tests/PromiseTest/NotifyTestTrait.php index 9e70013..566da9f 100644 --- a/tests/PromiseTest/NotifyTestTrait.php +++ b/tests/PromiseTest/NotifyTestTrait.php @@ -152,9 +152,7 @@ public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToA $adapter->resolve(); $adapter->promise() - ->then(static function () use ($promise2) { - return $promise2; - }) + ->then(static fn() => $promise2) ->then( $this->expectCallableNever(), $this->expectCallableNever(), @@ -181,9 +179,7 @@ public function notifyShouldForwardProgressEventsWhenIntermediaryCallbackTiedToA ->with($sentinel); $adapter->promise() - ->then(static function () use ($promise2) { - return $promise2; - }) + ->then(static fn() => $promise2) ->then( $this->expectCallableNever(), $this->expectCallableNever(), diff --git a/tests/PromiseTest/PromiseFulfilledTestTrait.php b/tests/PromiseTest/PromiseFulfilledTestTrait.php index 55191eb..7af050a 100644 --- a/tests/PromiseTest/PromiseFulfilledTestTrait.php +++ b/tests/PromiseTest/PromiseFulfilledTestTrait.php @@ -86,9 +86,7 @@ public function thenShouldForwardCallbackResultToNextCallback(): void $adapter->resolve(1); $adapter->promise() ->then( - static function ($val) { - return $val + 1; - }, + static fn($val) => $val + 1, $this->expectCallableNever(), ) ->then( @@ -111,9 +109,7 @@ public function thenShouldForwardPromisedCallbackResultValueToNextCallback(): vo $adapter->resolve(1); $adapter->promise() ->then( - static function ($val) { - return \React\Promise\resolve($val + 1); - }, + static fn($val) => \React\Promise\resolve($val + 1), $this->expectCallableNever(), ) ->then( @@ -136,9 +132,7 @@ public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackReturnsARejec $adapter->resolve(1); $adapter->promise() ->then( - static function ($val) { - return \React\Promise\reject($val + 1); - }, + static fn($val) => \React\Promise\reject($val + 1), $this->expectCallableNever(), ) ->then( @@ -234,9 +228,7 @@ public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandler $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); $adapter->resolve(1); - $this->assertNull($adapter->promise()->done(static function () { - return \React\Promise\reject(); - })); + $this->assertNull($adapter->promise()->done(static fn() => \React\Promise\reject())); } #[\PHPUnit\Framework\Attributes\Test] @@ -282,9 +274,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromiseForFulf $adapter->resolve($value); $adapter->promise() - ->always(static function () { - return 1; - }) + ->always(static fn() => 1) ->then($mock); } @@ -303,9 +293,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromiseForFulfill $adapter->resolve($value); $adapter->promise() - ->always(static function () { - return \React\Promise\resolve(1); - }) + ->always(static fn() => \React\Promise\resolve(1)) ->then($mock); } @@ -345,9 +333,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForFulfilledPromise(): void $adapter->resolve(1); $adapter->promise() - ->always(static function () use ($exception) { - return \React\Promise\reject($exception); - }) + ->always(static fn() => \React\Promise\reject($exception)) ->then(null, $mock); } } diff --git a/tests/PromiseTest/PromiseRejectedTestTrait.php b/tests/PromiseTest/PromiseRejectedTestTrait.php index f76d160..bfbcf5c 100644 --- a/tests/PromiseTest/PromiseRejectedTestTrait.php +++ b/tests/PromiseTest/PromiseRejectedTestTrait.php @@ -95,9 +95,7 @@ public function shouldSwitchFromErrbacksToCallbacksWhenErrbackDoesNotExplicitlyP $adapter->promise() ->then( $this->expectCallableNever(), - static function ($val) { - return $val + 1; - }, + static fn($val) => $val + 1, ) ->then( $mock, @@ -120,9 +118,7 @@ public function shouldSwitchFromErrbacksToCallbacksWhenErrbackReturnsAResolution $adapter->promise() ->then( $this->expectCallableNever(), - static function ($val) { - return \React\Promise\resolve($val + 1); - }, + static fn($val) => \React\Promise\resolve($val + 1), ) ->then( $mock, @@ -176,9 +172,7 @@ public function shouldPropagateRejectionsWhenErrbackReturnsARejection(): void $adapter->promise() ->then( $this->expectCallableNever(), - static function ($val) { - return \React\Promise\reject($val + 1); - }, + static fn($val) => \React\Promise\reject($val + 1), ) ->then( $this->expectCallableNever(), @@ -252,9 +246,7 @@ public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRe $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); $adapter->reject(1); - $this->assertNull($adapter->promise()->done(null, static function () { - return \React\Promise\reject(); - })); + $this->assertNull($adapter->promise()->done(null, static fn() => \React\Promise\reject())); } #[\PHPUnit\Framework\Attributes\Test] @@ -265,9 +257,7 @@ public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWith $this->setExpectedException('\Exception', 'UnhandledRejectionException'); $adapter->reject(1); - $this->assertNull($adapter->promise()->done(null, static function () { - return \React\Promise\reject(new \Exception('UnhandledRejectionException')); - })); + $this->assertNull($adapter->promise()->done(null, static fn() => \React\Promise\reject(new \Exception('UnhandledRejectionException')))); } #[\PHPUnit\Framework\Attributes\Test] @@ -419,9 +409,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromiseFor $adapter->reject($exception); $adapter->promise() - ->always(static function () { - return 1; - }) + ->always(static fn() => 1) ->then(null, $mock); } @@ -440,9 +428,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromiseForRej $adapter->reject($exception); $adapter->promise() - ->always(static function () { - return \React\Promise\resolve(1); - }) + ->always(static fn() => \React\Promise\resolve(1)) ->then(null, $mock); } @@ -484,9 +470,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForRejectedPromise(): void $adapter->reject($exception1); $adapter->promise() - ->always(static function () use ($exception2) { - return \React\Promise\reject($exception2); - }) + ->always(static fn() => \React\Promise\reject($exception2)) ->then(null, $mock); } diff --git a/tests/PromiseTest/RejectTestTrait.php b/tests/PromiseTest/RejectTestTrait.php index 4854209..8da5fee 100644 --- a/tests/PromiseTest/RejectTestTrait.php +++ b/tests/PromiseTest/RejectTestTrait.php @@ -177,9 +177,7 @@ public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRe $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); - $this->assertNull($adapter->promise()->done(null, static function () { - return \React\Promise\reject(); - })); + $this->assertNull($adapter->promise()->done(null, static fn() => \React\Promise\reject())); $adapter->reject(1); } @@ -190,9 +188,7 @@ public function doneShouldThrowRejectionExceptionWhenRejectionHandlerRejectsWith $this->setExpectedException('\Exception', 'UnhandledRejectionException'); - $this->assertNull($adapter->promise()->done(null, static function () { - return \React\Promise\reject(new \Exception('UnhandledRejectionException')); - })); + $this->assertNull($adapter->promise()->done(null, static fn() => \React\Promise\reject(new \Exception('UnhandledRejectionException')))); $adapter->reject(1); } @@ -206,9 +202,7 @@ public function doneShouldThrowUnhandledRejectionExceptionWhenRejectionHandlerRe $d = new Deferred(); $promise = $d->promise(); - $this->assertNull($adapter->promise()->done(null, static function () use ($promise) { - return $promise; - })); + $this->assertNull($adapter->promise()->done(null, static fn() => $promise)); $adapter->reject(1); $d->reject(1); } @@ -292,9 +286,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsANonPromise(): ->with($this->identicalTo($exception)); $adapter->promise() - ->always(static function () { - return 1; - }) + ->always(static fn() => 1) ->then(null, $mock); $adapter->reject($exception); @@ -314,9 +306,7 @@ public function alwaysShouldNotSuppressRejectionWhenHandlerReturnsAPromise(): vo ->with($this->identicalTo($exception)); $adapter->promise() - ->always(static function () { - return \React\Promise\resolve(1); - }) + ->always(static fn() => \React\Promise\resolve(1)) ->then(null, $mock); $adapter->reject($exception); @@ -358,9 +348,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForRejection(): void ->with($this->identicalTo($exception)); $adapter->promise() - ->always(static function () use ($exception) { - return \React\Promise\reject($exception); - }) + ->always(static fn() => \React\Promise\reject($exception)) ->then(null, $mock); $adapter->reject($exception); diff --git a/tests/PromiseTest/ResolveTestTrait.php b/tests/PromiseTest/ResolveTestTrait.php index d61df14..babb843 100644 --- a/tests/PromiseTest/ResolveTestTrait.php +++ b/tests/PromiseTest/ResolveTestTrait.php @@ -194,9 +194,7 @@ public function doneShouldThrowUnhandledRejectionExceptionWhenFulfillmentHandler $this->setExpectedException(\React\Promise\UnhandledRejectionException::class); - $this->assertNull($adapter->promise()->done(static function () { - return \React\Promise\reject(); - })); + $this->assertNull($adapter->promise()->done(static fn() => \React\Promise\reject())); $adapter->resolve(1); } @@ -234,9 +232,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsANonPromise(): voi ->with($this->identicalTo($value)); $adapter->promise() - ->always(static function () { - return 1; - }) + ->always(static fn() => 1) ->then($mock); $adapter->resolve($value); @@ -256,9 +252,7 @@ public function alwaysShouldNotSuppressValueWhenHandlerReturnsAPromise(): void ->with($this->identicalTo($value)); $adapter->promise() - ->always(static function () { - return \React\Promise\resolve(1); - }) + ->always(static fn() => \React\Promise\resolve(1)) ->then($mock); $adapter->resolve($value); @@ -300,9 +294,7 @@ public function alwaysShouldRejectWhenHandlerRejectsForFulfillment(): void ->with($this->identicalTo($exception)); $adapter->promise() - ->always(static function () use ($exception) { - return \React\Promise\reject($exception); - }) + ->always(static fn() => \React\Promise\reject($exception)) ->then(null, $mock); $adapter->resolve(1); diff --git a/tests/fixtures/SimpleFulfilledTestPromise.php b/tests/fixtures/SimpleFulfilledTestPromise.php index 3d36001..507e824 100644 --- a/tests/fixtures/SimpleFulfilledTestPromise.php +++ b/tests/fixtures/SimpleFulfilledTestPromise.php @@ -14,9 +14,7 @@ public function then(?callable $onFulfilled = null, ?callable $onRejected = null } return new self(); - } catch (\Throwable $exception) { - return new RejectedPromise($exception); - } catch (\Exception $exception) { + } catch (\Throwable|\Exception $exception) { return new RejectedPromise($exception); } } diff --git a/tests/fixtures/SimpleFulfilledTestThenable.php b/tests/fixtures/SimpleFulfilledTestThenable.php index e136c49..7933835 100644 --- a/tests/fixtures/SimpleFulfilledTestThenable.php +++ b/tests/fixtures/SimpleFulfilledTestThenable.php @@ -14,9 +14,7 @@ public function then(?callable $onFulfilled = null, ?callable $onRejected = null } return new self(); - } catch (\Throwable $exception) { - return new RejectedPromise($exception); - } catch (\Exception $exception) { + } catch (\Throwable|\Exception $exception) { return new RejectedPromise($exception); } } diff --git a/tests/fixtures/SimpleRejectedTestPromise.php b/tests/fixtures/SimpleRejectedTestPromise.php index 6f6cddc..cdf90de 100644 --- a/tests/fixtures/SimpleRejectedTestPromise.php +++ b/tests/fixtures/SimpleRejectedTestPromise.php @@ -14,9 +14,7 @@ public function then(?callable $onFulfilled = null, ?callable $onRejected = null } return new self(); - } catch (\Throwable $exception) { - return new RejectedPromise($exception); - } catch (\Exception $exception) { + } catch (\Throwable|\Exception $exception) { return new RejectedPromise($exception); } } From f104e595a23756f306c08f580bbc672d27613475 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 19:46:05 +0400 Subject: [PATCH 06/15] test: restructurize tests; add Arch tests --- composer.json | 6 +-- tests/Arch/ArchTest.php | 42 +++++++++++++++++++ tests/{ => Unit}/CancellationQueueTest.php | 7 +++- tests/{ => Unit}/DeferredTest.php | 8 ++-- .../Fixture}/ArrayAccessibleException.php | 2 +- .../Fixture}/CallbackWithDNFTypehintClass.php | 2 +- .../CallbackWithIntersectionTypehintClass.php | 2 +- .../Fixture}/CallbackWithTypehintClass.php | 2 +- .../CallbackWithUnionTypehintClass.php | 2 +- .../Fixture}/CallbackWithoutTypehintClass.php | 2 +- .../Fixture}/CountableException.php | 2 +- .../Fixture}/CountableNonException.php | 2 +- .../Fixture}/SimpleFulfilledTestPromise.php | 5 ++- .../Fixture}/SimpleFulfilledTestThenable.php | 4 +- .../Fixture}/SimpleRejectedTestPromise.php | 5 ++- .../Fixture}/SimpleTestCancellable.php | 2 +- .../SimpleTestCancellableThenable.php | 2 +- tests/{ => Unit}/FulfilledPromiseTest.php | 10 +++-- tests/{ => Unit}/FunctionAllTest.php | 8 +++- tests/{ => Unit}/FunctionAnyTest.php | 8 +++- .../{ => Unit}/FunctionCheckTypehintTest.php | 37 ++++++++++------ tests/{ => Unit}/FunctionMapTest.php | 8 +++- tests/{ => Unit}/FunctionRaceTest.php | 8 +++- tests/{ => Unit}/FunctionReduceTest.php | 8 +++- tests/{ => Unit}/FunctionRejectTest.php | 7 +++- tests/{ => Unit}/FunctionResolveTest.php | 10 ++++- tests/{ => Unit}/FunctionSomeTest.php | 7 +++- tests/{ => Unit}/LazyPromiseTest.php | 10 +++-- .../PromiseAdapter/CallbackPromiseAdapter.php | 2 +- .../PromiseAdapterInterface.php | 2 +- tests/{ => Unit}/PromiseTest.php | 10 +++-- .../PromiseTest/CancelTestTrait.php | 4 +- .../{ => Unit}/PromiseTest/FullTestTrait.php | 2 +- .../PromiseTest/NotifyTestTrait.php | 4 +- .../PromiseTest/PromiseFulfilledTestTrait.php | 4 +- .../PromiseTest/PromisePendingTestTrait.php | 4 +- .../PromiseTest/PromiseRejectedTestTrait.php | 4 +- .../PromiseTest/PromiseSettledTestTrait.php | 4 +- .../PromiseTest/RejectTestTrait.php | 4 +- .../PromiseTest/ResolveTestTrait.php | 4 +- tests/{ => Unit}/RejectedPromiseTest.php | 10 +++-- tests/{ => Unit}/TestCase.php | 2 +- 42 files changed, 202 insertions(+), 76 deletions(-) create mode 100644 tests/Arch/ArchTest.php rename tests/{ => Unit}/CancellationQueueTest.php (92%) rename tests/{ => Unit}/DeferredTest.php (94%) rename tests/{fixtures => Unit/Fixture}/ArrayAccessibleException.php (90%) rename tests/{fixtures => Unit/Fixture}/CallbackWithDNFTypehintClass.php (90%) rename tests/{fixtures => Unit/Fixture}/CallbackWithIntersectionTypehintClass.php (87%) rename tests/{fixtures => Unit/Fixture}/CallbackWithTypehintClass.php (87%) rename tests/{fixtures => Unit/Fixture}/CallbackWithUnionTypehintClass.php (89%) rename tests/{fixtures => Unit/Fixture}/CallbackWithoutTypehintClass.php (83%) rename tests/{fixtures => Unit/Fixture}/CountableException.php (81%) rename tests/{fixtures => Unit/Fixture}/CountableNonException.php (79%) rename tests/{fixtures => Unit/Fixture}/SimpleFulfilledTestPromise.php (80%) rename tests/{fixtures => Unit/Fixture}/SimpleFulfilledTestThenable.php (84%) rename tests/{fixtures => Unit/Fixture}/SimpleRejectedTestPromise.php (80%) rename tests/{fixtures => Unit/Fixture}/SimpleTestCancellable.php (80%) rename tests/{fixtures => Unit/Fixture}/SimpleTestCancellableThenable.php (88%) rename tests/{ => Unit}/FulfilledPromiseTest.php (89%) rename tests/{ => Unit}/FunctionAllTest.php (94%) rename tests/{ => Unit}/FunctionAnyTest.php (96%) rename tests/{ => Unit}/FunctionCheckTypehintTest.php (75%) rename tests/{ => Unit}/FunctionMapTest.php (96%) rename tests/{ => Unit}/FunctionRaceTest.php (97%) rename tests/{ => Unit}/FunctionReduceTest.php (98%) rename tests/{ => Unit}/FunctionRejectTest.php (91%) rename tests/{ => Unit}/FunctionResolveTest.php (93%) rename tests/{ => Unit}/FunctionSomeTest.php (97%) rename tests/{ => Unit}/LazyPromiseTest.php (91%) rename tests/{ => Unit}/PromiseAdapter/CallbackPromiseAdapter.php (93%) rename tests/{ => Unit}/PromiseAdapter/PromiseAdapterInterface.php (81%) rename tests/{ => Unit}/PromiseTest.php (95%) rename tests/{ => Unit}/PromiseTest/CancelTestTrait.php (98%) rename tests/{ => Unit}/PromiseTest/FullTestTrait.php (85%) rename tests/{ => Unit}/PromiseTest/NotifyTestTrait.php (98%) rename tests/{ => Unit}/PromiseTest/PromiseFulfilledTestTrait.php (98%) rename tests/{ => Unit}/PromiseTest/PromisePendingTestTrait.php (94%) rename tests/{ => Unit}/PromiseTest/PromiseRejectedTestTrait.php (99%) rename tests/{ => Unit}/PromiseTest/PromiseSettledTestTrait.php (95%) rename tests/{ => Unit}/PromiseTest/RejectTestTrait.php (98%) rename tests/{ => Unit}/PromiseTest/ResolveTestTrait.php (98%) rename tests/{ => Unit}/RejectedPromiseTest.php (89%) rename tests/{ => Unit}/TestCase.php (97%) diff --git a/composer.json b/composer.json index 755ac23..024a7f8 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ "php": ">=8.1" }, "require-dev": { + "buggregator/trap": "^1.13", "phpunit/phpunit": "^10.5.10", "ta-tikoma/phpunit-architecture-test": "^0.8.5" }, @@ -48,10 +49,7 @@ }, "autoload-dev": { "psr-4": { - "React\\Promise\\": [ - "tests/", - "tests/fixtures/" - ] + "React\\Promise\\Tests": "tests/" } }, "config": { diff --git a/tests/Arch/ArchTest.php b/tests/Arch/ArchTest.php new file mode 100644 index 0000000..82dbee6 --- /dev/null +++ b/tests/Arch/ArchTest.php @@ -0,0 +1,42 @@ +layer(); + + foreach ($layer as $object) { + foreach ($object->uses as $use) { + foreach ($functions as $function) { + $function === $use and throw new \Exception( + \sprintf( + 'Function `%s()` is used in %s.', + $function, + $object->name, + ), + ); + } + } + } + + $this->assertTrue(true); + } +} diff --git a/tests/CancellationQueueTest.php b/tests/Unit/CancellationQueueTest.php similarity index 92% rename from tests/CancellationQueueTest.php rename to tests/Unit/CancellationQueueTest.php index 0d66248..06024c2 100644 --- a/tests/CancellationQueueTest.php +++ b/tests/Unit/CancellationQueueTest.php @@ -2,7 +2,12 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; + +use React\Promise\CancellationQueue; +use React\Promise\Deferred; +use React\Promise\Tests\Unit\Fixture\SimpleTestCancellable; +use React\Promise\Tests\Unit\Fixture\SimpleTestCancellableThenable; class CancellationQueueTest extends TestCase { diff --git a/tests/DeferredTest.php b/tests/Unit/DeferredTest.php similarity index 94% rename from tests/DeferredTest.php rename to tests/Unit/DeferredTest.php index dd8055b..59e50aa 100644 --- a/tests/DeferredTest.php +++ b/tests/Unit/DeferredTest.php @@ -2,13 +2,15 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; -use React\Promise\PromiseAdapter\CallbackPromiseAdapter; +use React\Promise\Deferred; +use React\Promise\Tests\Unit; +use React\Promise\Tests\Unit\PromiseAdapter\CallbackPromiseAdapter; class DeferredTest extends TestCase { - use PromiseTest\FullTestTrait; + use Unit\PromiseTest\FullTestTrait; public function getPromiseTestAdapter(?callable $canceller = null) { diff --git a/tests/fixtures/ArrayAccessibleException.php b/tests/Unit/Fixture/ArrayAccessibleException.php similarity index 90% rename from tests/fixtures/ArrayAccessibleException.php rename to tests/Unit/Fixture/ArrayAccessibleException.php index d98d401..003d015 100644 --- a/tests/fixtures/ArrayAccessibleException.php +++ b/tests/Unit/Fixture/ArrayAccessibleException.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit\Fixture; class ArrayAccessibleException extends \RuntimeException implements \ArrayAccess { diff --git a/tests/fixtures/CallbackWithDNFTypehintClass.php b/tests/Unit/Fixture/CallbackWithDNFTypehintClass.php similarity index 90% rename from tests/fixtures/CallbackWithDNFTypehintClass.php rename to tests/Unit/Fixture/CallbackWithDNFTypehintClass.php index 391916b..535fcb2 100644 --- a/tests/fixtures/CallbackWithDNFTypehintClass.php +++ b/tests/Unit/Fixture/CallbackWithDNFTypehintClass.php @@ -1,6 +1,6 @@ assertTrue(_checkTypehint('React\Promise\testCallbackWithTypehint', new \InvalidArgumentException())); - $this->assertfalse(_checkTypehint('React\Promise\testCallbackWithTypehint', new \Exception())); + $this->assertTrue(_checkTypehint('\React\Promise\Tests\Unit\testCallbackWithTypehint', new \InvalidArgumentException())); + $this->assertfalse(_checkTypehint('\React\Promise\Tests\Unit\testCallbackWithTypehint', new \Exception())); } #[\PHPUnit\Framework\Attributes\Test] @@ -72,8 +83,8 @@ public function shouldAcceptObjectMethodCallbackWithUnionTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithUnionTypehint(): void { - self::assertTrue(_checkTypehint(\React\Promise\CallbackWithUnionTypehintClass::testCallbackStatic(...), new \InvalidArgumentException())); - self::assertFalse(_checkTypehint(\React\Promise\CallbackWithUnionTypehintClass::testCallbackStatic(...), new \Exception())); + self::assertTrue(_checkTypehint(Fixture\CallbackWithUnionTypehintClass::testCallbackStatic(...), new \InvalidArgumentException())); + self::assertFalse(_checkTypehint(Fixture\CallbackWithUnionTypehintClass::testCallbackStatic(...), new \Exception())); } #[\PHPUnit\Framework\Attributes\RequiresPhp('8.1')] @@ -98,9 +109,9 @@ public function shouldAcceptObjectMethodCallbackWithIntersectionTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithIntersectionTypehint(): void { - self::assertFalse(_checkTypehint(\React\Promise\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new \RuntimeException())); - self::assertFalse(_checkTypehint(\React\Promise\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new CountableNonException())); - self::assertTrue(_checkTypehint(\React\Promise\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new CountableException())); + self::assertFalse(_checkTypehint(Fixture\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new \RuntimeException())); + self::assertFalse(_checkTypehint(Fixture\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new CountableNonException())); + self::assertTrue(_checkTypehint(Fixture\CallbackWithIntersectionTypehintClass::testCallbackStatic(...), new CountableException())); } #[\PHPUnit\Framework\Attributes\RequiresPhp('8.2')] @@ -125,9 +136,9 @@ public function shouldAcceptObjectMethodCallbackWithDNFTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithDNFTypehint(): void { - self::assertFalse(_checkTypehint(\React\Promise\CallbackWithDNFTypehintClass::testCallbackStatic(...), new \RuntimeException())); - self::assertTrue(_checkTypehint(\React\Promise\CallbackWithDNFTypehintClass::testCallbackStatic(...), new CountableException())); - self::assertTrue(_checkTypehint(\React\Promise\CallbackWithDNFTypehintClass::testCallbackStatic(...), new ArrayAccessibleException())); + self::assertFalse(_checkTypehint(Fixture\CallbackWithDNFTypehintClass::testCallbackStatic(...), new \RuntimeException())); + self::assertTrue(_checkTypehint(Fixture\CallbackWithDNFTypehintClass::testCallbackStatic(...), new CountableException())); + self::assertTrue(_checkTypehint(Fixture\CallbackWithDNFTypehintClass::testCallbackStatic(...), new ArrayAccessibleException())); } #[\PHPUnit\Framework\Attributes\Test] @@ -139,7 +150,7 @@ public function shouldAcceptClosureCallbackWithoutTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptFunctionStringCallbackWithoutTypehint(): void { - $this->assertTrue(_checkTypehint('React\Promise\testCallbackWithoutTypehint', new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint('\React\Promise\Tests\Unit\testCallbackWithoutTypehint', new \InvalidArgumentException())); } #[\PHPUnit\Framework\Attributes\Test] @@ -157,7 +168,7 @@ public function shouldAcceptObjectMethodCallbackWithoutTypehint(): void #[\PHPUnit\Framework\Attributes\Test] public function shouldAcceptStaticClassCallbackWithoutTypehint(): void { - $this->assertTrue(_checkTypehint(\React\Promise\CallbackWithoutTypehintClass::testCallbackStatic(...), new \InvalidArgumentException())); + $this->assertTrue(_checkTypehint(Fixture\CallbackWithoutTypehintClass::testCallbackStatic(...), new \InvalidArgumentException())); } } diff --git a/tests/FunctionMapTest.php b/tests/Unit/FunctionMapTest.php similarity index 96% rename from tests/FunctionMapTest.php rename to tests/Unit/FunctionMapTest.php index 187eaef..6d87f49 100644 --- a/tests/FunctionMapTest.php +++ b/tests/Unit/FunctionMapTest.php @@ -2,7 +2,13 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; + +use React\Promise\Deferred; + +use function React\Promise\map; +use function React\Promise\reject; +use function React\Promise\resolve; class FunctionMapTest extends TestCase { diff --git a/tests/FunctionRaceTest.php b/tests/Unit/FunctionRaceTest.php similarity index 97% rename from tests/FunctionRaceTest.php rename to tests/Unit/FunctionRaceTest.php index 42984a2..50ba96e 100644 --- a/tests/FunctionRaceTest.php +++ b/tests/Unit/FunctionRaceTest.php @@ -2,7 +2,13 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; + +use React\Promise\Deferred; + +use function React\Promise\race; +use function React\Promise\reject; +use function React\Promise\resolve; class FunctionRaceTest extends TestCase { diff --git a/tests/FunctionReduceTest.php b/tests/Unit/FunctionReduceTest.php similarity index 98% rename from tests/FunctionReduceTest.php rename to tests/Unit/FunctionReduceTest.php index 9c3f966..b770347 100644 --- a/tests/FunctionReduceTest.php +++ b/tests/Unit/FunctionReduceTest.php @@ -2,7 +2,13 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; + +use React\Promise\Deferred; + +use function React\Promise\reduce; +use function React\Promise\reject; +use function React\Promise\resolve; class FunctionReduceTest extends TestCase { diff --git a/tests/FunctionRejectTest.php b/tests/Unit/FunctionRejectTest.php similarity index 91% rename from tests/FunctionRejectTest.php rename to tests/Unit/FunctionRejectTest.php index 4f5d427..7a305fd 100644 --- a/tests/FunctionRejectTest.php +++ b/tests/Unit/FunctionRejectTest.php @@ -2,7 +2,12 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; + +use React\Promise\FulfilledPromise; +use React\Promise\RejectedPromise; + +use function React\Promise\reject; class FunctionRejectTest extends TestCase { diff --git a/tests/FunctionResolveTest.php b/tests/Unit/FunctionResolveTest.php similarity index 93% rename from tests/FunctionResolveTest.php rename to tests/Unit/FunctionResolveTest.php index e5ceed5..40bac63 100644 --- a/tests/FunctionResolveTest.php +++ b/tests/Unit/FunctionResolveTest.php @@ -2,7 +2,15 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; + +use React\Promise\Deferred; +use React\Promise\FulfilledPromise; +use React\Promise\RejectedPromise; +use React\Promise\Tests\Unit\Fixture\SimpleFulfilledTestThenable; +use React\Promise\Tests\Unit\Fixture\SimpleTestCancellableThenable; + +use function React\Promise\resolve; class FunctionResolveTest extends TestCase { diff --git a/tests/FunctionSomeTest.php b/tests/Unit/FunctionSomeTest.php similarity index 97% rename from tests/FunctionSomeTest.php rename to tests/Unit/FunctionSomeTest.php index 4a7b0e2..fb0bc47 100644 --- a/tests/FunctionSomeTest.php +++ b/tests/Unit/FunctionSomeTest.php @@ -2,10 +2,15 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; +use React\Promise\Deferred; use React\Promise\Exception\LengthException; +use function React\Promise\reject; +use function React\Promise\resolve; +use function React\Promise\some; + class FunctionSomeTest extends TestCase { #[\PHPUnit\Framework\Attributes\Test] diff --git a/tests/LazyPromiseTest.php b/tests/Unit/LazyPromiseTest.php similarity index 91% rename from tests/LazyPromiseTest.php rename to tests/Unit/LazyPromiseTest.php index c721fcc..29a10d1 100644 --- a/tests/LazyPromiseTest.php +++ b/tests/Unit/LazyPromiseTest.php @@ -2,13 +2,17 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; -use React\Promise\PromiseAdapter\CallbackPromiseAdapter; +use React\Promise\Deferred; +use React\Promise\FulfilledPromise; +use React\Promise\LazyPromise; +use React\Promise\Tests\Unit; +use React\Promise\Tests\Unit\PromiseAdapter\CallbackPromiseAdapter; class LazyPromiseTest extends TestCase { - use PromiseTest\FullTestTrait; + use Unit\PromiseTest\FullTestTrait; public function getPromiseTestAdapter(?callable $canceller = null) { diff --git a/tests/PromiseAdapter/CallbackPromiseAdapter.php b/tests/Unit/PromiseAdapter/CallbackPromiseAdapter.php similarity index 93% rename from tests/PromiseAdapter/CallbackPromiseAdapter.php rename to tests/Unit/PromiseAdapter/CallbackPromiseAdapter.php index 4d539ea..f7c8792 100644 --- a/tests/PromiseAdapter/CallbackPromiseAdapter.php +++ b/tests/Unit/PromiseAdapter/CallbackPromiseAdapter.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace React\Promise\PromiseAdapter; +namespace React\Promise\Tests\Unit\PromiseAdapter; class CallbackPromiseAdapter implements PromiseAdapterInterface { diff --git a/tests/PromiseAdapter/PromiseAdapterInterface.php b/tests/Unit/PromiseAdapter/PromiseAdapterInterface.php similarity index 81% rename from tests/PromiseAdapter/PromiseAdapterInterface.php rename to tests/Unit/PromiseAdapter/PromiseAdapterInterface.php index 34b28a6..c0cdf06 100644 --- a/tests/PromiseAdapter/PromiseAdapterInterface.php +++ b/tests/Unit/PromiseAdapter/PromiseAdapterInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace React\Promise\PromiseAdapter; +namespace React\Promise\Tests\Unit\PromiseAdapter; interface PromiseAdapterInterface { diff --git a/tests/PromiseTest.php b/tests/Unit/PromiseTest.php similarity index 95% rename from tests/PromiseTest.php rename to tests/Unit/PromiseTest.php index e160dd0..f1c6b91 100644 --- a/tests/PromiseTest.php +++ b/tests/Unit/PromiseTest.php @@ -2,13 +2,17 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; -use React\Promise\PromiseAdapter\CallbackPromiseAdapter; +use React\Promise\Promise; +use React\Promise\Tests\Unit; +use React\Promise\Tests\Unit\Fixture\SimpleFulfilledTestPromise; +use React\Promise\Tests\Unit\Fixture\SimpleRejectedTestPromise; +use React\Promise\Tests\Unit\PromiseAdapter\CallbackPromiseAdapter; class PromiseTest extends TestCase { - use PromiseTest\FullTestTrait; + use Unit\PromiseTest\FullTestTrait; public function getPromiseTestAdapter(?callable $canceller = null) { diff --git a/tests/PromiseTest/CancelTestTrait.php b/tests/Unit/PromiseTest/CancelTestTrait.php similarity index 98% rename from tests/PromiseTest/CancelTestTrait.php rename to tests/Unit/PromiseTest/CancelTestTrait.php index e7934c3..f728317 100644 --- a/tests/PromiseTest/CancelTestTrait.php +++ b/tests/Unit/PromiseTest/CancelTestTrait.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; use React\Promise; trait CancelTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/PromiseTest/FullTestTrait.php b/tests/Unit/PromiseTest/FullTestTrait.php similarity index 85% rename from tests/PromiseTest/FullTestTrait.php rename to tests/Unit/PromiseTest/FullTestTrait.php index 8143541..675248c 100644 --- a/tests/PromiseTest/FullTestTrait.php +++ b/tests/Unit/PromiseTest/FullTestTrait.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; trait FullTestTrait { diff --git a/tests/PromiseTest/NotifyTestTrait.php b/tests/Unit/PromiseTest/NotifyTestTrait.php similarity index 98% rename from tests/PromiseTest/NotifyTestTrait.php rename to tests/Unit/PromiseTest/NotifyTestTrait.php index 566da9f..6af2a4e 100644 --- a/tests/PromiseTest/NotifyTestTrait.php +++ b/tests/Unit/PromiseTest/NotifyTestTrait.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; trait NotifyTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/PromiseTest/PromiseFulfilledTestTrait.php b/tests/Unit/PromiseTest/PromiseFulfilledTestTrait.php similarity index 98% rename from tests/PromiseTest/PromiseFulfilledTestTrait.php rename to tests/Unit/PromiseTest/PromiseFulfilledTestTrait.php index 7af050a..0c50f49 100644 --- a/tests/PromiseTest/PromiseFulfilledTestTrait.php +++ b/tests/Unit/PromiseTest/PromiseFulfilledTestTrait.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; trait PromiseFulfilledTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/PromiseTest/PromisePendingTestTrait.php b/tests/Unit/PromiseTest/PromisePendingTestTrait.php similarity index 94% rename from tests/PromiseTest/PromisePendingTestTrait.php rename to tests/Unit/PromiseTest/PromisePendingTestTrait.php index 43168fc..6260e62 100644 --- a/tests/PromiseTest/PromisePendingTestTrait.php +++ b/tests/Unit/PromiseTest/PromisePendingTestTrait.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; trait PromisePendingTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/PromiseTest/PromiseRejectedTestTrait.php b/tests/Unit/PromiseTest/PromiseRejectedTestTrait.php similarity index 99% rename from tests/PromiseTest/PromiseRejectedTestTrait.php rename to tests/Unit/PromiseTest/PromiseRejectedTestTrait.php index bfbcf5c..e9b936b 100644 --- a/tests/PromiseTest/PromiseRejectedTestTrait.php +++ b/tests/Unit/PromiseTest/PromiseRejectedTestTrait.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; use React\Promise\Deferred; use React\Promise\UnhandledRejectionException; @@ -10,7 +10,7 @@ trait PromiseRejectedTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/PromiseTest/PromiseSettledTestTrait.php b/tests/Unit/PromiseTest/PromiseSettledTestTrait.php similarity index 95% rename from tests/PromiseTest/PromiseSettledTestTrait.php rename to tests/Unit/PromiseTest/PromiseSettledTestTrait.php index 25176a3..7f544d9 100644 --- a/tests/PromiseTest/PromiseSettledTestTrait.php +++ b/tests/Unit/PromiseTest/PromiseSettledTestTrait.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; trait PromiseSettledTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/PromiseTest/RejectTestTrait.php b/tests/Unit/PromiseTest/RejectTestTrait.php similarity index 98% rename from tests/PromiseTest/RejectTestTrait.php rename to tests/Unit/PromiseTest/RejectTestTrait.php index 8da5fee..64ba73f 100644 --- a/tests/PromiseTest/RejectTestTrait.php +++ b/tests/Unit/PromiseTest/RejectTestTrait.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; use React\Promise; use React\Promise\Deferred; @@ -10,7 +10,7 @@ trait RejectTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/PromiseTest/ResolveTestTrait.php b/tests/Unit/PromiseTest/ResolveTestTrait.php similarity index 98% rename from tests/PromiseTest/ResolveTestTrait.php rename to tests/Unit/PromiseTest/ResolveTestTrait.php index babb843..d30cdc3 100644 --- a/tests/PromiseTest/ResolveTestTrait.php +++ b/tests/Unit/PromiseTest/ResolveTestTrait.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace React\Promise\PromiseTest; +namespace React\Promise\Tests\Unit\PromiseTest; use React\Promise; trait ResolveTestTrait { /** - * @return \React\Promise\PromiseAdapter\PromiseAdapterInterface + * @return \React\Promise\Tests\Unit\PromiseAdapter\PromiseAdapterInterface */ abstract public function getPromiseTestAdapter(?callable $canceller = null); diff --git a/tests/RejectedPromiseTest.php b/tests/Unit/RejectedPromiseTest.php similarity index 89% rename from tests/RejectedPromiseTest.php rename to tests/Unit/RejectedPromiseTest.php index f426c88..ace58b5 100644 --- a/tests/RejectedPromiseTest.php +++ b/tests/Unit/RejectedPromiseTest.php @@ -2,14 +2,16 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; -use React\Promise\PromiseAdapter\CallbackPromiseAdapter; +use React\Promise\RejectedPromise; +use React\Promise\Tests\Unit; +use React\Promise\Tests\Unit\PromiseAdapter\CallbackPromiseAdapter; class RejectedPromiseTest extends TestCase { - use PromiseTest\PromiseSettledTestTrait; - use PromiseTest\PromiseRejectedTestTrait; + use Unit\PromiseTest\PromiseSettledTestTrait; + use Unit\PromiseTest\PromiseRejectedTestTrait; public function getPromiseTestAdapter(?callable $canceller = null) { diff --git a/tests/TestCase.php b/tests/Unit/TestCase.php similarity index 97% rename from tests/TestCase.php rename to tests/Unit/TestCase.php index a857900..bbb5a4a 100644 --- a/tests/TestCase.php +++ b/tests/Unit/TestCase.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace React\Promise; +namespace React\Promise\Tests\Unit; class TestCase extends \PHPUnit\Framework\TestCase { From 5fa760eda8d76df5d1c0cde6a578dddf50d29d46 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 19:50:29 +0400 Subject: [PATCH 07/15] refactor: use strict types and static closures --- README.md | 1 + src/CancellablePromiseInterface.php | 2 ++ src/CancellationQueue.php | 4 ++- src/Deferred.php | 2 ++ src/Exception/LengthException.php | 2 ++ src/ExtendedPromiseInterface.php | 2 ++ src/FulfilledPromise.php | 4 ++- src/LazyPromise.php | 2 ++ src/Promise.php | 10 +++++--- src/PromiseInterface.php | 2 ++ src/PromisorInterface.php | 2 ++ src/RejectedPromise.php | 4 ++- src/UnhandledRejectionException.php | 2 ++ src/functions.php | 40 +++++++++++++++-------------- src/functions_include.php | 2 ++ 15 files changed, 55 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 5752ca6..7fd5e31 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ A lightweight implementation of [CommonJS Promises/A][CommonJS Promises/A] for P > [!NOTE] > This is a fork of [reactphp/promise][reactphp/promise] with the following improvements: > - PHP 8.1+ compatibility +> - `declare(strict_types=1);` in all files > - `@yield` annotations in promise interfaces > - Enhanced type annotations > - Replaces `react/promise` v2 diff --git a/src/CancellablePromiseInterface.php b/src/CancellablePromiseInterface.php index 6b3a8c6..bddd47f 100644 --- a/src/CancellablePromiseInterface.php +++ b/src/CancellablePromiseInterface.php @@ -1,5 +1,7 @@ queue); isset($this->queue[$i]); $i++) { + for ($i = \key($this->queue); isset($this->queue[$i]); $i++) { $cancellable = $this->queue[$i]; $exception = null; diff --git a/src/Deferred.php b/src/Deferred.php index 93786d5..9a23323 100644 --- a/src/Deferred.php +++ b/src/Deferred.php @@ -1,5 +1,7 @@ then(fn($value) => resolve($onFulfilledOrRejected())->then(fn() => $value)); + return $this->then(static fn($value) => resolve($onFulfilledOrRejected())->then(static fn() => $value)); } public function progress(callable $onProgress) diff --git a/src/LazyPromise.php b/src/LazyPromise.php index 59f6f5c..bacae41 100644 --- a/src/LazyPromise.php +++ b/src/LazyPromise.php @@ -1,5 +1,7 @@ then(static fn($value) => resolve($onFulfilledOrRejected())->then(fn() => $value), static fn($reason) => resolve($onFulfilledOrRejected())->then(fn() => new RejectedPromise($reason))); + return $this->then(static fn($value) => resolve($onFulfilledOrRejected())->then(static fn() => $value), static fn($reason) => resolve($onFulfilledOrRejected())->then(static fn() => new RejectedPromise($reason))); } public function progress(callable $onProgress) @@ -127,7 +129,7 @@ private function resolver(?callable $onFulfilled = null, ?callable $onRejected = }; } - private function reject($reason = null) + private function reject($reason = null): void { if ($this->result !== null) { return; @@ -136,7 +138,7 @@ private function reject($reason = null) $this->settle(reject($reason)); } - private function settle(ExtendedPromiseInterface $promise) + private function settle(ExtendedPromiseInterface $promise): void { $promise = $this->unwrap($promise); @@ -177,7 +179,7 @@ private function extract($promise) return $promise; } - private function call(callable $cb) + private function call(callable $cb): void { // Explicitly overwrite argument with null value. This ensure that this // argument does not show up in the stack trace in PHP 7+ only. diff --git a/src/PromiseInterface.php b/src/PromiseInterface.php index dfaf436..7f4ba6f 100644 --- a/src/PromiseInterface.php +++ b/src/PromiseInterface.php @@ -1,5 +1,7 @@ then(null, fn($reason) => resolve($onFulfilledOrRejected())->then(fn() => new RejectedPromise($reason))); + return $this->then(null, static fn($reason) => resolve($onFulfilledOrRejected())->then(static fn() => new RejectedPromise($reason))); } public function progress(callable $onProgress) diff --git a/src/UnhandledRejectionException.php b/src/UnhandledRejectionException.php index 55c3f96..cdd0a2e 100644 --- a/src/UnhandledRejectionException.php +++ b/src/UnhandledRejectionException.php @@ -1,5 +1,7 @@ then($resolve, $reject, $notify); }, $canceller); } @@ -58,7 +60,7 @@ function resolve($promiseOrValue = null) function reject($promiseOrValue = null) { if ($promiseOrValue instanceof PromiseInterface) { - return resolve($promiseOrValue)->then(fn($value) => new RejectedPromise($value)); + return resolve($promiseOrValue)->then(static fn($value) => new RejectedPromise($value)); } return new RejectedPromise($promiseOrValue); @@ -75,7 +77,7 @@ function reject($promiseOrValue = null) */ function all($promisesOrValues) { - return map($promisesOrValues, fn($val) => $val); + return map($promisesOrValues, static fn($val) => $val); } /** @@ -93,10 +95,10 @@ function race($promisesOrValues) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue): void { + return new Promise(static function ($resolve, $reject, $notify) use ($promisesOrValues, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($cancellationQueue, $resolve, $reject, $notify): void { - if (!is_array($array) || !$array) { + ->done(static function ($array) use ($cancellationQueue, $resolve, $reject, $notify): void { + if (!\is_array($array) || !$array) { $resolve(); return; } @@ -128,7 +130,7 @@ function race($promisesOrValues) function any($promisesOrValues) { return some($promisesOrValues, 1) - ->then(fn($val) => \array_shift($val)); + ->then(static fn($val) => \array_shift($val)); } /** @@ -154,9 +156,9 @@ function some($promisesOrValues, $howMany) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue): void { + return new Promise(static function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify): void { + ->done(static function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify): void { if (!\is_array($array) || $howMany < 1) { $resolve([]); return; @@ -182,7 +184,7 @@ function some($promisesOrValues, $howMany) $reasons = []; foreach ($array as $i => $promiseOrValue) { - $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve): void { + $fulfiller = static function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve): void { if ($toResolve < 1 || $toReject < 1) { return; } @@ -194,7 +196,7 @@ function some($promisesOrValues, $howMany) } }; - $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject): void { + $rejecter = static function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject): void { if ($toResolve < 1 || $toReject < 1) { return; } @@ -230,9 +232,9 @@ function map($promisesOrValues, callable $mapFunc) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue): void { + return new Promise(static function ($resolve, $reject, $notify) use ($promisesOrValues, $mapFunc, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify): void { + ->done(static function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify): void { if (!\is_array($array) || !$array) { $resolve([]); return; @@ -248,7 +250,7 @@ function map($promisesOrValues, callable $mapFunc) resolve($promiseOrValue) ->then($mapFunc) ->done( - function ($mapped) use ($i, &$values, &$toResolve, $resolve): void { + static function ($mapped) use ($i, &$values, &$toResolve, $resolve): void { $values[$i] = $mapped; if (--$toResolve === 0) { @@ -278,9 +280,9 @@ function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); - return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue): void { + return new Promise(static function ($resolve, $reject, $notify) use ($promisesOrValues, $reduceFunc, $initialValue, $cancellationQueue): void { resolve($promisesOrValues) - ->done(function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify): void { + ->done(static function ($array) use ($reduceFunc, $initialValue, $cancellationQueue, $resolve, $reject, $notify): void { if (!\is_array($array)) { $array = []; } @@ -290,13 +292,13 @@ function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) // Wrap the supplied $reduceFunc with one that handles promises and then // delegates to the supplied. - $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $cancellationQueue, $total, &$i) { + $wrappedReduceFunc = static function ($current, $val) use ($reduceFunc, $cancellationQueue, $total, &$i) { $cancellationQueue->enqueue($val); return $current - ->then(function ($c) use ($reduceFunc, $total, &$i, $val) { + ->then(static function ($c) use ($reduceFunc, $total, &$i, $val) { return resolve($val) - ->then(function ($value) use ($reduceFunc, $total, &$i, $c) { + ->then(static function ($value) use ($reduceFunc, $total, &$i, $c) { return $reduceFunc($c, $value, $i++, $total); }); }); diff --git a/src/functions_include.php b/src/functions_include.php index 750fe6a..54b0141 100644 --- a/src/functions_include.php +++ b/src/functions_include.php @@ -1,5 +1,7 @@ Date: Tue, 26 Aug 2025 20:03:42 +0400 Subject: [PATCH 08/15] chore: install Psalm --- composer.json | 17 +- psalm-baseline.xml | 447 ++++++++++++++++++++++++++++++++++++++++ psalm.xml | 32 +++ tests/Arch/ArchTest.php | 4 +- 4 files changed, 495 insertions(+), 5 deletions(-) create mode 100644 psalm-baseline.xml create mode 100644 psalm.xml diff --git a/composer.json b/composer.json index 024a7f8..3fd9671 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,9 @@ "require-dev": { "buggregator/trap": "^1.13", "phpunit/phpunit": "^10.5.10", - "ta-tikoma/phpunit-architecture-test": "^0.8.5" + "spiral/code-style": "^2.2", + "ta-tikoma/phpunit-architecture-test": "^0.8.5", + "vimeo/psalm": "^6.13" }, "replace": { "react/promise": "^2.0" @@ -49,7 +51,7 @@ }, "autoload-dev": { "psr-4": { - "React\\Promise\\Tests": "tests/" + "React\\Promise\\Tests\\": "tests/" } }, "config": { @@ -57,5 +59,16 @@ "abandoned": "report" }, "sort-packages": true + }, + "scripts": { + "cs:fix": "php-cs-fixer fix -v", + "psalm": "psalm", + "psalm:baseline": "psalm --set-baseline=psalm-baseline.xml", + "psalm:ci": "psalm --output-format=github --shepherd --show-info=false --stats --threads=4", + "test": "phpunit --color=always --testdox", + "test:cc": [ + "@putenv XDEBUG_MODE=coverage", + "phpunit --coverage-clover=runtime/phpunit/logs/clover.xml --color=always" + ] } } diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 0000000..f4ad91c --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + + + + + queue]]> + queue]]> + + + + + + queue[$i]]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + notifyCallback, $update)]]> + rejectCallback, $reason)]]> + resolveCallback, $value)]]> + + + promise]]> + promise]]> + + + + + + + + + + + + + + + + then(static fn($value) => resolve($onFulfilledOrRejected())->then(static fn() => $value))]]> + + + + + + $value]]> + + + + + + + + + + + + + + + + + + + + + + + promise()->cancel()]]> + promise()->done($onFulfilled, $onRejected, $onProgress)]]> + + + + + + + + + + + + + + + + + promise()->always($onFulfilledOrRejected)]]> + promise()->otherwise($onRejected)]]> + promise()->progress($onProgress)]]> + promise()->then($onFulfilled, $onRejected, $onProgress)]]> + + + + + + + + + + + + + + + + + result->done($onFulfilled, $onRejected, $onProgress)]]> + + + then(null, null, $onProgress)]]> + then(null, static function ($reason) use ($onRejected) { + if (!_checkTypehint($onRejected, $reason)) { + return new RejectedPromise($reason); + } + + return $onRejected($reason); + })]]> + then(static fn($value) => resolve($onFulfilledOrRejected())->then(static fn() => $value), static fn($reason) => resolve($onFulfilledOrRejected())->then(static fn() => new RejectedPromise($reason)))]]> + + + + + + + + + + + + + + + $value]]> + + + + + + + + + + + cancelRequests]]> + requiredCancelRequests]]> + requiredCancelRequests]]> + + result]]> + + + handlers]]> + progressHandlers]]> + + + + + + + + + resolver($onFulfilled, $onRejected, $onProgress)]]> + resolver($onFulfilled, $onRejected, $onProgress)]]> + + + handlers[]]]> + handlers[]]]> + progressHandlers[]]]> + progressHandlers[]]]> + + + + + + + + + + + + + + + + + + + + + + + + cancelRequests]]> + requiredCancelRequests]]> + + + result->then($onFulfilled, $onRejected, $onProgress)]]> + + + + + + + + + + + cancelRequests]]> + + + + + + cancelRequests]]> + requiredCancelRequests]]> + + + + + + + + + + + + + + + + + + + + resolver($onFulfilled, $onRejected, $onProgress), + static function () use (&$parent): void { + if (++$parent->cancelRequests >= $parent->requiredCancelRequests) { + $parent->cancel(); + } + + $parent = null; + }, + )]]> + resolver($onFulfilled, $onRejected, $onProgress))]]> + + + progressHandlers]]> + + + + + + + + then(null, $onRejected)]]> + then(null, static fn($reason) => resolve($onFulfilledOrRejected())->then(static fn() => new RejectedPromise($reason)))]]> + + + + + + + + + + reason]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + getName()]]> + getName()]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $val]]> + \array_shift($val)]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + getName()))->isInstance($object)]]> + + + getName()))->isInstance($object)]]> + + + + + + + + + + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..bf7d2a7 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/Arch/ArchTest.php b/tests/Arch/ArchTest.php index 82dbee6..050be9b 100644 --- a/tests/Arch/ArchTest.php +++ b/tests/Arch/ArchTest.php @@ -12,15 +12,13 @@ final class ArchTest extends TestCase use ArchitectureAsserts; protected array $excludedPaths = [ - 'resources', 'tests', 'vendor', - 'src/Test', ]; public function testForgottenDebugFunctions(): void { - $functions = ['dd', 'exit', 'die', 'var_dump', 'echo', 'print', 'dump', 'tr', 'td']; + $functions = ['dd', 'exit', 'die', 'var_dump', 'echo', 'print', 'dump', 'tr', 'td', 'error_log', 'trap']; $layer = $this->layer(); foreach ($layer as $object) { From ac798abac22c92aa8c243abb4935e16e73e3ba56 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 20:04:17 +0400 Subject: [PATCH 09/15] chore: update metafiles, configure PHPUnit --- .gitattributes | 1 + .gitignore | 1 + .php-cs-fixer.dist.php | 13 +++++++++++++ composer.json | 3 +++ phpunit.xml.dist | 21 ++++++++++++++++----- rector.php | 16 ++++++++++++++++ 6 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 .php-cs-fixer.dist.php create mode 100644 rector.php diff --git a/.gitattributes b/.gitattributes index 90e0fc5..a0650eb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,3 +6,4 @@ /psalm.* export-ignore /psalm-baseline.xml export-ignore /infection.* export-ignore +/rector.php export-ignore diff --git a/.gitignore b/.gitignore index 1ae5173..99dd26d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /.* !/.github/ +!/.php-cs-fixer.dist.php /runtime/ /vendor/ /.env diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..78b194f --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,13 @@ +include(__DIR__ . '/src') + ->include(__DIR__ . '/tests') + ->include(__DIR__ . '/rector.php') + ->include(__FILE__) + ->allowRisky(false) + ->build(); diff --git a/composer.json b/composer.json index 3fd9671..61a9939 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "require-dev": { "buggregator/trap": "^1.13", "phpunit/phpunit": "^10.5.10", + "rector/rector": "^2.1", "spiral/code-style": "^2.2", "ta-tikoma/phpunit-architecture-test": "^0.8.5", "vimeo/psalm": "^6.13" @@ -65,6 +66,8 @@ "psalm": "psalm", "psalm:baseline": "psalm --set-baseline=psalm-baseline.xml", "psalm:ci": "psalm --output-format=github --shepherd --show-info=false --stats --threads=4", + "refactor": "rector process --config=rector.php", + "refactor:ci": "rector process --config=rector.php --dry-run --ansi", "test": "phpunit --color=always --testdox", "test:cc": [ "@putenv XDEBUG_MODE=coverage", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b96d082..90262eb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -2,24 +2,35 @@ +> ./tests/ + + + + + + + + + + - ./src/ + src - ./src/functions_include.php + tests - + diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..c2b1065 --- /dev/null +++ b/rector.php @@ -0,0 +1,16 @@ +withPaths([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + // uncomment to reach your current PHP version + // ->withPhpSets(php81: true) + ->withTypeCoverageLevel(0) + ->withDeadCodeLevel(0) + ->withCodeQualityLevel(0); From 4bb57971ef38136bc43a7584f65a0aeef0cfe613 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 20:06:24 +0400 Subject: [PATCH 10/15] ci: add GitHub Actions for code style fixing and static analysis --- .github/workflows/cs-fix.yml | 12 +++++++++ .github/workflows/static-analysis.yml | 35 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 .github/workflows/cs-fix.yml create mode 100644 .github/workflows/static-analysis.yml diff --git a/.github/workflows/cs-fix.yml b/.github/workflows/cs-fix.yml new file mode 100644 index 0000000..0395b27 --- /dev/null +++ b/.github/workflows/cs-fix.yml @@ -0,0 +1,12 @@ +on: + push: + branches: + - '*' + +name: Fix Code Style + +jobs: + cs-fix: + permissions: + contents: write + uses: spiral/gh-actions/.github/workflows/cs-fix.yml@master diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..d88e569 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,35 @@ +name: Static Analysis + +on: [push, pull_request] + +concurrency: + cancel-in-progress: ${{ !contains(github.ref, 'release/')}} + group: tests-${{ github.workflow }}-${{ github.ref }} + +jobs: + psalm: + name: Psalm Validation (PHP ${{ matrix.php }}, OS ${{ matrix.os }}) + runs-on: ${{ matrix.os }} + continue-on-error: true + strategy: + fail-fast: false + matrix: + php: [8.3] + os: [ubuntu-latest] + steps: + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom + + - name: Check Out Code + uses: actions/checkout@v4 + + - name: Install dependencies with composer + uses: ramsey/composer-install@v3 + with: + dependency-versions: ${{ matrix.dependencies }} + + - name: 🔍 Run Tests + run: vendor/bin/psalm From b3cd3f2f55e54cf12d1a662efe9a45cdcc43d3da Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 26 Aug 2025 16:06:51 +0000 Subject: [PATCH 11/15] style(php-cs-fixer): fix coding standards --- .../Unit/Fixture/CallbackWithDNFTypehintClass.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/Unit/Fixture/CallbackWithDNFTypehintClass.php b/tests/Unit/Fixture/CallbackWithDNFTypehintClass.php index 535fcb2..56817e4 100644 --- a/tests/Unit/Fixture/CallbackWithDNFTypehintClass.php +++ b/tests/Unit/Fixture/CallbackWithDNFTypehintClass.php @@ -2,20 +2,11 @@ namespace React\Promise\Tests\Unit\Fixture; -use Countable; -use RuntimeException; - class CallbackWithDNFTypehintClass { - public function __invoke((RuntimeException&Countable)|(RuntimeException&\ArrayAccess) $e) - { - } + public static function testCallbackStatic((\RuntimeException&\Countable)|(\RuntimeException&\ArrayAccess) $e) {} -public function testCallback((RuntimeException&Countable)|(RuntimeException&\ArrayAccess) $e) - { - } + public function testCallback((\RuntimeException&\Countable)|(\RuntimeException&\ArrayAccess) $e) {} - public static function testCallbackStatic((RuntimeException&Countable)|(RuntimeException&\ArrayAccess) $e) - { - } + public function __invoke((\RuntimeException&\Countable)|(\RuntimeException&\ArrayAccess) $e) {} } From 68376b3379fa254491d274eacef1fdbb3c85a764 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 20:08:04 +0400 Subject: [PATCH 12/15] ci: update PHP version matrix in GitHub Actions --- .github/workflows/ci.yml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4509b0a..c0bd1fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,18 +11,10 @@ jobs: strategy: matrix: php: + - 8.4 - 8.3 - 8.2 - 8.1 - - 8.0 - - 7.4 - - 7.3 - - 7.2 - - 7.1 - - 7.0 - - 5.6 - - 5.5 - - 5.4 steps: - uses: actions/checkout@v4 - uses: shivammathur/setup-php@v2 @@ -31,10 +23,7 @@ jobs: coverage: xdebug ini-file: development - run: composer install - - run: vendor/bin/phpunit --coverage-text - if: ${{ matrix.php >= 7.3 }} - - run: vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy - if: ${{ matrix.php < 7.3 }} + - run: composer test:cc PHPUnit-hhvm: name: PHPUnit (HHVM) From 15273b5bcd45ac5e390934a2cb7bc36b24e389cc Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 20:10:33 +0400 Subject: [PATCH 13/15] ci: update actions/checkout to v5 and remove HHVM configuration --- .github/workflows/ci.yml | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0bd1fb..703b75e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - 8.2 - 8.1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} @@ -24,19 +24,3 @@ jobs: ini-file: development - run: composer install - run: composer test:cc - - PHPUnit-hhvm: - name: PHPUnit (HHVM) - runs-on: ubuntu-22.04 - continue-on-error: true - steps: - - uses: actions/checkout@v4 - - run: cp "$(which composer)" composer.phar && ./composer.phar self-update --2.2 # downgrade Composer for HHVM - - name: Run hhvm composer.phar install - uses: docker://hhvm/hhvm:3.30-lts-latest - with: - args: hhvm composer.phar install - - name: Run hhvm vendor/bin/phpunit - uses: docker://hhvm/hhvm:3.30-lts-latest - with: - args: hhvm vendor/bin/phpunit From 51cafc614a9faa64a41694e23e8642d79012aa28 Mon Sep 17 00:00:00 2001 From: roxblnfk Date: Tue, 26 Aug 2025 23:15:56 +0400 Subject: [PATCH 14/15] refactor: Cover PromiseInterface with types --- psalm-baseline.xml | 128 ++++++++++++++++------------ src/CancellablePromiseInterface.php | 4 + src/Deferred.php | 13 ++- src/ExtendedPromiseInterface.php | 16 +++- src/FulfilledPromise.php | 10 ++- src/LazyPromise.php | 4 + src/Promise.php | 26 ++++-- src/PromiseInterface.php | 14 ++- src/RejectedPromise.php | 4 + src/functions.php | 34 ++++---- 10 files changed, 169 insertions(+), 84 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index f4ad91c..e37fee0 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -56,7 +56,6 @@ - @@ -71,10 +70,6 @@ rejectCallback, $reason)]]> resolveCallback, $value)]]> - - promise]]> - promise]]> - @@ -97,12 +92,9 @@ $value]]> - - - - - - + + value]]> + @@ -157,6 +149,11 @@ + + + + + result->done($onFulfilled, $onRejected, $onProgress)]]> @@ -191,64 +188,33 @@ - - - - - cancelRequests]]> - requiredCancelRequests]]> - requiredCancelRequests]]> - - result]]> - - - handlers]]> - progressHandlers]]> - - + + resolver($onFulfilled, $onRejected, $onProgress)]]> resolver($onFulfilled, $onRejected, $onProgress)]]> - - handlers[]]]> - handlers[]]]> - progressHandlers[]]]> - progressHandlers[]]]> - - - - - + result]]> - - - - - - - - cancelRequests]]> - requiredCancelRequests]]> - - - result->then($onFulfilled, $onRejected, $onProgress)]]> - + + + progressHandlers]]> + @@ -269,11 +235,12 @@ - - - + + handlers]]> + handlers]]> + @@ -283,6 +250,7 @@ + reason]]> + + reason]]> + reason]]> + @@ -359,6 +331,12 @@ + + + + + ]]> + @@ -386,20 +364,19 @@ - - - $val]]> \array_shift($val)]]> - + + + @@ -421,7 +398,46 @@ + + + + ]]> + ]]> + done(static function ($array) use ($mapFunc, $cancellationQueue, $resolve, $reject, $notify): void { + if (!\is_array($array) || !$array) { + $resolve([]); + return; + } + + $toResolve = \count($array); + $values = []; + + foreach ($array as $i => $promiseOrValue) { + $cancellationQueue->enqueue($promiseOrValue); + $values[$i] = null; + + resolve($promiseOrValue) + ->then($mapFunc) + ->done( + static function ($mapped) use ($i, &$values, &$toResolve, $resolve): void { + $values[$i] = $mapped; + + if (--$toResolve === 0) { + $resolve($values); + } + }, + $reject, + $notify, + ); + } + }, $reject, $notify); + }, $cancellationQueue)]]> + + then(static fn($value) => new RejectedPromise($value))]]> + diff --git a/src/CancellablePromiseInterface.php b/src/CancellablePromiseInterface.php index bddd47f..43ee09e 100644 --- a/src/CancellablePromiseInterface.php +++ b/src/CancellablePromiseInterface.php @@ -4,6 +4,10 @@ namespace React\Promise; +/** + * @template T + * @extends PromiseInterface + */ interface CancellablePromiseInterface extends PromiseInterface { /** diff --git a/src/Deferred.php b/src/Deferred.php index 9a23323..8190a5d 100644 --- a/src/Deferred.php +++ b/src/Deferred.php @@ -4,14 +4,25 @@ namespace React\Promise; +/** + * @template T + */ class Deferred implements PromisorInterface { - private $promise; + /** + * @var null|PromiseInterface + */ + private ?PromiseInterface $promise = null; private $resolveCallback; private $rejectCallback; private $notifyCallback; + + /** @var callable|null */ private $canceller; + /** + * @param (callable(callable(T):void,callable(\Throwable):void):void)|null $canceller + */ public function __construct(?callable $canceller = null) { $this->canceller = $canceller; diff --git a/src/ExtendedPromiseInterface.php b/src/ExtendedPromiseInterface.php index 5572fd3..dfdf0e5 100644 --- a/src/ExtendedPromiseInterface.php +++ b/src/ExtendedPromiseInterface.php @@ -4,6 +4,10 @@ namespace React\Promise; +/** + * @template T + * @extends PromiseInterface + */ interface ExtendedPromiseInterface extends PromiseInterface { /** @@ -16,7 +20,9 @@ interface ExtendedPromiseInterface extends PromiseInterface * Since the purpose of `done()` is consumption rather than transformation, * `done()` always returns `null`. * - * @param callable|null $onProgress This argument is deprecated and should not be used anymore. + * @param null|(callable((T is void ? null : T)): mixed) $onFulfilled + * @param null|(callable(\Throwable): mixed) $onRejected + * @param null|callable $onProgress This argument is deprecated and should not be used anymore. * @return void */ public function done(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null); @@ -31,7 +37,9 @@ public function done(?callable $onFulfilled = null, ?callable $onRejected = null * Additionally, you can type hint the `$reason` argument of `$onRejected` to catch * only specific errors. * - * @return ExtendedPromiseInterface + * @template TRejected + * @param callable(\Throwable): (PromiseInterface|TRejected) $onRejected + * @return ExtendedPromiseInterface */ public function otherwise(callable $onRejected); @@ -77,7 +85,9 @@ public function otherwise(callable $onRejected); * ->always('cleanup'); * ``` * - * @return ExtendedPromiseInterface + * @param callable(): (void|PromiseInterface) $onFulfilledOrRejected + * + * @return ExtendedPromiseInterface */ public function always(callable $onFulfilledOrRejected); diff --git a/src/FulfilledPromise.php b/src/FulfilledPromise.php index 9712185..f73c676 100644 --- a/src/FulfilledPromise.php +++ b/src/FulfilledPromise.php @@ -5,12 +5,20 @@ namespace React\Promise; /** + * @template T + * @implements ExtendedPromiseInterface + * @implements CancellablePromiseInterface + * * @deprecated 2.8.0 External usage of FulfilledPromise is deprecated, use `resolve()` instead. */ class FulfilledPromise implements ExtendedPromiseInterface, CancellablePromiseInterface { - private $value; + /** @var T */ + private mixed $value; + /** + * @param T $value + */ public function __construct($value = null) { if ($value instanceof PromiseInterface) { diff --git a/src/LazyPromise.php b/src/LazyPromise.php index bacae41..19bfcb8 100644 --- a/src/LazyPromise.php +++ b/src/LazyPromise.php @@ -5,6 +5,10 @@ namespace React\Promise; /** + * @template T + * @implements ExtendedPromiseInterface + * @implements CancellablePromiseInterface + * * @deprecated 2.8.0 LazyPromise is deprecated and should not be used anymore. */ class LazyPromise implements ExtendedPromiseInterface, CancellablePromiseInterface diff --git a/src/Promise.php b/src/Promise.php index e002516..784da3d 100644 --- a/src/Promise.php +++ b/src/Promise.php @@ -4,14 +4,30 @@ namespace React\Promise; +/** + * @template T + * @implements ExtendedPromiseInterface + * @implements CancellablePromiseInterface + */ class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface { + /** @var (callable(callable(T): void, callable(\Throwable): void): void)|null */ private $canceller; - private $result; - private $handlers = []; - private $progressHandlers = []; - private $requiredCancelRequests = 0; - private $cancelRequests = 0; + + /** @var ?PromiseInterface */ + private ?PromiseInterface $result = null; + + /** @var list): void> */ + private array $handlers = []; + + /** @var list */ + private array $progressHandlers = []; + + /** @var int<0, max> */ + private int $requiredCancelRequests = 0; + + /** @var int<0, max> */ + private int $cancelRequests = 0; public function __construct(callable $resolver, ?callable $canceller = null) { diff --git a/src/PromiseInterface.php b/src/PromiseInterface.php index 7f4ba6f..5a7e64d 100644 --- a/src/PromiseInterface.php +++ b/src/PromiseInterface.php @@ -4,6 +4,12 @@ namespace React\Promise; +/** + * @note This is a stub interface for better IDE support. + * + * @yield T + * @template-covariant T + */ interface PromiseInterface { /** @@ -34,8 +40,12 @@ interface PromiseInterface * than once. * 3. `$onProgress` (deprecated) may be called multiple times. * - * @param callable|null $onProgress This argument is deprecated and should not be used anymore. - * @return PromiseInterface + * @template TFulfilled + * @template TRejected + * @param null|(callable(mixed): (PromiseInterface|TFulfilled)) $onFulfilled + * @param null|(callable(\Throwable): (PromiseInterface|TRejected)) $onRejected + * @param null|callable $onProgress This argument is deprecated and should not be used anymore. + * @return PromiseInterface<($onRejected is null ? ($onFulfilled is null ? T : TFulfilled) : ($onFulfilled is null ? T|TRejected : TFulfilled|TRejected))> */ public function then(?callable $onFulfilled = null, ?callable $onRejected = null, ?callable $onProgress = null); } diff --git a/src/RejectedPromise.php b/src/RejectedPromise.php index 9dc07aa..efb0575 100644 --- a/src/RejectedPromise.php +++ b/src/RejectedPromise.php @@ -5,6 +5,10 @@ namespace React\Promise; /** + * @template T + * @implements ExtendedPromiseInterface + * @implements CancellablePromiseInterface + * * @deprecated 2.8.0 External usage of RejectedPromise is deprecated, use `reject()` instead. */ class RejectedPromise implements ExtendedPromiseInterface, CancellablePromiseInterface diff --git a/src/functions.php b/src/functions.php index 116c4b5..6d7bd65 100644 --- a/src/functions.php +++ b/src/functions.php @@ -15,10 +15,11 @@ * * If `$promiseOrValue` is a promise, it will be returned as is. * - * @param mixed $promiseOrValue - * @return PromiseInterface + * @template T + * @param PromiseInterface|T $promiseOrValue + * @return PromiseInterface */ -function resolve($promiseOrValue = null) +function resolve($promiseOrValue = null): PromiseInterface { if ($promiseOrValue instanceof ExtendedPromiseInterface) { return $promiseOrValue; @@ -55,9 +56,9 @@ function resolve($promiseOrValue = null) * the value of another promise. * * @param mixed $promiseOrValue - * @return PromiseInterface + * @return PromiseInterface */ -function reject($promiseOrValue = null) +function reject($promiseOrValue = null): PromiseInterface { if ($promiseOrValue instanceof PromiseInterface) { return resolve($promiseOrValue)->then(static fn($value) => new RejectedPromise($value)); @@ -72,10 +73,11 @@ function reject($promiseOrValue = null) * will be an array containing the resolution values of each of the items in * `$promisesOrValues`. * - * @param array $promisesOrValues - * @return PromiseInterface + * @template T + * @param array|T> $promisesOrValues + * @return PromiseInterface> */ -function all($promisesOrValues) +function all($promisesOrValues): PromiseInterface { return map($promisesOrValues, static fn($val) => $val); } @@ -90,7 +92,7 @@ function all($promisesOrValues) * @param array $promisesOrValues * @return PromiseInterface */ -function race($promisesOrValues) +function race($promisesOrValues): PromiseInterface { $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); @@ -127,7 +129,7 @@ function race($promisesOrValues) * @param array $promisesOrValues * @return PromiseInterface */ -function any($promisesOrValues) +function any($promisesOrValues): PromiseInterface { return some($promisesOrValues, 1) ->then(static fn($val) => \array_shift($val)); @@ -151,7 +153,7 @@ function any($promisesOrValues) * @param int $howMany * @return PromiseInterface */ -function some($promisesOrValues, $howMany) +function some($promisesOrValues, $howMany): PromiseInterface { $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); @@ -225,9 +227,9 @@ function some($promisesOrValues, $howMany) * value of a promise or value in `$promisesOrValues`. * * @param array $promisesOrValues - * @return PromiseInterface + * @return PromiseInterface */ -function map($promisesOrValues, callable $mapFunc) +function map($promisesOrValues, callable $mapFunc): PromiseInterface { $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); @@ -275,7 +277,7 @@ static function ($mapped) use ($i, &$values, &$toResolve, $resolve): void { * @param mixed $initialValue * @return PromiseInterface */ -function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) +function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null): PromiseInterface { $cancellationQueue = new CancellationQueue(); $cancellationQueue->enqueue($promisesOrValues); @@ -296,9 +298,9 @@ function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null) $cancellationQueue->enqueue($val); return $current - ->then(static function ($c) use ($reduceFunc, $total, &$i, $val) { + ->then(static function ($c) use ($reduceFunc, $total, &$i, $val): PromiseInterface { return resolve($val) - ->then(static function ($value) use ($reduceFunc, $total, &$i, $c) { + ->then(static function ($value) use ($reduceFunc, $total, &$i, $c): mixed { return $reduceFunc($c, $value, $i++, $total); }); }); From eebd67dd497eb3fdb020de5fa5dd05c726885534 Mon Sep 17 00:00:00 2001 From: github-actions Date: Tue, 26 Aug 2025 19:16:30 +0000 Subject: [PATCH 15/15] style(php-cs-fixer): fix coding standards --- src/Deferred.php | 1 + src/functions.php | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Deferred.php b/src/Deferred.php index 8190a5d..5f27e07 100644 --- a/src/Deferred.php +++ b/src/Deferred.php @@ -13,6 +13,7 @@ class Deferred implements PromisorInterface * @var null|PromiseInterface */ private ?PromiseInterface $promise = null; + private $resolveCallback; private $rejectCallback; private $notifyCallback; diff --git a/src/functions.php b/src/functions.php index 6d7bd65..85363f1 100644 --- a/src/functions.php +++ b/src/functions.php @@ -90,7 +90,6 @@ function all($promisesOrValues): PromiseInterface * contains 0 items. * * @param array $promisesOrValues - * @return PromiseInterface */ function race($promisesOrValues): PromiseInterface { @@ -127,7 +126,6 @@ function race($promisesOrValues): PromiseInterface * if `$promisesOrValues` contains 0 items. * * @param array $promisesOrValues - * @return PromiseInterface */ function any($promisesOrValues): PromiseInterface { @@ -151,7 +149,6 @@ function any($promisesOrValues): PromiseInterface * * @param array $promisesOrValues * @param int $howMany - * @return PromiseInterface */ function some($promisesOrValues, $howMany): PromiseInterface { @@ -275,7 +272,6 @@ static function ($mapped) use ($i, &$values, &$toResolve, $resolve): void { * * @param array $promisesOrValues * @param mixed $initialValue - * @return PromiseInterface */ function reduce($promisesOrValues, callable $reduceFunc, $initialValue = null): PromiseInterface {