diff --git a/.gitattributes b/.gitattributes index 0b1a9bf2..9c56fa5e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,7 +4,6 @@ tests export-ignore .gitattributes export-ignore .gitignore export-ignore .php-cs-fixer.dist.php export-ignore -.scrutinizer.yml export-ignore dockerfile.sh export-ignore phpunit.xml.dist export-ignore psalm.xml export-ignore diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index d56e5dd6..85341189 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -1,6 +1,8 @@ name: QA on: push: + branches: + - master pull_request: workflow_dispatch: schedule: @@ -8,14 +10,23 @@ on: jobs: tests: + permissions: + actions: read + contents: read env: TNT_IMAGE: tarantool/tarantool:3.1 PHP_IMAGE: php:8.3-cli strategy: fail-fast: false matrix: - operating-system: [ubuntu-latest] + operating-system: [ubuntu-24.04] env: + - TNT_IMAGE: tarantool/tarantool:3.7 + - TNT_IMAGE: tarantool/tarantool:3.6 + - TNT_IMAGE: tarantool/tarantool:3.5 + - TNT_IMAGE: tarantool/tarantool:3.4 + - TNT_IMAGE: tarantool/tarantool:3.3 + - TNT_IMAGE: tarantool/tarantool:3.2 - TNT_IMAGE: tarantool/tarantool:3.0 - TNT_IMAGE: tarantool/tarantool:2.11 - TNT_IMAGE: tarantool/tarantool:2.10 @@ -31,55 +42,30 @@ jobs: - TNT_IMAGE: tarantool/tarantool:1.9 - TNT_IMAGE: tarantool/tarantool:1.7 - - PHP_IMAGE: php:8.3-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock + - PHP_IMAGE: php:8.5-cli + - PHP_IMAGE: php:8.4-cli - PHP_IMAGE: php:8.2-cli - - PHP_IMAGE: php:8.2-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:8.1-cli - - PHP_IMAGE: php:8.1-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:8.0-cli - - PHP_IMAGE: php:8.0-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:7.4-cli - - PHP_IMAGE: php:7.4-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:7.3-cli QA: 1 - - PHP_IMAGE: php:7.3-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - - PHP_IMAGE: php:7.2-cli - - PHP_IMAGE: php:7.2-cli - TNT_LISTEN_URI: /tmp/tarantool_client.sock - - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli - - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli + - COVERAGE_FILE: coverage.xml + PHP_IMAGE: php:8.3-cli + - COVERAGE_FILE: coverage.xml + PHP_IMAGE: php:8.3-cli EXT_DISABLE_DECIMAL: true - - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli + - COVERAGE_FILE: coverage.xml + PHP_IMAGE: php:8.3-cli TNT_LISTEN_URI: /tmp/tarantool_client.sock - - COVERAGE_FILE: coverage.clover - # scrutinizer doesn't support PHP 8 - PHP_IMAGE: php:7.4-cli + - COVERAGE_FILE: coverage.xml + PHP_IMAGE: php:8.3-cli # some tests are skipped on Tarantool > 2.8 TNT_IMAGE: tarantool/tarantool:2.8 + name: ${{ matrix.env.PHP_IMAGE || 'php:8.3-cli' }}, ${{ matrix.env.TNT_IMAGE || 'tarantool/tarantool:3.1' }}${{ matrix.env.QA && ', qa' || '' }}${{ matrix.env.COVERAGE_FILE && ', coverage' || '' }}${{ matrix.env.EXT_DISABLE_DECIMAL && ', decimal disabled' || '' }}${{ matrix.env.TNT_LISTEN_URI && ', unix socket' || '' }} runs-on: ${{ matrix.operating-system }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Build docker image env: ${{ matrix.env }} @@ -91,7 +77,7 @@ jobs: docker network create tarantool-php docker run --net=tarantool-php --rm $TNT_IMAGE sh -c "tarantool --version" docker run --net=tarantool-php -d --name=tarantool -v /tmp:/tmp -v $PWD/tests/Integration/client.lua:/client.lua -e TNT_LISTEN_URI=$TNT_LISTEN_URI $TNT_IMAGE tarantool /client.lua - docker run --net=tarantool-php --rm -v /tmp:/tmp -v $PWD:/client -w /client -e COMPOSER_ROOT_VERSION=dev-master client + docker run --net=tarantool-php --rm -v /tmp:/tmp -v "$GITHUB_WORKSPACE:$GITHUB_WORKSPACE" -w "$GITHUB_WORKSPACE" -e COMPOSER_ROOT_VERSION=dev-master client - name: Check code quality env: ${{ matrix.env }} @@ -100,9 +86,36 @@ jobs: docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php vendor/bin/php-cs-fixer fix --dry-run --diff --verbose . docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php vendor/bin/psalm - - name: Upload code coverage to Scrutinizer + - name: Upload code coverage report env: ${{ matrix.env }} if: ${{ env.COVERAGE_FILE }} - run: | - curl -sSOL https://scrutinizer-ci.com/ocular.phar - docker run --net=tarantool-php --rm -v $PWD:/client -w /client client php ocular.phar code-coverage:upload --format=php-clover "$COVERAGE_FILE" + uses: actions/upload-artifact@v7 + with: + name: coverage-${{ strategy.job-index }} + path: ${{ env.COVERAGE_FILE }} + + coverage: + needs: tests + runs-on: ubuntu-24.04 + permissions: + actions: read + contents: read + statuses: write + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Download coverage reports + uses: actions/download-artifact@v8 + with: + pattern: coverage-* + path: coverage-reports + + - name: Add combined code coverage report to workflow summary + uses: getsentry/coverage-action@0.3.8 + with: + token: ${{ secrets.GITHUB_TOKEN }} + directory: coverage-reports + coverage-format: cobertura + enable-tests: false + name: full-test-matrix diff --git a/.github/workflows/reusable_qa.yml b/.github/workflows/reusable_qa.yml index 197d83c0..5327e5c5 100644 --- a/.github/workflows/reusable_qa.yml +++ b/.github/workflows/reusable_qa.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Clone the tarantool-php/client connector - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: repository: tarantool-php/client diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 29a475da..21f85273 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -5,22 +5,34 @@ namespace Tarantool\Client; use PhpCsFixer\Config; +use PhpCsFixer\Fixer\ConfigurableFixerInterface; use PhpCsFixer\Fixer\ConstantNotation\NativeConstantInvocationFixer; -use PhpCsFixer\Fixer\FixerInterface; use PhpCsFixer\Fixer\FunctionNotation\NativeFunctionInvocationFixer; +use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; +use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; use PhpCsFixer\Tokenizer\Tokens; -final class FilterableFixer implements FixerInterface +final class FilterableFixer implements ConfigurableFixerInterface { - private $fixer; - private $pathRegex; + private ConfigurableFixerInterface $fixer; + private string $pathRegex; - public function __construct(FixerInterface $fixer, string $pathRegex) + public function __construct(ConfigurableFixerInterface $fixer, string $pathRegex) { $this->fixer = $fixer; $this->pathRegex = $pathRegex; } + public function configure(array $configuration) : void + { + $this->fixer->configure($configuration); + } + + public function getConfigurationDefinition() : FixerConfigurationResolverInterface + { + return $this->fixer->getConfigurationDefinition(); + } + public function isCandidate(Tokens $tokens) : bool { return $this->fixer->isCandidate($tokens); @@ -46,6 +58,11 @@ public function getPriority() : int return $this->fixer->getPriority(); } + public function getDefinition() : FixerDefinitionInterface + { + return $this->fixer->getDefinition(); + } + public function supports(\SplFileInfo $file) : bool { if (1 !== preg_match($this->pathRegex, $file->getRealPath())) { @@ -77,11 +94,13 @@ public function supports(\SplFileInfo $file) : bool '@Symfony:risky' => true, 'array_syntax' => ['syntax' => 'short'], 'binary_operator_spaces' => ['operators' => ['=' => null, '=>' => null]], + 'class_attributes_separation' => ['elements' => ['method' => 'one', 'property' => 'none']], 'declare_strict_types' => true, + 'integer_literal_case' => false, 'native_constant_invocation' => false, 'native_function_invocation' => false, 'FilterableFixer/native_constant_invocation' => true, - 'FilterableFixer/native_function_invocation' => true, + 'FilterableFixer/native_function_invocation' => ['include' => ['@all']], 'no_useless_else' => true, 'no_useless_return' => true, 'ordered_imports' => [ diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index e5562954..00000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,28 +0,0 @@ -checks: - php: true - -tools: - php_mess_detector: true - php_cpd: true - php_loc: - excluded_dirs: [vendor] - php_pdepend: - excluded_dirs: [vendor] - external_code_coverage: - runs: 4 - -build: - environment: - variables: - COMPOSER_ROOT_VERSION: dev-master - apt_packages: - - libmpdec-dev - php: - version: 7.4 - pecl_extensions: - - decimal - nodes: - analysis: - tests: - override: - - php-scrutinizer-run diff --git a/README.md b/README.md index 199530e8..88d29f32 100755 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ # PHP client for Tarantool [![Quality Assurance](https://github.com/tarantool-php/client/workflows/QA/badge.svg)](https://github.com/tarantool-php/client/actions?query=workflow%3AQA) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/tarantool-php/client/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/tarantool-php/client/?branch=master) -[![Code Coverage](https://scrutinizer-ci.com/g/tarantool-php/client/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/tarantool-php/client/?branch=master) [![Telegram](https://img.shields.io/badge/Telegram-join%20chat-blue.svg)](https://t.me/tarantool_php) -A pure PHP client for [Tarantool](https://www.tarantool.io/en/developers/) 1.7.1 or above. +A pure PHP client for [Tarantool](https://www.tarantool.io/en/developers/) 1.7.1 and later, including the 2.x and 3.x series. ## Features @@ -38,16 +36,18 @@ A pure PHP client for [Tarantool](https://www.tarantool.io/en/developers/) 1.7.1 ## Installation +This release requires PHP 8.2 or newer and `rybakit/msgpack` 0.11.2 or newer. + The recommended way to install the library is through [Composer](http://getcomposer.org): ```bash composer require tarantool/client ``` -In order to use the [Decimal](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-decimal-type) -type that was added in Tarantool 2.3, you additionally need to install the [decimal](http://php-decimal.io/#installation) -extension. Also, to improve performance when working with the [UUID](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-uuid-type) -type, which is available since Tarantool 2.4, it is recommended to additionally install the [uuid](https://pecl.php.net/package/uuid) extension. +To use the [Decimal](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-decimal-type) +type added in Tarantool 2.3, install the [decimal](http://php-decimal.io/#installation) +extension. To improve performance when working with the [UUID](https://www.tarantool.io/en/doc/latest/dev_guide/internals/msgpack_extensions/#the-uuid-type) +type, available since Tarantool 2.4, you can also install the [uuid](https://pecl.php.net/package/uuid) extension. ## Creating a client @@ -60,9 +60,9 @@ use Tarantool\Client\Client; $client = Client::fromDefaults(); ``` -The client will be configured to connect to `127.0.0.1` on port `3301` with the default stream connection options. -Also, the best available msgpack package will be chosen automatically. A custom configuration can be accomplished -by one of several methods listed. +The client connects to `127.0.0.1` on port `3301` using the default stream connection options. +It also selects the best available MessagePack package automatically. You can configure the client in several ways, +as described below. #### DSN string @@ -111,18 +111,18 @@ The following options are available: Name | Type | Default | Description --- | :---: | :---: | --- *uri* | string | 'tcp://127.0.0.1:3301' | The connection uri that is used to create a `StreamConnection` object. -*connect_timeout* | float | 5.0 | The number of seconds that the client waits for a connect to a Tarantool server before throwing a `ConnectionFailed` exception. -*socket_timeout* | float | 5.0 | The number of seconds that the client waits for a respond from a Tarantool server before throwing a `CommunicationFailed` exception. +*connect_timeout* | float | 5.0 | The number of seconds that the client waits to connect to a Tarantool server before throwing a `ConnectionFailed` exception. +*socket_timeout* | float | 5.0 | The number of seconds that the client waits for a response from a Tarantool server before throwing a `CommunicationFailed` exception. *tcp_nodelay* | boolean | true | Whether the Nagle algorithm is disabled on a TCP connection. *persistent* | boolean | false | Whether to use a persistent connection. *username* | string | | The username for the user being authenticated. *password* | string | '' | The password for the user being authenticated. If the username is not set, this option will be ignored. -*max_retries* | integer | 0 | The number of times the client retries unsuccessful request. If set to 0, the client does not try to resend the request after the initial unsuccessful attempt. +*max_retries* | integer | 0 | The number of times the client retries an unsuccessful request. If set to 0, the client does not retry after the initial unsuccessful attempt. #### Custom build -For more deep customisation, you can build a client from the ground up: +For more extensive customization, you can build a client from the ground up: ```php use MessagePack\BufferUnpacker; @@ -158,8 +158,8 @@ $client = new Client($handler); ## Handlers -A handler is a function which transforms a request into a response. Once you have created a handler object, -you can make requests to Tarantool, for example: +A handler transforms a request into a response. Once you have created a handler object, +you can use it to send requests to Tarantool, for example: ```php use Tarantool\Client\Keys; @@ -180,9 +180,9 @@ The library ships with two handlers: ## Middleware -Middleware is the suggested way to extend the client with custom functionality. There are several middleware classes -implemented to address the common use cases, like authentification, logging and [more](src/Middleware). -The usage is straightforward: +Middleware is the recommended way to extend the client with custom functionality. The library includes middleware +for common use cases, such as authentication and logging. See the full list in [`src/Middleware`](src/Middleware). +Usage is straightforward: ```php use Tarantool\Client\Client; @@ -193,7 +193,7 @@ $client = Client::fromDefaults()->withMiddleware( ); ``` -You may also assign multiple middleware to the client (they will be executed in [FIFO](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)) order): +You can also add multiple middleware components to the client. They execute in [FIFO](https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)) order: ```php use Tarantool\Client\Client; @@ -210,8 +210,8 @@ $client = Client::fromDefaults()->withMiddleware( ); ``` -Please be aware that the order in which you add the middleware does matter. The same middleware, -placed in different order, can give very different or sometimes unexpected behavior. +The order in which you add middleware matters. The same middleware, +placed in a different order, can produce different or sometimes unexpected behavior. To illustrate, consider the following configurations: ```php @@ -404,7 +404,7 @@ $space->upsert([1, 'foo', 'bar'], Operations::set(2, 'qux')); // Since Tarantool 2.3 you can refer to tuple fields by name: // $space->upsert([1, 'foo', 'bar'], Operations::set('name1', 'baz')); -// $space->upsert([1, 'foo', 'bar'], Operations::set('name2'', 'qux')); +// $space->upsert([1, 'foo', 'bar'], Operations::set('name2', 'qux')); ``` *Space data* @@ -563,9 +563,9 @@ Result 3: [3] ### SQL protocol -The following are examples of SQL protocol requests. For more detailed information and examples please see +The following are examples of SQL protocol requests. For more detailed information and examples, please see the [official documentation](https://www.tarantool.io/en/doc/latest/reference/reference_sql/sql/). -*Note that SQL is supported only as of Tarantool 2.0.* +*SQL is supported starting with Tarantool 2.0.*
Execute
@@ -602,8 +602,8 @@ Result 3: [1,{"id":1,"email":"foo@example.com"}] Result 4: [{"id":1,"email":"foo@example.com"},{"id":2,"email":"bar@example.com"}] ``` -If you need to execute a dynamic SQL statement whose type you don't know, you can use the generic method `execute()`. -This method returns a Response object with the body containing either an array of result set rows or an array +If you need to execute a dynamic SQL statement and do not know its type, use the generic `execute()` method. +It returns a `Response` object whose body contains either an array of result-set rows or an array with information about the changed rows: ```php @@ -660,10 +660,9 @@ $space->insert([42, Money::EUR(500)]); [[$id, $money]] = $space->select(Criteria::key([42])); ``` -This can be achieved by extending the MessagePack type system with your own types. To do this, you need to write -a MessagePack extension that converts your objects into MessagePack structures and back (for more details, read -the msgpack.php's [README](https://github.com/rybakit/msgpack.php#custom-types)). Once you have implemented -your extension, you should register it with the packer object: +You can do this by extending the MessagePack type system with your own types. Write a MessagePack extension +that converts your objects to and from MessagePack structures (see the msgpack.php [README](https://github.com/rybakit/msgpack.php#custom-types) for details). +Once you have implemented the extension, register it with the packer object: ```php $packer = PurePacker::fromExtensions(new MoneyExtension()); @@ -695,14 +694,14 @@ To run all tests: vendor/bin/phpunit ``` -If you already have Docker installed, you can run the tests in a docker container. -First, create a container: +If you already have Docker installed, you can run the tests in a Docker container. +First, build the Docker image: ```bash ./dockerfile.sh | docker build -t client - ``` -The command above will create a container named `client` with PHP 8.3 runtime. +The command above builds an image named `client` with the PHP 8.3 runtime. You may change the default runtime by defining the `PHP_IMAGE` environment variable: ```bash diff --git a/composer.json b/composer.json index 1e1f7b15..faa6989d 100644 --- a/composer.json +++ b/composer.json @@ -11,18 +11,20 @@ } ], "require": { - "php": "^7.2.5|^8", - "rybakit/msgpack": "^0.9", - "symfony/uid": "^5.1|^6|^7" + "php": "^8.2", + "rybakit/msgpack": "^0.11.2", + "symfony/uid": "^5.1|^6|^7|^8" }, "require-dev": { "ext-json": "*", "ext-sockets": "*", - "friendsofphp/php-cs-fixer": "^2.19", - "monolog/monolog": "^1.24|^2.0", - "psr/log": "^1.1", - "tarantool/phpunit-extras": "^0.2.0", - "vimeo/psalm": "^3.9|^4" + "composer/semver": "^3.3", + "friendsofphp/php-cs-fixer": "^3.0", + "monolog/monolog": "^3.0", + "phpunit/phpunit": "^10.5", + "psr/log": "^3.0", + "tarantool/phpunit-extras": "^0.3.0", + "vimeo/psalm": "^5.23|^6" }, "suggest": { "ext-decimal": "For using decimals with Tarantool 2.3+", @@ -45,6 +47,7 @@ }, "sort-packages": true }, + "prefer-stable": true, "extra": { "branch-alias": { "dev-master": "0.10.x-dev" diff --git a/dockerfile.sh b/dockerfile.sh index ee910f5c..11c210f4 100755 --- a/dockerfile.sh +++ b/dockerfile.sh @@ -51,5 +51,5 @@ ENV PATH=~/.composer/vendor/bin:\$PATH ENV TNT_LISTEN_URI=$TNT_LISTEN_URI CMD if [ ! -f composer.lock ]; then composer install; fi && \\ - vendor/bin/phpunit ${COVERAGE_FILE:+ --coverage-text --coverage-clover=}$COVERAGE_FILE + vendor/bin/phpunit ${COVERAGE_FILE:+ --coverage-text --coverage-cobertura=}$COVERAGE_FILE " diff --git a/examples/bootstrap.php b/examples/bootstrap.php index 77df1719..0e9b3b34 100644 --- a/examples/bootstrap.php +++ b/examples/bootstrap.php @@ -42,8 +42,7 @@ function ensure_server_version_at_least(string $version, Client $client) : void return; } - /** @psalm-suppress PossiblyUndefinedArrayOffset */ - requirement_exit('Tarantool version >= %s is required to run "%s"', $version, $_SERVER['SCRIPT_FILENAME']); + requirement_exit('Tarantool version >= %s is required to run "%s"', $version, $_SERVER['SCRIPT_FILENAME'] ?? ''); } function ensure_extension(string $name) : void @@ -52,11 +51,10 @@ function ensure_extension(string $name) : void return; } - /** @psalm-suppress PossiblyUndefinedArrayOffset */ - requirement_exit('PHP extension "%s" is required to run "%s"', $name, $_SERVER['SCRIPT_FILENAME']); + requirement_exit('PHP extension "%s" is required to run "%s"', $name, $_SERVER['SCRIPT_FILENAME'] ?? ''); } -function requirement_exit(string $message, ...$args) : void +function requirement_exit(string $message, mixed ...$args) : never { echo "Unfulfilled requirement:\n"; echo $args ? sprintf($message, ...$args) : $message, "\n"; diff --git a/examples/custom_error/example.php b/examples/custom_error/example.php index b0ef4875..1b9e9114 100644 --- a/examples/custom_error/example.php +++ b/examples/custom_error/example.php @@ -31,7 +31,7 @@ reason = "User #99 not found", })'); } catch (UserNotFound $e) { - printf("%s: [%d] %s\n", get_class($e), $e->getCode(), $e->getMessage()); + printf("%s: [%d] %s\n", $e::class, $e->getCode(), $e->getMessage()); } /* OUTPUT diff --git a/examples/logging/SlowRequestHandler.php b/examples/logging/SlowRequestHandler.php index fc46596e..8a813d82 100644 --- a/examples/logging/SlowRequestHandler.php +++ b/examples/logging/SlowRequestHandler.php @@ -15,40 +15,33 @@ use Monolog\Handler\HandlerInterface; use Monolog\Handler\HandlerWrapper; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LogRecord; use Tarantool\Client\RequestTypes; final class SlowRequestHandler extends HandlerWrapper { - /** @var int */ - private $thresholdMs; + private readonly Level $level; - /** @var int */ - private $level; - - /** @var string */ - private $levelName; - - /** - * @param positive-int $thresholdMs - * @param Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY $level - */ - public function __construct(HandlerInterface $handler, int $thresholdMs, int $level = Logger::WARNING) - { + public function __construct( + HandlerInterface $handler, + private readonly int $thresholdMs, + Level|int $level = Level::Warning, + ) { parent::__construct($handler); - $this->thresholdMs = $thresholdMs; - $this->level = $level; - $this->levelName = Logger::getLevelName($this->level); + $this->level = $level instanceof Level ? $level : Level::from($level); } - public function isHandling(array $record) : bool + #[\Override] + public function isHandling(LogRecord $record) : bool { // Handle all levels return true; } - public function handle(array $record) : bool + #[\Override] + public function handle(LogRecord $record) : bool { if (!isset($record['context']['duration_ms'], $record['context']['request'])) { return false; @@ -60,11 +53,10 @@ public function handle(array $record) : bool $request = $record['context']['request']; - return $this->handler->handle([ - 'level' => $this->level, - 'level_name' => $this->levelName, - 'message' => sprintf('Slow %s request detected (%d ms)', RequestTypes::getName($request->getType()), $record['context']['duration_ms']), - 'context' => ['request_body' => $request->getBody()], - ] + $record); + return $this->handler->handle($record->with( + level: $this->level, + message: sprintf('Slow %s request detected (%d ms)', RequestTypes::getName($request->getType()), $record['context']['duration_ms']), + context: ['request_body' => $request->getBody()] + $record['context'] + )); } } diff --git a/examples/logging/example.php b/examples/logging/example.php index f7f9eb3b..8de894c3 100644 --- a/examples/logging/example.php +++ b/examples/logging/example.php @@ -19,7 +19,7 @@ $loader = require __DIR__.'/../bootstrap.php'; $loader->addPsr4('App\\', __DIR__); -$stream = new StreamHandler('php://stdout' /*, Logger::WARNING */); +$stream = new StreamHandler('php://stdout' /* , Logger::WARNING */); $logger = new Logger('example'); $logger->pushHandler($stream); diff --git a/examples/protocol/delete.php b/examples/protocol/delete.php index 9a278044..4732aa78 100644 --- a/examples/protocol/delete.php +++ b/examples/protocol/delete.php @@ -16,8 +16,7 @@ $client = create_client(); $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); $result1 = $space->delete([2]); diff --git a/examples/protocol/insert.php b/examples/protocol/insert.php index a17ed637..31f32a7f 100644 --- a/examples/protocol/insert.php +++ b/examples/protocol/insert.php @@ -16,13 +16,11 @@ $client = create_client(); $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); $result = $space->insert([1, 'foo', 'bar']); diff --git a/examples/protocol/replace.php b/examples/protocol/replace.php index 9e410ed7..c10a3887 100644 --- a/examples/protocol/replace.php +++ b/examples/protocol/replace.php @@ -16,15 +16,13 @@ $client = create_client(); $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); $result1 = $space->replace([2, 'BAR']); diff --git a/examples/protocol/select.php b/examples/protocol/select.php index f9640ff2..96f21cc5 100644 --- a/examples/protocol/select.php +++ b/examples/protocol/select.php @@ -18,8 +18,7 @@ $client = create_client(); $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); $result1 = $space->select(Criteria::key([1])); diff --git a/examples/protocol/select_with_sorting.php b/examples/protocol/select_with_sorting.php index b2ddb833..8da508e3 100644 --- a/examples/protocol/select_with_sorting.php +++ b/examples/protocol/select_with_sorting.php @@ -18,8 +18,7 @@ $client = create_client(); $spaceName = 'cars'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); diff --git a/examples/protocol/update.php b/examples/protocol/update.php index af51bd28..39408192 100644 --- a/examples/protocol/update.php +++ b/examples/protocol/update.php @@ -18,8 +18,7 @@ $client = create_client(); $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); diff --git a/examples/protocol/upsert.php b/examples/protocol/upsert.php index f2344ab9..5747b473 100644 --- a/examples/protocol/upsert.php +++ b/examples/protocol/upsert.php @@ -19,8 +19,7 @@ $client = create_client(); $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); $space->upsert([1, 'foo', 'bar'], Operations::set(1, 'baz')); diff --git a/examples/tarantool16_call/LegacyCallMiddleware.php b/examples/tarantool16_call/LegacyCallMiddleware.php index 51bbe225..2a9f42c0 100644 --- a/examples/tarantool16_call/LegacyCallMiddleware.php +++ b/examples/tarantool16_call/LegacyCallMiddleware.php @@ -21,6 +21,7 @@ final class LegacyCallMiddleware implements Middleware { + #[\Override] public function process(Request $request, Handler $handler) : Response { if (!$request instanceof CallRequest) { diff --git a/examples/tarantool16_call/LegacyCallRequest.php b/examples/tarantool16_call/LegacyCallRequest.php index 6b3470b2..aef50752 100644 --- a/examples/tarantool16_call/LegacyCallRequest.php +++ b/examples/tarantool16_call/LegacyCallRequest.php @@ -21,12 +21,12 @@ final class LegacyCallRequest implements Request private const TYPE = 6; /** @var non-empty-array */ - private $body; + private readonly array $body; /** * @param non-empty-array $body */ - private function __construct($body) + private function __construct(array $body) { $this->body = $body; } @@ -36,11 +36,13 @@ public static function fromCallRequest(CallRequest $request) : self return new self($request->getBody()); } + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/examples/user_defined_type/Email.php b/examples/user_defined_type/Email.php index 9d37c2ad..edfe2915 100644 --- a/examples/user_defined_type/Email.php +++ b/examples/user_defined_type/Email.php @@ -15,11 +15,8 @@ final class Email { - private $value; - - public function __construct(string $value) + public function __construct(private readonly string $value) { - $this->value = $value; } public function equals(self $email) : bool diff --git a/examples/user_defined_type/EmailExtension.php b/examples/user_defined_type/EmailExtension.php index 085c6f8a..964b8fe6 100644 --- a/examples/user_defined_type/EmailExtension.php +++ b/examples/user_defined_type/EmailExtension.php @@ -19,22 +19,18 @@ final class EmailExtension implements Extension { - private $type; - - public function __construct(int $type) + public function __construct(private readonly int $type) { - $this->type = $type; } + #[\Override] public function getType() : int { return $this->type; } - /** - * @param mixed $value - */ - public function pack(Packer $packer, $value) : ?string + #[\Override] + public function pack(Packer $packer, mixed $value) : ?string { if (!$value instanceof Email) { return null; @@ -45,6 +41,7 @@ public function pack(Packer $packer, $value) : ?string ); } + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) : Email { return new Email($unpacker->unpackStr()); diff --git a/examples/user_defined_type/example_decimal.php b/examples/user_defined_type/example_decimal.php index c80740e9..e84384ca 100644 --- a/examples/user_defined_type/example_decimal.php +++ b/examples/user_defined_type/example_decimal.php @@ -22,17 +22,15 @@ $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); -$result1 = $space->insert([3, new Decimal('1.000000099')]); +$result1 = $space->insert([3, Decimal::valueOf('1.000000099')]); $result2 = $space->select(Criteria::key([3])); printf("Result 1: %s\n", $result1[0][1]->toString()); diff --git a/examples/user_defined_type/example_email.php b/examples/user_defined_type/example_email.php index 5cbf93ba..252635de 100644 --- a/examples/user_defined_type/example_email.php +++ b/examples/user_defined_type/example_email.php @@ -23,13 +23,11 @@ $client = create_client($packer); $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); diff --git a/examples/user_defined_type/example_uuid.php b/examples/user_defined_type/example_uuid.php index 381268e8..24ce84d5 100644 --- a/examples/user_defined_type/example_uuid.php +++ b/examples/user_defined_type/example_uuid.php @@ -21,15 +21,13 @@ $spaceName = 'example'; -$client->evaluate( -<<evaluate(<<getSpace($spaceName); diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 044d61c9..423c5824 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,16 +1,11 @@ @@ -33,9 +28,9 @@ - - + + src - - + + diff --git a/psalm.xml b/psalm.xml index bd18c5d6..708d942b 100644 --- a/psalm.xml +++ b/psalm.xml @@ -12,7 +12,6 @@ - @@ -32,10 +31,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/Client.php b/src/Client.php index e93fea27..966caaab 100644 --- a/src/Client.php +++ b/src/Client.php @@ -33,11 +33,10 @@ final class Client { - /** @var Handler */ - private $handler; + private Handler $handler; /** @var array */ - private $spaces = []; + private array $spaces = []; public function __construct(Handler $handler) { @@ -170,35 +169,23 @@ public function ping() : void $this->handler->handle(new PingRequest()); } - /** - * @param mixed ...$args - */ public function call(string $funcName, ...$args) : array { return $this->handler->handle(new CallRequest($funcName, $args)) ->getBodyField(Keys::DATA); } - /** - * @param mixed ...$args - */ public function evaluate(string $expr, ...$args) : array { return $this->handler->handle(new EvaluateRequest($expr, $args)) ->getBodyField(Keys::DATA); } - /** - * @param mixed ...$params - */ public function execute(string $sql, ...$params) : Response { return $this->handler->handle(ExecuteRequest::fromSql($sql, $params)); } - /** - * @param mixed ...$params - */ public function executeQuery(string $sql, ...$params) : SqlQueryResult { $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params)); @@ -209,9 +196,6 @@ public function executeQuery(string $sql, ...$params) : SqlQueryResult ); } - /** - * @param mixed ...$params - */ public function executeUpdate(string $sql, ...$params) : SqlUpdateResult { $response = $this->handler->handle(ExecuteRequest::fromSql($sql, $params)); diff --git a/src/Connection/Greeting.php b/src/Connection/Greeting.php index 8f6d0021..f8aa3543 100644 --- a/src/Connection/Greeting.php +++ b/src/Connection/Greeting.php @@ -19,29 +19,19 @@ final class Greeting { public const SIZE_BYTES = 128; - /** @var string */ - private $greeting; + private string $greeting; + private ?string $salt = null; + private ?string $serverVersion = null; + private bool $unknown = false; - /** @var string|null */ - private $salt; - - /** @var string|null */ - private $serverVersion; - - /** @var bool */ - private $unknown = false; - - /** - * @param string $greeting - */ - private function __construct($greeting) + private function __construct(string $greeting) { $this->greeting = $greeting; } public static function parse(string $greeting) : self { - if (0 === \strpos($greeting, 'Tarantool')) { + if (\str_starts_with($greeting, 'Tarantool')) { return new self($greeting); } diff --git a/src/Connection/StreamConnection.php b/src/Connection/StreamConnection.php index f15927c2..9cfd7e83 100644 --- a/src/Connection/StreamConnection.php +++ b/src/Connection/StreamConnection.php @@ -21,17 +21,10 @@ final class StreamConnection implements Connection { public const DEFAULT_TCP_URI = 'tcp://127.0.0.1:3301'; - /** @var string */ - private $uri; - - /** @var float */ - private $connectTimeout; - - /** @var float */ - private $socketTimeout; - - /** @var bool */ - private $persistent; + private string $uri; + private float $connectTimeout; + private float $socketTimeout; + private bool $persistent; /** @var resource|null */ private $streamContext; @@ -39,13 +32,9 @@ final class StreamConnection implements Connection /** @var resource|null */ private $stream; - /** @var Greeting|null */ - private $greeting; + private ?Greeting $greeting = null; - /** - * @param string $uri - */ - private function __construct($uri, float $connectTimeout, float $socketTimeout, bool $persistent, bool $tcpNoDelay) + private function __construct(string $uri, float $connectTimeout, float $socketTimeout, bool $persistent, bool $tcpNoDelay) { $this->uri = $uri; $this->connectTimeout = $connectTimeout; @@ -79,11 +68,12 @@ public static function createUds(string $uri, array $options = []) : self public static function create(string $uri, array $options = []) : self { - return 0 === \strpos($uri, 'unix://') + return \str_starts_with($uri, 'unix://') ? self::createUds($uri, $options) : self::createTcp($uri, $options); } + #[\Override] public function open() : Greeting { if ($this->greeting) { @@ -128,6 +118,7 @@ public function open() : Greeting return $this->greeting = Greeting::parse($greeting); } + #[\Override] public function close() : void { if ($this->stream) { @@ -139,11 +130,13 @@ public function close() : void $this->greeting = null; } + #[\Override] public function isClosed() : bool { return !$this->stream; } + #[\Override] public function send(string $data) : string { if (!$this->stream) { diff --git a/src/Dsn.php b/src/Dsn.php index 8dcc527f..57984a89 100644 --- a/src/Dsn.php +++ b/src/Dsn.php @@ -15,44 +15,28 @@ final class Dsn { - /** @var string|null */ - private $host; - - /** @var int|null */ - private $port; - - /** @var string|null */ - private $path; - - /** @var string */ - private $connectionUri; - - /** @var string|null */ - private $username; - - /** @var string|null */ - private $password; - - /** @var bool */ - private $isTcp = false; + private ?string $host = null; + private ?int $port = null; + private ?string $path = null; + private string $connectionUri; + private ?string $username = null; + private ?string $password = null; + private bool $isTcp = false; /** * @var array * @psalm-suppress PropertyNotSetInConstructor */ - private $options; + private array $options = []; - /** - * @param string $connectionUri - */ - private function __construct($connectionUri) + private function __construct(string $connectionUri) { $this->connectionUri = $connectionUri; } public static function parse(string $dsn) : self { - if (0 === \strpos($dsn, 'unix://') && isset($dsn[7])) { + if (\str_starts_with($dsn, 'unix://') && isset($dsn[7])) { return self::parseUds($dsn); } diff --git a/src/Error.php b/src/Error.php index f49155bd..c53e7109 100644 --- a/src/Error.php +++ b/src/Error.php @@ -15,14 +15,14 @@ final class Error { - private $type; - private $file; - private $line; - private $message; - private $number; - private $code; - private $fields; - private $previous; + private string $type; + private string $file; + private int $line; + private string $message; + private int $number; + private int $code; + private array $fields; + private ?self $previous; public function __construct( string $type, @@ -32,7 +32,7 @@ public function __construct( int $number, int $code, array $fields = [], - ?self $previous = null + ?self $previous = null, ) { $this->type = $type; $this->file = $file; @@ -138,9 +138,6 @@ public function getFields() : array return $this->fields; } - /** - * @return mixed - */ public function getField(string $name) { if (\array_key_exists($name, $this->fields)) { @@ -150,10 +147,6 @@ public function getField(string $name) throw new \OutOfRangeException(\sprintf('The field "%s" does not exist', $name)); } - /** - * @param mixed $default - * @return mixed - */ public function tryGetField(string $name, $default = null) { return \array_key_exists($name, $this->fields) ? $this->fields[$name] : $default; diff --git a/src/Exception/RequestDenied.php b/src/Exception/RequestDenied.php index b1b8689c..37b0bbef 100644 --- a/src/Exception/RequestDenied.php +++ b/src/Exception/RequestDenied.php @@ -19,6 +19,6 @@ final class RequestDenied extends \RuntimeException implements ClientException { public static function fromObject(Request $request) : self { - return new self(\sprintf('Request "%s" is denied', \get_class($request))); + return new self(\sprintf('Request "%s" is denied', $request::class)); } } diff --git a/src/Exception/RequestFailed.php b/src/Exception/RequestFailed.php index 704c388d..a1519624 100644 --- a/src/Exception/RequestFailed.php +++ b/src/Exception/RequestFailed.php @@ -19,8 +19,7 @@ final class RequestFailed extends \RuntimeException implements ClientException { - /** @var Error|null */ - private $error; + private ?Error $error = null; public function getError() : ?Error { diff --git a/src/Handler/DefaultHandler.php b/src/Handler/DefaultHandler.php index 26984b93..3eba2ead 100644 --- a/src/Handler/DefaultHandler.php +++ b/src/Handler/DefaultHandler.php @@ -22,8 +22,8 @@ final class DefaultHandler implements Handler { - private $connection; - private $packer; + private Connection $connection; + private Packer $packer; public function __construct(Connection $connection, Packer $packer) { @@ -31,6 +31,7 @@ public function __construct(Connection $connection, Packer $packer) $this->packer = $packer; } + #[\Override] public function handle(Request $request) : Response { $packet = $this->packer->pack($request, $sync = \mt_rand()); @@ -51,11 +52,13 @@ public function handle(Request $request) : Response return $response; } + #[\Override] public function getConnection() : Connection { return $this->connection; } + #[\Override] public function getPacker() : Packer { return $this->packer; diff --git a/src/Handler/MiddlewareHandler.php b/src/Handler/MiddlewareHandler.php index 5b0f882b..d0d0acaa 100644 --- a/src/Handler/MiddlewareHandler.php +++ b/src/Handler/MiddlewareHandler.php @@ -21,20 +21,15 @@ final class MiddlewareHandler implements Handler { - /** @var Handler */ - private $handler; + private Handler $handler; /** @var Middleware[] */ - private $middleware; + private array $middleware; - /** @var int */ - private $index = 0; + private int $index = 0; - /** - * @param Handler $handler - * @param Middleware[] $middleware - */ - private function __construct($handler, $middleware) + /** @param Middleware[] $middleware */ + private function __construct(Handler $handler, array $middleware) { $this->handler = $handler; $this->middleware = $middleware; @@ -70,6 +65,7 @@ public static function prepend(Handler $handler, array $middleware) : Handler return $handler; } + #[\Override] public function handle(Request $request) : Response { if (!isset($this->middleware[$this->index])) { @@ -82,11 +78,13 @@ public function handle(Request $request) : Response return $this->middleware[$this->index]->process($request, $new); } + #[\Override] public function getConnection() : Connection { return $this->handler->getConnection(); } + #[\Override] public function getPacker() : Packer { return $this->handler->getPacker(); diff --git a/src/Middleware/AuthenticationMiddleware.php b/src/Middleware/AuthenticationMiddleware.php index 3c6788f2..c7c34873 100644 --- a/src/Middleware/AuthenticationMiddleware.php +++ b/src/Middleware/AuthenticationMiddleware.php @@ -21,11 +21,9 @@ final class AuthenticationMiddleware implements Middleware { - private $username; - private $password; - - /** @var Greeting|null */ - private $greeting; + private string $username; + private string $password; + private ?Greeting $greeting = null; public function __construct(string $username, string $password = '') { @@ -33,6 +31,7 @@ public function __construct(string $username, string $password = '') $this->password = $password; } + #[\Override] public function process(Request $request, Handler $handler) : Response { $greeting = $handler->getConnection()->open(); diff --git a/src/Middleware/CustomErrorMiddleware.php b/src/Middleware/CustomErrorMiddleware.php index d351ca43..8a7deb05 100644 --- a/src/Middleware/CustomErrorMiddleware.php +++ b/src/Middleware/CustomErrorMiddleware.php @@ -22,12 +22,12 @@ final class CustomErrorMiddleware implements Middleware { /** @var \Closure(Error, RequestFailed) : \Exception */ - private $factory; + private \Closure $factory; /** * @param \Closure(Error, RequestFailed) : \Exception $factory */ - private function __construct($factory) + private function __construct(\Closure $factory) { $this->factory = $factory; } @@ -123,6 +123,7 @@ static function (Error $err, RequestFailed $ex) use ($namespace) : \Exception { ); } + #[\Override] public function process(Request $request, Handler $handler) : Response { try { diff --git a/src/Middleware/FirewallMiddleware.php b/src/Middleware/FirewallMiddleware.php index b45c5ddc..850b2992 100644 --- a/src/Middleware/FirewallMiddleware.php +++ b/src/Middleware/FirewallMiddleware.php @@ -22,16 +22,12 @@ final class FirewallMiddleware implements Middleware { /** @var array */ - private $allowed; + private array $allowed; /** @var array */ - private $denied; + private array $denied; - /** - * @param array $allowed - * @param array $denied - */ - private function __construct($allowed, $denied) + private function __construct(array $allowed, array $denied) { $this->allowed = $allowed ? \array_fill_keys($allowed, true) : []; $this->denied = $denied ? \array_fill_keys($denied, true) : []; @@ -99,6 +95,7 @@ public function andDenyOnly(int $requestType, int ...$requestTypes) : self return $new; } + #[\Override] public function process(Request $request, Handler $handler) : Response { $requestType = $request->getType(); diff --git a/src/Middleware/LoggingMiddleware.php b/src/Middleware/LoggingMiddleware.php index 527264bf..12e6a1b0 100644 --- a/src/Middleware/LoggingMiddleware.php +++ b/src/Middleware/LoggingMiddleware.php @@ -21,13 +21,14 @@ final class LoggingMiddleware implements Middleware { - private $logger; + private LoggerInterface $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } + #[\Override] public function process(Request $request, Handler $handler) : Response { $requestName = RequestTypes::getName($request->getType()); diff --git a/src/Middleware/RetryMiddleware.php b/src/Middleware/RetryMiddleware.php index 86b7de89..33bd3967 100644 --- a/src/Middleware/RetryMiddleware.php +++ b/src/Middleware/RetryMiddleware.php @@ -27,13 +27,13 @@ final class RetryMiddleware implements Middleware private const MAX_RETRIES_LIMIT = 10; private const MAX_DELAY_MS = 60000; - /** @var \Closure */ - private $getDelayMs; + /** @var \Closure(int, \Throwable) : ?int */ + private \Closure $getDelayMs; /** - * @param \Closure $getDelayMs + * @param \Closure(int, \Throwable) : ?int $getDelayMs */ - private function __construct($getDelayMs) + private function __construct(\Closure $getDelayMs) { $this->getDelayMs = $getDelayMs; } @@ -59,6 +59,9 @@ public static function linear(int $maxRetries = self::DEFAULT_MAX_RETRIES, int $ }); } + /** + * @param \Closure(int, \Throwable) : ?int $getDelayMs + */ public static function custom(\Closure $getDelayMs) : self { return new self(static function (int $retries, \Throwable $e) use ($getDelayMs) : ?int { @@ -66,17 +69,18 @@ public static function custom(\Closure $getDelayMs) : self }); } + #[\Override] public function process(Request $request, Handler $handler) : Response { $retries = 0; - do { + while (true) { try { return $handler->handle($request); } catch (UnexpectedResponse $e) { $handler->getConnection()->close(); break; - } catch (ConnectionFailed | CommunicationFailed $e) { + } catch (ConnectionFailed|CommunicationFailed $e) { $handler->getConnection()->close(); goto retry; } catch (ClientException $e) { @@ -91,7 +95,7 @@ public function process(Request $request, Handler $handler) : Response $delayMs += \mt_rand(0, $delayMs); \usleep($delayMs * 1000); } - } while (true); + } throw $e; } diff --git a/src/Packer/Extension/DecimalExtension.php b/src/Packer/Extension/DecimalExtension.php index 6f939ef1..268984e7 100644 --- a/src/Packer/Extension/DecimalExtension.php +++ b/src/Packer/Extension/DecimalExtension.php @@ -23,11 +23,13 @@ final class DecimalExtension implements Extension private const TYPE = 1; private const PRECISION = 38; + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function pack(Packer $packer, $value) : ?string { if (!$value instanceof Decimal) { @@ -60,6 +62,7 @@ public function pack(Packer $packer, $value) : ?string /** * @return Decimal */ + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) { /** @@ -80,6 +83,6 @@ public function unpackExt(BufferUnpacker $unpacker, int $extLength) : \substr_replace($dec, '.', -$scale, 0); } - return new Decimal($sign.$dec, self::PRECISION); + return Decimal::valueOf($sign.$dec, self::PRECISION); } } diff --git a/src/Packer/Extension/ErrorExtension.php b/src/Packer/Extension/ErrorExtension.php index 74b733cd..19224790 100644 --- a/src/Packer/Extension/ErrorExtension.php +++ b/src/Packer/Extension/ErrorExtension.php @@ -23,11 +23,13 @@ final class ErrorExtension implements Extension { private const TYPE = 3; + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function pack(Packer $packer, $value) : ?string { if (!$value instanceof Error) { @@ -49,6 +51,7 @@ public function pack(Packer $packer, $value) : ?string /** * @return Error */ + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) { return Error::fromMap($unpacker->unpackMap()); diff --git a/src/Packer/Extension/UuidExtension.php b/src/Packer/Extension/UuidExtension.php index 153265ea..ac9b8540 100644 --- a/src/Packer/Extension/UuidExtension.php +++ b/src/Packer/Extension/UuidExtension.php @@ -22,11 +22,13 @@ final class UuidExtension implements Extension { private const TYPE = 2; + #[\Override] public function getType() : int { return self::TYPE; } + #[\Override] public function pack(Packer $packer, $value) : ?string { if (!$value instanceof Uuid) { @@ -39,6 +41,7 @@ public function pack(Packer $packer, $value) : ?string /** * @return Uuid */ + #[\Override] public function unpackExt(BufferUnpacker $unpacker, int $extLength) { return Uuid::fromString($unpacker->read($extLength)); diff --git a/src/Packer/PurePacker.php b/src/Packer/PurePacker.php index 844b9a45..ba27cfb1 100644 --- a/src/Packer/PurePacker.php +++ b/src/Packer/PurePacker.php @@ -28,11 +28,8 @@ final class PurePacker implements ClientPacker { - /** @var Packer */ - private $packer; - - /** @var BufferUnpacker */ - private $unpacker; + private Packer $packer; + private BufferUnpacker $unpacker; public function __construct(?Packer $packer = null, ?BufferUnpacker $unpacker = null) { @@ -68,6 +65,7 @@ public static function fromAvailableExtensions() : self ); } + #[\Override] public function pack(Request $request, int $sync) : string { // Hot path optimization @@ -78,6 +76,7 @@ public function pack(Request $request, int $sync) : string return PacketLength::pack(\strlen($packet)).$packet; } + #[\Override] public function unpack(string $packet) : Response { $this->unpacker->reset($packet); diff --git a/src/PreparedStatement.php b/src/PreparedStatement.php index 64ea5f47..8249a51f 100644 --- a/src/PreparedStatement.php +++ b/src/PreparedStatement.php @@ -19,11 +19,11 @@ final class PreparedStatement { - private $handler; - private $id; - private $bindCount; - private $bindMetadata; - private $metadata; + private Handler $handler; + private int $id; + private int $bindCount; + private array $bindMetadata; + private array $metadata; public function __construct(Handler $handler, int $id, int $bindCount, array $bindMetadata, array $metadata) { @@ -34,9 +34,6 @@ public function __construct(Handler $handler, int $id, int $bindCount, array $bi $this->metadata = $metadata; } - /** - * @param mixed ...$params - */ public function execute(...$params) : Response { return $this->handler->handle( @@ -44,9 +41,6 @@ public function execute(...$params) : Response ); } - /** - * @param mixed ...$params - */ public function executeQuery(...$params) : SqlQueryResult { $response = $this->handler->handle( @@ -59,9 +53,6 @@ public function executeQuery(...$params) : SqlQueryResult ); } - /** - * @param mixed ...$params - */ public function executeUpdate(...$params) : SqlUpdateResult { $response = $this->handler->handle( diff --git a/src/Request/AuthenticateRequest.php b/src/Request/AuthenticateRequest.php index 5d28a99c..3fa394d2 100644 --- a/src/Request/AuthenticateRequest.php +++ b/src/Request/AuthenticateRequest.php @@ -19,7 +19,7 @@ final class AuthenticateRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(string $salt, string $username, string $password = '') { @@ -32,11 +32,13 @@ public function __construct(string $salt, string $username, string $password = ' ]; } + #[\Override] public function getType() : int { return RequestTypes::AUTHENTICATE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/CallRequest.php b/src/Request/CallRequest.php index ec1a9d6b..f832bf15 100644 --- a/src/Request/CallRequest.php +++ b/src/Request/CallRequest.php @@ -19,7 +19,7 @@ final class CallRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(string $funcName, array $args = []) { @@ -29,11 +29,13 @@ public function __construct(string $funcName, array $args = []) ]; } + #[\Override] public function getType() : int { return RequestTypes::CALL; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/DeleteRequest.php b/src/Request/DeleteRequest.php index 5b6a5a28..b4d3174e 100644 --- a/src/Request/DeleteRequest.php +++ b/src/Request/DeleteRequest.php @@ -19,7 +19,7 @@ final class DeleteRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, int $indexId, array $key) { @@ -30,11 +30,13 @@ public function __construct(int $spaceId, int $indexId, array $key) ]; } + #[\Override] public function getType() : int { return RequestTypes::DELETE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/EvaluateRequest.php b/src/Request/EvaluateRequest.php index fa7b8813..1ac931c7 100644 --- a/src/Request/EvaluateRequest.php +++ b/src/Request/EvaluateRequest.php @@ -19,7 +19,7 @@ final class EvaluateRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(string $expr, array $args = []) { @@ -29,11 +29,13 @@ public function __construct(string $expr, array $args = []) ]; } + #[\Override] public function getType() : int { return RequestTypes::EVALUATE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/ExecuteRequest.php b/src/Request/ExecuteRequest.php index 61c304a3..3c1e91f5 100644 --- a/src/Request/ExecuteRequest.php +++ b/src/Request/ExecuteRequest.php @@ -19,12 +19,12 @@ final class ExecuteRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; /** * @param non-empty-array $body */ - private function __construct($body) + private function __construct(array $body) { $this->body = $body; } @@ -49,11 +49,13 @@ public static function fromStatementId(int $statementId, array $params = []) : s ]); } + #[\Override] public function getType() : int { return RequestTypes::EXECUTE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/InsertRequest.php b/src/Request/InsertRequest.php index ee809ffd..8a7baa9a 100644 --- a/src/Request/InsertRequest.php +++ b/src/Request/InsertRequest.php @@ -19,7 +19,7 @@ final class InsertRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, array $tuple) { @@ -29,11 +29,13 @@ public function __construct(int $spaceId, array $tuple) ]; } + #[\Override] public function getType() : int { return RequestTypes::INSERT; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/PingRequest.php b/src/Request/PingRequest.php index 48b27336..1d2262ca 100644 --- a/src/Request/PingRequest.php +++ b/src/Request/PingRequest.php @@ -17,11 +17,13 @@ final class PingRequest implements Request { + #[\Override] public function getType() : int { return RequestTypes::PING; } + #[\Override] public function getBody() : array { return []; diff --git a/src/Request/PrepareRequest.php b/src/Request/PrepareRequest.php index 94a87e35..d5540d17 100644 --- a/src/Request/PrepareRequest.php +++ b/src/Request/PrepareRequest.php @@ -19,12 +19,12 @@ final class PrepareRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; /** * @param non-empty-array $body */ - private function __construct($body) + private function __construct(array $body) { $this->body = $body; } @@ -39,11 +39,13 @@ public static function fromStatementId(int $statementId) : self return new self([Keys::STMT_ID => $statementId]); } + #[\Override] public function getType() : int { return RequestTypes::PREPARE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/ReplaceRequest.php b/src/Request/ReplaceRequest.php index 3c100c32..c361c7eb 100644 --- a/src/Request/ReplaceRequest.php +++ b/src/Request/ReplaceRequest.php @@ -19,7 +19,7 @@ final class ReplaceRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, array $tuple) { @@ -29,11 +29,13 @@ public function __construct(int $spaceId, array $tuple) ]; } + #[\Override] public function getType() : int { return RequestTypes::REPLACE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/SelectRequest.php b/src/Request/SelectRequest.php index 6b7a7193..4069e7ab 100644 --- a/src/Request/SelectRequest.php +++ b/src/Request/SelectRequest.php @@ -19,7 +19,7 @@ final class SelectRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, int $indexId, array $key, int $offset, int $limit, int $iteratorType) { @@ -33,11 +33,13 @@ public function __construct(int $spaceId, int $indexId, array $key, int $offset, ]; } + #[\Override] public function getType() : int { return RequestTypes::SELECT; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/UpdateRequest.php b/src/Request/UpdateRequest.php index dc0853d3..89e8db50 100644 --- a/src/Request/UpdateRequest.php +++ b/src/Request/UpdateRequest.php @@ -19,7 +19,7 @@ final class UpdateRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, int $indexId, array $key, array $operations) { @@ -31,11 +31,13 @@ public function __construct(int $spaceId, int $indexId, array $key, array $opera ]; } + #[\Override] public function getType() : int { return RequestTypes::UPDATE; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Request/UpsertRequest.php b/src/Request/UpsertRequest.php index 4e9bf70a..85b2eccb 100644 --- a/src/Request/UpsertRequest.php +++ b/src/Request/UpsertRequest.php @@ -19,7 +19,7 @@ final class UpsertRequest implements Request { /** @var non-empty-array */ - private $body; + private array $body; public function __construct(int $spaceId, array $tuple, array $operations) { @@ -30,11 +30,13 @@ public function __construct(int $spaceId, array $tuple, array $operations) ]; } + #[\Override] public function getType() : int { return RequestTypes::UPSERT; } + #[\Override] public function getBody() : array { return $this->body; diff --git a/src/Response.php b/src/Response.php index 5ce01423..d16a28d4 100644 --- a/src/Response.php +++ b/src/Response.php @@ -17,8 +17,8 @@ final class Response { public const TYPE_ERROR = 0x8000; - private $header; - private $body; + private array $header; + private array $body; public function __construct(array $header, array $body) { @@ -48,9 +48,6 @@ public function getSchemaId() : int return $this->header[Keys::SCHEMA_ID]; } - /** - * @return mixed - */ public function getBodyField(int $key) { if (\array_key_exists($key, $this->body)) { @@ -60,11 +57,6 @@ public function getBodyField(int $key) throw new \OutOfRangeException(\sprintf('The body key 0x%x does not exist', $key)); } - /** - * @param mixed $default - * - * @return mixed - */ public function tryGetBodyField(int $key, $default = null) { return \array_key_exists($key, $this->body) ? $this->body[$key] : $default; diff --git a/src/Schema/Criteria.php b/src/Schema/Criteria.php index 744023d0..7756ebf7 100644 --- a/src/Schema/Criteria.php +++ b/src/Schema/Criteria.php @@ -15,29 +15,22 @@ final class Criteria { - /** @var int|string */ - private $index = 0; + private int|string $index = 0; /** @var array */ - private $key = []; + private array $key = []; - /** @var int */ - private $limit = \PHP_INT_MAX & 0xffffffff; + private int $limit = \PHP_INT_MAX & 0xFFFFFFFF; + private int $offset = 0; - /** @var int */ - private $offset = 0; - - /** @psalm-var null|IteratorTypes::* */ - private $iteratorType; + /** @psalm-var IteratorTypes::*|null */ + private ?int $iteratorType = null; private function __construct() { } - /** - * @param int|string $index - */ - public static function index($index) : self + public static function index(int|string $index) : self { $self = new self(); $self->index = $index; @@ -45,10 +38,7 @@ public static function index($index) : self return $self; } - /** - * @param int|string $index - */ - public function andIndex($index) : self + public function andIndex(int|string $index) : self { $new = clone $this; $new->index = $index; @@ -56,10 +46,7 @@ public function andIndex($index) : self return $new; } - /** - * @return int|string - */ - public function getIndex() + public function getIndex() : int|string { return $this->index; } diff --git a/src/Schema/Operations.php b/src/Schema/Operations.php index 1fe1233e..9fd18e73 100644 --- a/src/Schema/Operations.php +++ b/src/Schema/Operations.php @@ -16,28 +16,22 @@ final class Operations { /** @var non-empty-array */ - private $operations; + private array $operations; /** * @param non-empty-array $operation */ - private function __construct($operation) + private function __construct(array $operation) { $this->operations = [$operation]; } - /** - * @param int|string $field - */ - public static function add($field, int $value) : self + public static function add(int|string $field, int $value) : self { return new self(['+', $field, $value]); } - /** - * @param int|string $field - */ - public function andAdd($field, int $value) : self + public function andAdd(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['+', $field, $value]; @@ -45,18 +39,12 @@ public function andAdd($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function subtract($field, int $value) : self + public static function subtract(int|string $field, int $value) : self { return new self(['-', $field, $value]); } - /** - * @param int|string $field - */ - public function andSubtract($field, int $value) : self + public function andSubtract(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['-', $field, $value]; @@ -64,18 +52,12 @@ public function andSubtract($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function bitwiseAnd($field, int $value) : self + public static function bitwiseAnd(int|string $field, int $value) : self { return new self(['&', $field, $value]); } - /** - * @param int|string $field - */ - public function andBitwiseAnd($field, int $value) : self + public function andBitwiseAnd(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['&', $field, $value]; @@ -83,18 +65,12 @@ public function andBitwiseAnd($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function bitwiseOr($field, int $value) : self + public static function bitwiseOr(int|string $field, int $value) : self { return new self(['|', $field, $value]); } - /** - * @param int|string $field - */ - public function andBitwiseOr($field, int $value) : self + public function andBitwiseOr(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['|', $field, $value]; @@ -102,18 +78,12 @@ public function andBitwiseOr($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function bitwiseXor($field, int $value) : self + public static function bitwiseXor(int|string $field, int $value) : self { return new self(['^', $field, $value]); } - /** - * @param int|string $field - */ - public function andBitwiseXor($field, int $value) : self + public function andBitwiseXor(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['^', $field, $value]; @@ -121,18 +91,12 @@ public function andBitwiseXor($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function splice($field, int $offset, int $length, string $replacement) : self + public static function splice(int|string $field, int $offset, int $length, string $replacement) : self { return new self([':', $field, $offset, $length, $replacement]); } - /** - * @param int|string $field - */ - public function andSplice($field, int $offset, int $length, string $replacement) : self + public function andSplice(int|string $field, int $offset, int $length, string $replacement) : self { $new = clone $this; $new->operations[] = [':', $field, $offset, $length, $replacement]; @@ -140,18 +104,12 @@ public function andSplice($field, int $offset, int $length, string $replacement) return $new; } - /** - * @param int|string $field - */ - public static function insert($field, int $value) : self + public static function insert(int|string $field, int $value) : self { return new self(['!', $field, $value]); } - /** - * @param int|string $field - */ - public function andInsert($field, int $value) : self + public function andInsert(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['!', $field, $value]; @@ -159,18 +117,12 @@ public function andInsert($field, int $value) : self return $new; } - /** - * @param int|string $field - */ - public static function delete($field, int $value) : self + public static function delete(int|string $field, int $value) : self { return new self(['#', $field, $value]); } - /** - * @param int|string $field - */ - public function andDelete($field, int $value) : self + public function andDelete(int|string $field, int $value) : self { $new = clone $this; $new->operations[] = ['#', $field, $value]; @@ -178,20 +130,12 @@ public function andDelete($field, int $value) : self return $new; } - /** - * @param int|string $field - * @param mixed $value - */ - public static function set($field, $value) : self + public static function set(int|string $field, $value) : self { return new self(['=', $field, $value]); } - /** - * @param int|string $field - * @param mixed $value - */ - public function andSet($field, $value) : self + public function andSet(int|string $field, $value) : self { $new = clone $this; $new->operations[] = ['=', $field, $value]; diff --git a/src/Schema/Space.php b/src/Schema/Space.php index 3742eab3..7fc4ab20 100644 --- a/src/Schema/Space.php +++ b/src/Schema/Space.php @@ -30,11 +30,11 @@ final class Space public const VINDEX_ID = 289; public const VINDEX_NAME_INDEX = 2; - private $handler; - private $id; + private Handler $handler; + private int $id; /** @var array */ - private $indexes = []; + private array $indexes = []; public function __construct(Handler $handler, int $id) { @@ -89,9 +89,8 @@ public function replace(array $tuple) : array /** * @psalm-param non-empty-array $key - * @param int|string $index */ - public function update(array $key, Operations $operations, $index = 0) : array + public function update(array $key, Operations $operations, int|string $index = 0) : array { if (\is_string($index)) { $index = $this->getIndexIdByName($index); @@ -114,9 +113,8 @@ public function upsert(array $tuple, Operations $operations) : void /** * @psalm-param non-empty-array $key - * @param int|string $index */ - public function delete(array $key, $index = 0) : array + public function delete(array $key, int|string $index = 0) : array { if (\is_string($index)) { $index = $this->getIndexIdByName($index); diff --git a/src/SqlQueryResult.php b/src/SqlQueryResult.php index b517ecf1..609c3650 100644 --- a/src/SqlQueryResult.php +++ b/src/SqlQueryResult.php @@ -13,16 +13,20 @@ namespace Tarantool\Client; +/** + * @implements \ArrayAccess + * @implements \IteratorAggregate + */ final class SqlQueryResult implements \ArrayAccess, \Countable, \IteratorAggregate { /** @var array */ - private $data; + private array $data; /** @var array> */ - private $metadata; + private array $metadata; /** @var array */ - private $keys; + private array $keys; public function __construct(array $data, array $metadata) { @@ -56,6 +60,7 @@ public function getLast() : ?array return $this->data ? \array_combine($this->keys, \end($this->data)) : null; } + #[\Override] public function getIterator() : \Generator { foreach ($this->data as $item) { @@ -63,16 +68,19 @@ public function getIterator() : \Generator } } + #[\Override] public function count() : int { return \count($this->data); } + #[\Override] public function offsetExists($offset) : bool { return isset($this->data[$offset]); } + #[\Override] public function offsetGet($offset) : array { if (!isset($this->data[$offset])) { @@ -82,11 +90,13 @@ public function offsetGet($offset) : array return \array_combine($this->keys, $this->data[$offset]); } + #[\Override] public function offsetSet($offset, $value) : void { throw new \BadMethodCallException(self::class.' object cannot be modified'); } + #[\Override] public function offsetUnset($offset) : void { throw new \BadMethodCallException(self::class.' object cannot be modified'); diff --git a/src/SqlUpdateResult.php b/src/SqlUpdateResult.php index 27ff604a..34aa3761 100644 --- a/src/SqlUpdateResult.php +++ b/src/SqlUpdateResult.php @@ -15,13 +15,14 @@ final class SqlUpdateResult implements \Countable { - private $info; + private array $info; public function __construct(array $info) { $this->info = $info; } + #[\Override] public function count() : int { return $this->info[Keys::SQL_INFO_ROW_COUNT]; diff --git a/tests/GreetingDataProvider.php b/tests/GreetingDataProvider.php index 1a8af0e6..8637543d 100644 --- a/tests/GreetingDataProvider.php +++ b/tests/GreetingDataProvider.php @@ -76,8 +76,8 @@ private static function generateSalt() : string private static function generateUuid4() : string { $data = random_bytes(16); - $data[6] = \chr(\ord($data[6]) & 0x0f | 0x40); - $data[8] = \chr(\ord($data[8]) & 0x3f | 0x80); + $data[6] = \chr(\ord($data[6]) & 0x0F | 0x40); + $data[8] = \chr(\ord($data[8]) & 0x3F | 0x80); return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); } diff --git a/tests/Integration/BoxErrorTest.php b/tests/Integration/BoxErrorTest.php index 425197fa..c1dc948a 100644 --- a/tests/Integration/BoxErrorTest.php +++ b/tests/Integration/BoxErrorTest.php @@ -15,6 +15,7 @@ use Tarantool\Client\Error; use Tarantool\Client\Exception\RequestFailed; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; final class BoxErrorTest extends TestCase { @@ -27,9 +28,7 @@ public function testExceptionIsThrown() : void $this->client->evaluate('box.error({code = 42, reason = "Because I can"})'); } - /** - * @requires Tarantool >=2.4.1 - */ + #[RequiresTarantool('>=2.4.1')] public function testExceptionWithErrorIsThrown() : void { try { @@ -72,9 +71,7 @@ public function testExceptionWithErrorIsThrown() : void } } - /** - * @requires Tarantool >=2.4.1 - */ + #[RequiresTarantool('>=2.4.1')] public function testExceptionWithNestedErrorIsThrown() : void { try { diff --git a/tests/Integration/BoxNullTest.php b/tests/Integration/BoxNullTest.php index 66d93516..104bfd98 100644 --- a/tests/Integration/BoxNullTest.php +++ b/tests/Integration/BoxNullTest.php @@ -14,20 +14,19 @@ namespace Tarantool\Client\Tests\Integration; use Tarantool\Client\Schema\Criteria; +use Tarantool\PhpUnit\Attribute\Lua; final class BoxNullTest extends TestCase { - /** - * @lua format = {} - * @lua format[1] = {name = 'foo', type = 'unsigned'} - * @lua format[2] = {name = 'bar', type = 'map', is_nullable = true} - * @lua format[3] = {name = 'baz', type = 'unsigned', is_nullable = true} - * @lua space = create_space('box_null', {format = format}) - * @lua space:create_index('pk') - * @lua space:insert{1, {a = 1}} - * @lua space:insert{2, {b = 2}, box.NULL} - * @lua space:insert{3, box.NULL, 300} - */ + #[Lua('format = {}')] + #[Lua('format[1] = {name = "foo", type = "unsigned"}')] + #[Lua('format[2] = {name = "bar", type = "map", is_nullable = true}')] + #[Lua('format[3] = {name = "baz", type = "unsigned", is_nullable = true}')] + #[Lua('space = create_space("box_null", {format = format})')] + #[Lua('space:create_index("pk")')] + #[Lua('space:insert{1, {a = 1}}')] + #[Lua('space:insert{2, {b = 2}, box.NULL}')] + #[Lua('space:insert{3, box.NULL, 300}')] public function testNull() : void { $space = $this->client->getSpace('box_null'); diff --git a/tests/Integration/ClientBuilder.php b/tests/Integration/ClientBuilder.php index dcc7f9af..7f80253e 100755 --- a/tests/Integration/ClientBuilder.php +++ b/tests/Integration/ClientBuilder.php @@ -28,10 +28,10 @@ final class ClientBuilder private const DEFAULT_TCP_HOST = '127.0.0.1'; private const DEFAULT_TCP_PORT = 3301; - private $packerFactory; - private $uri; - private $options = []; - private $connectionOptions = []; + private ?\Closure $packerFactory = null; + private ?string $uri = null; + private array $options = []; + private array $connectionOptions = []; public function setPackerFactory(\Closure $factory) : self { @@ -56,7 +56,7 @@ public function setConnectionOptions(array $options) : self public function isTcpConnection() : bool { - return 0 === strpos($this->uri, 'tcp:'); + return str_starts_with($this->uri, 'tcp:'); } public function setHost(string $host) : self @@ -77,13 +77,13 @@ public function setPort(int $port) : self public function setUri(string $uri) : self { - if (0 === strpos($uri, '/')) { + if (str_starts_with($uri, '/')) { $uri = 'unix://'.$uri; - } elseif (0 === strpos($uri, 'unix/:')) { + } elseif (str_starts_with($uri, 'unix/:')) { $uri = 'unix://'.substr($uri, 6); } elseif (!preg_match('/[\D]/', $uri)) { $uri = 'tcp://127.0.0.1:'.$uri; - } elseif (0 !== strpos($uri, 'tcp://') && (0 !== strpos($uri, 'unix://'))) { + } elseif (!str_starts_with($uri, 'tcp://') && (!str_starts_with($uri, 'unix://'))) { $uri = 'tcp://'.$uri; } diff --git a/tests/Integration/ClientMiddlewareTest.php b/tests/Integration/ClientMiddlewareTest.php index 98c039d5..b020b97c 100644 --- a/tests/Integration/ClientMiddlewareTest.php +++ b/tests/Integration/ClientMiddlewareTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Integration; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Client; use Tarantool\Client\Exception\CommunicationFailed; use Tarantool\Client\Exception\RequestFailed; @@ -26,6 +27,7 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Space; use Tarantool\Client\Tests\SpyMiddleware; +use Tarantool\PhpUnit\Attribute\Lua; final class ClientMiddlewareTest extends TestCase { @@ -50,13 +52,10 @@ public function testSpaceInheritsMiddleware() : void self::assertSame([1, 1, 1], $middleware->getTraceLogArray()); } - /** - * @doesNotPerformAssertions - * - * @lua fiber = require('fiber') - * @lua function test() try_drop_user('foobar') fiber.sleep(.5) create_user('foobar', '') end - * @lua fiber.create(test) - */ + #[DoesNotPerformAssertions] + #[Lua('fiber = require("fiber")')] + #[Lua('function test() try_drop_user("foobar") fiber.sleep(.5) create_user("foobar", "") end')] + #[Lua('fiber.create(test)')] public function testAuthenticationRetrySucceeds() : void { $client = Client::fromOptions([ @@ -115,9 +114,7 @@ public function testNoRetriesOnUnexpectedResponse() : void $client->ping(); } - /** - * @doesNotPerformAssertions - */ + #[DoesNotPerformAssertions] public function testReconnectOnBrokenConnection() : void { $clientBuilder = ClientBuilder::createFromEnv(); @@ -146,7 +143,7 @@ public function testThrowOnBrokenConnection() : void private static function createBrokenConnectionMiddleware() : Middleware { - return new class() implements Middleware { + return new class implements Middleware { private $count = 0; public function process(Request $request, Handler $handler) : Response diff --git a/tests/Integration/ClientSpaceCachingTest.php b/tests/Integration/ClientSpaceCachingTest.php index c795a363..86a6aa46 100644 --- a/tests/Integration/ClientSpaceCachingTest.php +++ b/tests/Integration/ClientSpaceCachingTest.php @@ -14,10 +14,9 @@ namespace Tarantool\Client\Tests\Integration; use Tarantool\Client\Schema\Criteria; +use Tarantool\PhpUnit\Attribute\Lua; -/** - * @lua create_space('test_space_caching'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) - */ +#[Lua('create_space("test_space_caching"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] final class ClientSpaceCachingTest extends TestCase { public function testCacheSpace() : void diff --git a/tests/Integration/CompositeKeyTest.php b/tests/Integration/CompositeKeyTest.php index f29b694d..bb0ac522 100755 --- a/tests/Integration/CompositeKeyTest.php +++ b/tests/Integration/CompositeKeyTest.php @@ -15,13 +15,12 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; +use Tarantool\PhpUnit\Attribute\Lua; -/** - * @lua space = create_space('composite_key') - * @lua space:create_index('primary', {type = 'tree', unique = true, parts = {1, 'unsigned', 2, 'unsigned'}}) - * @lua space:insert{2016, 10, 1} - * @lua space:insert{2016, 11, 0} - */ +#[Lua('space = create_space("composite_key")')] +#[Lua('space:create_index("primary", {type = "tree", unique = true, parts = {1, "unsigned", 2, "unsigned"}})')] +#[Lua('space:insert{2016, 10, 1}')] +#[Lua('space:insert{2016, 11, 0}')] final class CompositeKeyTest extends TestCase { public function testSelectByCompositeKey() : void diff --git a/tests/Integration/Connection/ConnectionTest.php b/tests/Integration/Connection/ConnectionTest.php index af7c5f92..f10c8c59 100644 --- a/tests/Integration/Connection/ConnectionTest.php +++ b/tests/Integration/Connection/ConnectionTest.php @@ -13,6 +13,8 @@ namespace Tarantool\Client\Tests\Integration\Connection; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Exception\CommunicationFailed; use Tarantool\Client\Exception\ConnectionFailed; use Tarantool\Client\Exception\UnexpectedResponse; @@ -25,15 +27,13 @@ use Tarantool\Client\Tests\Integration\FakeServer\Handler\AtConnectionHandler; use Tarantool\Client\Tests\Integration\FakeServer\Handler\WriteHandler; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; final class ConnectionTest extends TestCase { - /** - * @dataProvider provideAutoConnectData - * @doesNotPerformAssertions - * - * @lua create_space('test_auto_connect'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) - */ + #[DataProvider('provideAutoConnectData')] + #[DoesNotPerformAssertions] + #[Lua('create_space("test_auto_connect"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] public function testAutoConnect(string $methodName, array $methodArgs, ?string $space = null) : void { $object = $space ? $this->client->getSpace($space) : $this->client; @@ -42,7 +42,7 @@ public function testAutoConnect(string $methodName, array $methodArgs, ?string $ $object->$methodName(...$methodArgs); } - public function provideAutoConnectData() : iterable + public static function provideAutoConnectData() : iterable { return [ ['ping', []], diff --git a/tests/Integration/Connection/ParseGreetingTest.php b/tests/Integration/Connection/ParseGreetingTest.php index 93e5c4be..9b1d8b2b 100644 --- a/tests/Integration/Connection/ParseGreetingTest.php +++ b/tests/Integration/Connection/ParseGreetingTest.php @@ -13,7 +13,9 @@ namespace Tarantool\Client\Tests\Integration\Connection; +use PHPUnit\Framework\Attributes\DataProviderExternal; use Tarantool\Client\Exception\CommunicationFailed; +use Tarantool\Client\Tests\GreetingDataProvider; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\FakeServer\FakeServerBuilder; use Tarantool\Client\Tests\Integration\FakeServer\Handler\WriteHandler; @@ -21,9 +23,7 @@ final class ParseGreetingTest extends TestCase { - /** - * @dataProvider \Tarantool\Client\Tests\GreetingDataProvider::provideGreetingsWithInvalidServerName - */ + #[DataProviderExternal(GreetingDataProvider::class, 'provideGreetingsWithInvalidServerName')] public function testParseGreetingWithInvalidServerName(string $greeting) : void { $clientBuilder = ClientBuilder::createForFakeServer(); @@ -52,9 +52,7 @@ public function testParseGreetingWithInvalidServerName(string $greeting) : void self::fail(); } - /** - * @dataProvider \Tarantool\Client\Tests\GreetingDataProvider::provideGreetingsWithInvalidSalt - */ + #[DataProviderExternal(GreetingDataProvider::class, 'provideGreetingsWithInvalidSalt')] public function testParseGreetingWithInvalidSalt(string $greeting) : void { $clientBuilder = ClientBuilder::createForFakeServer(); diff --git a/tests/Integration/ExamplesTest.php b/tests/Integration/ExamplesTest.php index 24363b87..d49aa4d3 100644 --- a/tests/Integration/ExamplesTest.php +++ b/tests/Integration/ExamplesTest.php @@ -13,11 +13,11 @@ namespace Tarantool\Client\Tests\Integration; +use PHPUnit\Framework\Attributes\DataProvider; + final class ExamplesTest extends TestCase { - /** - * @dataProvider provideExampleData - */ + #[DataProvider('provideExampleData')] public function testExample(string $filename) : void { $uri = ClientBuilder::createFromEnv()->getUri(); @@ -25,7 +25,7 @@ public function testExample(string $filename) : void exec("php $filename $uri", $output, $exitCode); $flattenOutput = implode("\n", $output); - if (0 === strpos($flattenOutput, 'Unfulfilled requirement:')) { + if (str_starts_with($flattenOutput, 'Unfulfilled requirement:')) { self::markTestSkipped($flattenOutput); } @@ -37,7 +37,7 @@ public function testExample(string $filename) : void } } - public function provideExampleData() : iterable + public static function provideExampleData() : iterable { $dir = dirname(__DIR__, 2).'/examples'; foreach (glob("$dir/{**/*,*}.php", GLOB_BRACE) as $filename) { diff --git a/tests/Integration/MessagePack/DateTimeExtension.php b/tests/Integration/MessagePack/DateTimeExtension.php index 42111451..6bc88cc4 100644 --- a/tests/Integration/MessagePack/DateTimeExtension.php +++ b/tests/Integration/MessagePack/DateTimeExtension.php @@ -19,7 +19,7 @@ class DateTimeExtension implements Extension { - private $type; + private readonly int $type; public function __construct(int $type) { diff --git a/tests/Integration/MessagePack/DecimalExtensionTest.php b/tests/Integration/MessagePack/DecimalExtensionTest.php index d678bf64..fa9bec7e 100755 --- a/tests/Integration/MessagePack/DecimalExtensionTest.php +++ b/tests/Integration/MessagePack/DecimalExtensionTest.php @@ -14,23 +14,26 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; use Decimal\Decimal; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; use Tarantool\Client\Client; use Tarantool\Client\Packer\Extension\DecimalExtension; use Tarantool\Client\Packer\PurePacker; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; - -/** - * @requires Tarantool >=2.3 - * @requires extension decimal - * - * @lua dec = require('decimal').new('18446744073709551615') - * @lua space = create_space('decimal_primary') - * @lua space:format({{name = 'id', type = 'decimal'}}) - * @lua space:create_index("primary", {parts = {1, 'decimal'}}) - * @lua space:insert({dec}) - */ +use Tarantool\Client\Tests\PackerDataProvider; +use Tarantool\PhpUnit\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; + +#[RequiresTarantool('>=2.3')] +#[RequiresPhpExtension('decimal')] +#[Lua('dec = require("decimal").new("18446744073709551615")')] +#[Lua('space = create_space("decimal_primary")')] +#[Lua('space:format({{name = "id", type = "decimal"}})')] +#[Lua('space:create_index("primary", {parts = {1, "decimal"}})')] +#[Lua('space:insert({dec})')] final class DecimalExtensionTest extends TestCase { public const DECIMAL_BIG_INT = '18446744073709551615'; @@ -40,46 +43,45 @@ public function testBinarySelectByDecimalKeySucceeds() : void { $client = self::createClientWithDecimalSupport(); - $decimal = new Decimal(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); + $decimal = Decimal::valueOf(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); $space = $client->getSpace('decimal_primary'); $result = $space->select(Criteria::key([$decimal])); self::assertTrue(isset($result[0][0])); - self::assertTrue($decimal->equals($result[0][0])); + self::assertEquals($decimal, $result[0][0]); } - /** - * @requires Tarantool >=2.10-stable - */ + #[RequiresTarantool('>=2.10-stable')] public function testSqlSelectByDecimalKeySucceeds() : void { $client = self::createClientWithDecimalSupport(); - $decimal = new Decimal(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); + $decimal = Decimal::valueOf(self::DECIMAL_BIG_INT, self::TARANTOOL_DECIMAL_PRECISION); $result = $client->executeQuery('SELECT * FROM "decimal_primary" WHERE "id" = ?', $decimal); self::assertFalse($result->isEmpty()); - self::assertTrue($decimal->equals($result->getFirst()['id'])); + self::assertEquals($decimal, $result->getFirst()['id']); } - /** - * @dataProvider provideDecimalStrings - */ + #[DataProvider('provideDecimalStrings')] public function testLuaPackingAndUnpacking(string $decimalString) : void { $client = self::createClientWithDecimalSupport(); [$decimal] = $client->evaluate('return require("decimal").new(...)', $decimalString); - self::assertTrue($decimal->equals($decimalString)); + self::assertSame( + self::normalizeDecimalString($decimalString), + $decimal->toFixed(self::TARANTOOL_DECIMAL_PRECISION) + ); [$isEqual] = $client->evaluate( sprintf("return require('decimal').new('%s') == ...", $decimalString), - new Decimal($decimalString, self::TARANTOOL_DECIMAL_PRECISION) + Decimal::valueOf($decimalString, self::TARANTOOL_DECIMAL_PRECISION) ); self::assertTrue($isEqual); } - public function provideDecimalStrings() : iterable + public static function provideDecimalStrings() : iterable { return [ ['0'], @@ -109,12 +111,10 @@ public function testBigIntegerUnpacksToDecimal() : void [$number] = $client->evaluate('return 18446744073709551615ULL'); self::assertInstanceOf(Decimal::class, $number); - self::assertTrue((new Decimal('18446744073709551615'))->equals($number)); + self::assertEquals(Decimal::valueOf('18446744073709551615'), $number); } - /** - * @dataProvider \Tarantool\Client\Tests\PackerDataProvider::providePurePackerWithDefaultSettings() - */ + #[DataProviderExternal(PackerDataProvider::class, 'providePurePackerWithDefaultSettings')] public function testPurePackerUnpacksBigIntToDecimal(PurePacker $packer) : void { $client = ClientBuilder::createFromEnv() @@ -124,7 +124,7 @@ public function testPurePackerUnpacksBigIntToDecimal(PurePacker $packer) : void [$number] = $client->evaluate(sprintf('return %sULL', self::DECIMAL_BIG_INT)); self::assertInstanceOf(Decimal::class, $number); - self::assertTrue((new Decimal(self::DECIMAL_BIG_INT))->equals($number)); + self::assertEquals(Decimal::valueOf(self::DECIMAL_BIG_INT), $number); } private static function createClientWithDecimalSupport() : Client @@ -135,4 +135,9 @@ private static function createClientWithDecimalSupport() : Client }) ->build(); } + + private static function normalizeDecimalString(string $decimal) : string + { + return Decimal::valueOf($decimal, self::TARANTOOL_DECIMAL_PRECISION)->toFixed(self::TARANTOOL_DECIMAL_PRECISION); + } } diff --git a/tests/Integration/MessagePack/ErrorExtensionTest.php b/tests/Integration/MessagePack/ErrorExtensionTest.php index 9bcb2598..12941b84 100755 --- a/tests/Integration/MessagePack/ErrorExtensionTest.php +++ b/tests/Integration/MessagePack/ErrorExtensionTest.php @@ -19,13 +19,14 @@ use Tarantool\Client\Packer\PurePacker; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; final class ErrorExtensionTest extends TestCase { /** - * @requires Tarantool >=2.4.1 <2.10 * @see https://github.com/tarantool/tarantool/issues/6428 */ + #[RequiresTarantool('>=2.4.1 <2.10')] public function testLuaPackingAndUnpacking() : void { $client = self::createClientWithExtendedErrorSupport(); diff --git a/tests/Integration/MessagePack/MessagePackTest.php b/tests/Integration/MessagePack/MessagePackTest.php index 4a6248cf..d1c36a4d 100755 --- a/tests/Integration/MessagePack/MessagePackTest.php +++ b/tests/Integration/MessagePack/MessagePackTest.php @@ -13,25 +13,25 @@ namespace Tarantool\Client\Tests\Integration\MessagePack; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; use Tarantool\Client\Packer\PurePacker; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; -use Tarantool\Client\Tests\PhpUnitCompat; +use Tarantool\Client\Tests\PackerDataProvider; +use Tarantool\PhpUnit\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\RequiresIfLua; final class MessagePackTest extends TestCase { - use PhpUnitCompat; - - /** - * @dataProvider providePackUnpackData - */ + #[DataProvider('providePackUnpackData')] public function testPackUnpack($arg) : void { self::assertSame([$arg], $this->client->evaluate('return ...', $arg)); } - public function providePackUnpackData() : iterable + public static function providePackUnpackData() : iterable { return [ [[]], @@ -68,10 +68,8 @@ public function testPackUnpackMultiDimensionalArray() : void self::assertEqualsCanonicalizing($array, $result); } - /** - * @lua space = create_space('custom_type') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('space = create_space("custom_type")')] + #[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testCustomType() : void { $client = ClientBuilder::createFromEnv() @@ -88,11 +86,8 @@ public function testCustomType() : void self::assertEquals($date, $space->select(Criteria::key([100]))[0][1]); } - /** - * @requires condition env.EXT_DISABLE_DECIMAL - * - * @dataProvider \Tarantool\Client\Tests\PackerDataProvider::providePurePackerWithDefaultSettings() - */ + #[RequiresIfLua('os.getenv("EXT_DISABLE_DECIMAL")')] + #[DataProviderExternal(PackerDataProvider::class, 'providePurePackerWithDefaultSettings')] public function testPurePackerUnpacksBigIntToString(PurePacker $packer) : void { $client = ClientBuilder::createFromEnv() diff --git a/tests/Integration/MessagePack/UuidExtensionTest.php b/tests/Integration/MessagePack/UuidExtensionTest.php index 6dba4fa3..cd8a68c7 100755 --- a/tests/Integration/MessagePack/UuidExtensionTest.php +++ b/tests/Integration/MessagePack/UuidExtensionTest.php @@ -20,16 +20,15 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; -/** - * @requires Tarantool >=2.4 - * - * @lua uuid = require('uuid').fromstr('64d22e4d-ac92-4a23-899a-e59f34af5479') - * @lua space = create_space('uuid_primary') - * @lua space:format({{name = 'id', type = 'uuid'}}) - * @lua space:create_index("primary", {parts = {1, 'uuid'}}) - * @lua space:insert({uuid}) - */ +#[RequiresTarantool('>=2.4')] +#[Lua('uuid = require("uuid").fromstr("64d22e4d-ac92-4a23-899a-e59f34af5479")')] +#[Lua('space = create_space("uuid_primary")')] +#[Lua('space:format({{name = "id", type = "uuid"}})')] +#[Lua('space:create_index("primary", {parts = {1, "uuid"}})')] +#[Lua('space:insert({uuid})')] final class UuidExtensionTest extends TestCase { private const UUID_RFC4122 = '64d22e4d-ac92-4a23-899a-e59f34af5479'; @@ -46,9 +45,7 @@ public function testBinarySelectByUuidKeySucceeds() : void self::assertTrue($uuid->equals($result[0][0])); } - /** - * @requires Tarantool >=2.10-stable - */ + #[RequiresTarantool('>=2.10-stable')] public function testSqlSelectByUuidKeySucceeds() : void { $client = self::createClientWithUuidSupport(); diff --git a/tests/Integration/PacketSyncTest.php b/tests/Integration/PacketSyncTest.php index 9454cfcd..6682e407 100755 --- a/tests/Integration/PacketSyncTest.php +++ b/tests/Integration/PacketSyncTest.php @@ -13,13 +13,12 @@ namespace Tarantool\Client\Tests\Integration; +use PHPUnit\Framework\Attributes\DataProvider; use Tarantool\Client\Request\PingRequest; final class PacketSyncTest extends TestCase { - /** - * @dataProvider provideValidSync - */ + #[DataProvider('provideValidSync')] public function testSameSync(int $sync) : void { $handler = $this->client->getHandler(); @@ -35,7 +34,7 @@ public function testSameSync(int $sync) : void self::assertSame($sync, $response->getSync()); } - public function provideValidSync() : iterable + public static function provideValidSync() : iterable { return [ [0], diff --git a/tests/Integration/Requests/AuthenticateTest.php b/tests/Integration/Requests/AuthenticateTest.php index 9a175159..67b0d072 100644 --- a/tests/Integration/Requests/AuthenticateTest.php +++ b/tests/Integration/Requests/AuthenticateTest.php @@ -13,20 +13,20 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; final class AuthenticateTest extends TestCase { - /** - * @doesNotPerformAssertions - * @dataProvider provideValidCredentials - * - * @lua create_user('user_foo', 'foo') - * @lua create_user('user_empty', '') - * @lua create_user('user_big', '123456789012345678901234567890123456789012345678901234567890') - */ + #[DoesNotPerformAssertions] + #[DataProvider('provideValidCredentials')] + #[Lua('create_user("user_foo", "foo")')] + #[Lua('create_user("user_empty", "")')] + #[Lua('create_user("user_big", "123456789012345678901234567890123456789012345678901234567890")')] public function testAuthenticateWithValidCredentials(string $username, string $password) : void { $client = ClientBuilder::createFromEnv()->setOptions([ @@ -37,7 +37,7 @@ public function testAuthenticateWithValidCredentials(string $username, string $p $client->ping(); } - public function provideValidCredentials() : iterable + public static function provideValidCredentials() : iterable { return [ ['guest', ''], @@ -47,9 +47,7 @@ public function provideValidCredentials() : iterable ]; } - /** - * @dataProvider provideInvalidCredentials - */ + #[DataProvider('provideInvalidCredentials')] public function testAuthenticateWithInvalidCredentials(string $errorMessagePattern, $username, $password) : void { $client = ClientBuilder::createFromEnv()->setOptions([ @@ -65,7 +63,7 @@ public function testAuthenticateWithInvalidCredentials(string $errorMessagePatte } } - public function provideInvalidCredentials() : iterable + public static function provideInvalidCredentials() : iterable { return [ ["/(User 'non_existing_user' is not found|User not found or supplied credentials are invalid)/", 'non_existing_user', 'password'], @@ -73,10 +71,8 @@ public function provideInvalidCredentials() : iterable ]; } - /** - * @lua create_user('user_foo', 'foo') - * @lua create_space('test_auth_reconnect'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) - */ + #[Lua('create_user("user_foo", "foo")')] + #[Lua('create_space("test_auth_reconnect"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] public function testUseCredentialsAfterReconnect() : void { $client = ClientBuilder::createFromEnv()->setOptions([ diff --git a/tests/Integration/Requests/DeleteTest.php b/tests/Integration/Requests/DeleteTest.php index 117add69..680b3df9 100755 --- a/tests/Integration/Requests/DeleteTest.php +++ b/tests/Integration/Requests/DeleteTest.php @@ -15,15 +15,14 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\TestCase; - -/** - * @lua space = create_space('request_delete') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', parts = {2, 'str'}}) - * @lua space:insert{3, 'delete_me_1'} - * @lua space:insert{4, 'delete_me_2'} - * @lua space:insert{5, 'delete_me_3'} - */ +use Tarantool\PhpUnit\Attribute\Lua; + +#[Lua('space = create_space("request_delete")')] +#[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] +#[Lua('space:create_index("secondary", {type = "tree", parts = {2, "str"}})')] +#[Lua('space:insert{3, "delete_me_1"}')] +#[Lua('space:insert{4, "delete_me_2"}')] +#[Lua('space:insert{5, "delete_me_3"}')] final class DeleteTest extends TestCase { public function testDelete() : void diff --git a/tests/Integration/Requests/ExecuteTest.php b/tests/Integration/Requests/ExecuteTest.php index 7c863127..a4fa2493 100644 --- a/tests/Integration/Requests/ExecuteTest.php +++ b/tests/Integration/Requests/ExecuteTest.php @@ -16,20 +16,17 @@ use Tarantool\Client\Keys; use Tarantool\Client\Tests\Integration\ClientBuilder; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; +use Tarantool\PhpUnit\Attribute\Sql; -/** - * @requires Tarantool >=2 - * - * @sql DROP TABLE IF EXISTS exec_query - * @sql CREATE TABLE exec_query (id INTEGER PRIMARY KEY, name VARCHAR(50)) - * @sql INSERT INTO exec_query VALUES (1, 'A'), (2, 'B') - */ +#[RequiresTarantool('>=2')] +#[Sql('DROP TABLE IF EXISTS exec_query')] +#[Sql('CREATE TABLE exec_query (id INTEGER PRIMARY KEY, name VARCHAR(50))')] +#[Sql('INSERT INTO exec_query VALUES (1, \'A\'), (2, \'B\')')] final class ExecuteTest extends TestCase { - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50))')] public function testExecuteInsertsRows() : void { $response = $this->client->execute( @@ -52,10 +49,8 @@ public function testExecuteFetchesAllRows() : void self::assertSame([[1, 'A'], [2, 'B']], $response->getBodyField(Keys::DATA)); } - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50))')] public function testExecuteUpdateInsertsRows() : void { $result = $this->client->executeUpdate( @@ -67,10 +62,8 @@ public function testExecuteUpdateInsertsRows() : void self::assertSame(2, $result->count()); } - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(50))')] public function testExecuteUpdateInsertsRowsWithAutoIncrementedIds() : void { $result = $this->client->executeUpdate("INSERT INTO exec_update VALUES (100, 'A'), (null, 'B'), (120, 'C'), (null, 'D')"); @@ -79,11 +72,9 @@ public function testExecuteUpdateInsertsRowsWithAutoIncrementedIds() : void self::assertSame(4, $result->count()); } - /** - * @sql DROP TABLE IF EXISTS exec_update - * @sql CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50)) - * @sql INSERT INTO exec_update VALUES (1, 'A'), (2, 'B') - */ + #[Sql('DROP TABLE IF EXISTS exec_update')] + #[Sql('CREATE TABLE exec_update (id INTEGER PRIMARY KEY, name VARCHAR(50))')] + #[Sql('INSERT INTO exec_update VALUES (1, \'A\'), (2, \'B\')')] public function testExecuteUpdateUpdatesRow() : void { $result = $this->client->executeUpdate('UPDATE exec_update SET name = ? WHERE id = ?', 'BB', 2); @@ -151,11 +142,9 @@ public function testExecuteQueryBindsMixedParametersAndSubstitutesPositionalOnes self::assertSame(1, $result->count()); } - /** - * @sql DROP TABLE IF EXISTS %target_method% - * @sql CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY, NAME VARCHAR(50)) - * @sql INSERT INTO %target_method% VALUES (1, 'A'), (2, 'B') - */ + #[Sql('DROP TABLE IF EXISTS %target_method%')] + #[Sql('CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY, NAME VARCHAR(50))')] + #[Sql('INSERT INTO %target_method% VALUES (1, \'A\'), (2, \'B\')')] public function testSqlQueryResultHoldsMetadata() : void { $client = ClientBuilder::createFromEnv()->build(); @@ -172,12 +161,9 @@ public function testSqlQueryResultHoldsMetadata() : void ]], $response->getMetadata()); } - /** - * @requires Tarantool >=2.6 - * - * @sql DROP TABLE IF EXISTS %target_method% - * @sql CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME VARCHAR(50) COLLATE "unicode_ci") - */ + #[RequiresTarantool('>=2.6')] + #[Sql('DROP TABLE IF EXISTS %target_method%')] + #[Sql('CREATE TABLE %target_method% (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME VARCHAR(50) COLLATE "unicode_ci")')] public function testSqlQueryResultHoldsExtendedMetadata() : void { $client = ClientBuilder::createFromEnv()->build(); diff --git a/tests/Integration/Requests/InsertTest.php b/tests/Integration/Requests/InsertTest.php index 9a0cc0f5..88c2d729 100755 --- a/tests/Integration/Requests/InsertTest.php +++ b/tests/Integration/Requests/InsertTest.php @@ -13,17 +13,16 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DataProvider; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; final class InsertTest extends TestCase { - /** - * @dataProvider provideInsertData - * - * @lua create_space('request_insert_str'):create_index('primary', {type = 'hash', parts = {1, 'str'}}) - * @lua create_space('request_insert_num'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[DataProvider('provideInsertData')] + #[Lua('create_space("request_insert_str"):create_index("primary", {type = "hash", parts = {1, "str"}})')] + #[Lua('create_space("request_insert_num"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testInsert(string $spaceName, array $values) : void { $space = $this->client->getSpace($spaceName); @@ -32,7 +31,7 @@ public function testInsert(string $spaceName, array $values) : void self::assertSame([$values], $result); } - public function provideInsertData() : iterable + public static function provideInsertData() : iterable { return [ ['request_insert_str', ['']], @@ -45,12 +44,9 @@ public function provideInsertData() : iterable ]; } - /** - * @dataProvider provideInsertDataWithMismatchedTypes - * - * @lua create_space('request_insert_str'):create_index('primary', {type = 'hash', parts = {1, 'str'}}) - * @lua create_space('request_insert_num'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[DataProvider('provideInsertDataWithMismatchedTypes')] + #[Lua('create_space("request_insert_str"):create_index("primary", {type = "hash", parts = {1, "str"}})')] + #[Lua('create_space("request_insert_num"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testInsertTypeMismatchedValues(string $spaceName, array $values) : void { $space = $this->client->getSpace($spaceName); @@ -61,7 +57,7 @@ public function testInsertTypeMismatchedValues(string $spaceName, array $values) $space->insert($values); } - public function provideInsertDataWithMismatchedTypes() : iterable + public static function provideInsertDataWithMismatchedTypes() : iterable { return [ ['request_insert_str', [null]], @@ -74,11 +70,9 @@ public function provideInsertDataWithMismatchedTypes() : iterable ]; } - /** - * @lua space = create_space('request_insert_dup_key') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - * @lua space:insert{1, 'foobar'} - */ + #[Lua('space = create_space("request_insert_dup_key")')] + #[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] + #[Lua('space:insert{1, "foobar"}')] public function testInsertDuplicateKey() : void { $space = $this->client->getSpace('request_insert_dup_key'); @@ -89,10 +83,8 @@ public function testInsertDuplicateKey() : void $space->insert([1, 'bazqux']); } - /** - * @lua space = create_space('request_insert_empty_tuple') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('space = create_space("request_insert_empty_tuple")')] + #[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testInsertEmptyTuple() : void { $space = $this->client->getSpace('request_insert_empty_tuple'); diff --git a/tests/Integration/Requests/PingTest.php b/tests/Integration/Requests/PingTest.php index 5d8b7bf8..bbb70ead 100644 --- a/tests/Integration/Requests/PingTest.php +++ b/tests/Integration/Requests/PingTest.php @@ -13,13 +13,12 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use Tarantool\Client\Tests\Integration\TestCase; final class PingTest extends TestCase { - /** - * @doesNotPerformAssertions - */ + #[DoesNotPerformAssertions] public function testPing() : void { $this->client->ping(); diff --git a/tests/Integration/Requests/PrepareTest.php b/tests/Integration/Requests/PrepareTest.php index 9c1d8c5f..04684ab9 100644 --- a/tests/Integration/Requests/PrepareTest.php +++ b/tests/Integration/Requests/PrepareTest.php @@ -16,10 +16,10 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\PreparedStatement; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\RequiresTarantool; +use Tarantool\PhpUnit\Attribute\Sql; -/** - * @requires Tarantool >=2.3.2 - */ +#[RequiresTarantool('>=2.3.2')] final class PrepareTest extends TestCase { public function testPreparePreparesSqlStatement() : void @@ -62,10 +62,8 @@ public function testExecuteQueryReturnsResult() : void } } - /** - * @sql DROP TABLE IF EXISTS prepare_execute - * @sql CREATE TABLE prepare_execute (id INTEGER PRIMARY KEY, name VARCHAR(50)) - */ + #[Sql('DROP TABLE IF EXISTS prepare_execute')] + #[Sql('CREATE TABLE prepare_execute (id INTEGER PRIMARY KEY, name VARCHAR(50))')] public function testExecuteUpdateUpdatesRows() : void { $stmt = $this->client->prepare('INSERT INTO prepare_execute VALUES(:id, :name)'); diff --git a/tests/Integration/Requests/ReplaceTest.php b/tests/Integration/Requests/ReplaceTest.php index b652efb3..e5232d9e 100755 --- a/tests/Integration/Requests/ReplaceTest.php +++ b/tests/Integration/Requests/ReplaceTest.php @@ -16,13 +16,12 @@ use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; -/** - * @lua space = create_space('request_replace') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', parts = {2, 'str'}}) - * @lua space:insert{2, 'replace_me'} - */ +#[Lua('space = create_space("request_replace")')] +#[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] +#[Lua('space:create_index("secondary", {type = "tree", parts = {2, "str"}})')] +#[Lua('space:insert{2, "replace_me"}')] final class ReplaceTest extends TestCase { public function testReplace() : void diff --git a/tests/Integration/Requests/SelectTest.php b/tests/Integration/Requests/SelectTest.php index c5ecfd36..d254379c 100755 --- a/tests/Integration/Requests/SelectTest.php +++ b/tests/Integration/Requests/SelectTest.php @@ -13,20 +13,19 @@ namespace Tarantool\Client\Tests\Integration\Requests; +use PHPUnit\Framework\Attributes\DataProvider; use Tarantool\Client\Exception\RequestFailed; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; final class SelectTest extends TestCase { - /** - * @dataProvider provideSelectData - * - * @lua space = create_space('request_select') - * @lua space:create_index('primary', {type = 'tree', unique = true, parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', unique = false, parts = {2, 'unsigned', 3, 'str'}}) - * @lua for i = 1, 100 do space:replace{i, i * 2 % 5, 'tuple_' .. i} end - */ + #[DataProvider('provideSelectData')] + #[Lua('space = create_space("request_select")')] + #[Lua('space:create_index("primary", {type = "tree", unique = true, parts = {1, "unsigned"}})')] + #[Lua('space:create_index("secondary", {type = "tree", unique = false, parts = {2, "unsigned", 3, "str"}})')] + #[Lua('for i = 1, 100 do space:replace{i, i * 2 % 5, "tuple_" .. i} end')] public function testSelect(int $expectedCount, Criteria $criteria) : void { $space = $this->client->getSpace('request_select'); @@ -35,7 +34,7 @@ public function testSelect(int $expectedCount, Criteria $criteria) : void self::assertCount($expectedCount, $result); } - public function provideSelectData() : iterable + public static function provideSelectData() : iterable { return [ [100, Criteria::key([])], @@ -55,9 +54,7 @@ public function provideSelectData() : iterable ]; } - /** - * @lua create_space('request_select'):create_index('primary', {type = 'tree', parts = {1, 'unsigned'}}) - */ + #[Lua('create_space("request_select"):create_index("primary", {type = "tree", parts = {1, "unsigned"}})')] public function testSelectEmpty() : void { $space = $this->client->getSpace('request_select'); @@ -65,9 +62,7 @@ public function testSelectEmpty() : void self::assertEmpty($space->select(Criteria::key([]))); } - /** - * @lua create_space('request_select'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('create_space("request_select"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testSelectWithNonExistingIndexName() : void { $space = $this->client->getSpace('request_select'); @@ -78,9 +73,7 @@ public function testSelectWithNonExistingIndexName() : void $space->select(Criteria::key([1])->andIndex('non_existing_index')); } - /** - * @lua create_space('request_select'):create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ + #[Lua('create_space("request_select"):create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] public function testSelectWithNonExistingIndexId() : void { $space = $this->client->getSpace('request_select'); diff --git a/tests/Integration/Requests/UpdateTest.php b/tests/Integration/Requests/UpdateTest.php index 550ad862..417eb3b6 100755 --- a/tests/Integration/Requests/UpdateTest.php +++ b/tests/Integration/Requests/UpdateTest.php @@ -17,28 +17,25 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; -/** - * @lua space = create_space('request_update') - * @lua space:create_index('primary', {type = 'tree', unique = true, parts = {1, 'unsigned'}}) - * @lua space:create_index('secondary', {type = 'tree', unique = false, parts = {2, 'unsigned', 3, 'str'}}) - * @lua space:replace{1, 2, 'tuple_1'} - * @lua space:replace{2, 4, 'tuple_2'} - */ +#[Lua('space = create_space("request_update")')] +#[Lua('space:create_index("primary", {type = "tree", unique = true, parts = {1, "unsigned"}})')] +#[Lua('space:create_index("secondary", {type = "tree", unique = false, parts = {2, "unsigned", 3, "str"}})')] +#[Lua('space:replace{1, 2, "tuple_1"}')] +#[Lua('space:replace{2, 4, "tuple_2"}')] final class UpdateTest extends TestCase { - /** - * @dataProvider provideUpdateData - */ - public function testUpdate(Operations $operations, array $expectedResult) : void + public function testUpdate() : void { $space = $this->client->getSpace('request_update'); - $result = $space->update([1], $operations); - self::assertSame($expectedResult, $result); + foreach (self::provideUpdateData() as [$operations, $expectedResult]) { + self::assertSame($expectedResult, $space->update([1], $operations)); + } } - public function provideUpdateData() : iterable + public static function provideUpdateData() : iterable { return [ [ diff --git a/tests/Integration/Requests/UpsertTest.php b/tests/Integration/Requests/UpsertTest.php index 7374d334..7c1c3bf0 100755 --- a/tests/Integration/Requests/UpsertTest.php +++ b/tests/Integration/Requests/UpsertTest.php @@ -17,11 +17,10 @@ use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\Operations; use Tarantool\Client\Tests\Integration\TestCase; +use Tarantool\PhpUnit\Attribute\Lua; -/** - * @lua space = create_space('request_upsert') - * @lua space:create_index('primary', {type = 'hash', parts = {1, 'unsigned'}}) - */ +#[Lua('space = create_space("request_upsert")')] +#[Lua('space:create_index("primary", {type = "hash", parts = {1, "unsigned"}})')] final class UpsertTest extends TestCase { public function testUpsert() : void diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php index 15a97e39..fa5a063c 100644 --- a/tests/Integration/TestCase.php +++ b/tests/Integration/TestCase.php @@ -13,26 +13,21 @@ namespace Tarantool\Client\Tests\Integration; +use Composer\Semver\Semver; +use PHPUnit\Framework\Attributes\Before; use Tarantool\Client\Client; use Tarantool\Client\Connection\Connection; use Tarantool\Client\Connection\StreamConnection; use Tarantool\Client\Exception\CommunicationFailed; use Tarantool\Client\Handler\Handler; use Tarantool\Client\Request\Request; -use Tarantool\Client\Tests\PhpUnitCompat; -use Tarantool\PhpUnit\Annotation\Requirement\TarantoolVersionRequirement; use Tarantool\PhpUnit\TestCase as BaseTestCase; abstract class TestCase extends BaseTestCase { - use PhpUnitCompat; + protected ?Client $client = null; - /** @var Client|null */ - protected $client; - - /** - * @before - */ + #[Before] protected function getClient() : Client { return $this->client @@ -41,7 +36,19 @@ protected function getClient() : Client final protected function tarantoolVersionSatisfies(string $constraints) : bool { - return null === (new TarantoolVersionRequirement($this->getClient()))->check($constraints); + $version = $this->getClient()->call('box.info')[0]['version']; + if (!\is_string($version)) { + throw new \UnexpectedValueException('Tarantool version must be a string'); + } + + // Normalize 2.2.1-3-g878e2a42c to 2.2.1.3. + $version = (string) preg_replace('/-(\d+)-[^-]+$/', '.$1', $version); + + // Treat "entrypoint" versions as "dev", + // so 2.11.0-entrypoint.8 becomes 2.11.0-dev+entrypoint.8. + $version = (string) preg_replace('/(\d)-entrypoint/', '$1-dev+entrypoint', $version); + + return Semver::satisfies($version, $constraints); } final protected static function triggerUnexpectedResponse(Handler $handler, Request $initialRequest, int $sync = 0) : Connection @@ -62,7 +69,6 @@ final protected static function triggerUnexpectedResponse(Handler $handler, Requ final public static function getRawStream(StreamConnection $connection) { $prop = (new \ReflectionObject($connection))->getProperty('stream'); - $prop->setAccessible(true); return $prop->getValue($connection); } diff --git a/tests/PhpUnitCompat.php b/tests/PhpUnitCompat.php deleted file mode 100644 index 38c63620..00000000 --- a/tests/PhpUnitCompat.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -declare(strict_types=1); - -namespace Tarantool\Client\Tests; - -/** - * Compatibility layer for legacy PHPUnit versions. - */ -trait PhpUnitCompat -{ - /** - * TestCase::expectExceptionMessageRegExp() is deprecated since PHPUnit 8.4. - */ - public function expectExceptionMessageMatches(string $regularExpression) : void - { - is_callable(parent::class.'::expectExceptionMessageMatches') - ? parent::expectExceptionMessageMatches(...func_get_args()) - : parent::expectExceptionMessageRegExp(...func_get_args()); - } - - /** - * Assert::assertEquals()'s $delta, $maxDepth, $canonicalize parameters are deprecated since PHPUnit 8.0. - */ - public static function assertEqualsCanonicalizing($expected, $actual, string $message = '') : void - { - is_callable(parent::class.'::assertEqualsCanonicalizing') - ? parent::assertEqualsCanonicalizing($expected, $actual, $message) - : parent::assertEquals($expected, $actual, $message, 0.0, 10, true); - } - - /** - * Assert::assertRegExp() is deprecated since PHPUnit 9.1. - */ - public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = '') : void - { - is_callable(parent::class.'::assertMatchesRegularExpression') - ? parent::assertMatchesRegularExpression(...func_get_args()) - : parent::assertRegExp(...func_get_args()); - } -} diff --git a/tests/SpyMiddleware.php b/tests/SpyMiddleware.php index eb05062a..6fdc73ce 100644 --- a/tests/SpyMiddleware.php +++ b/tests/SpyMiddleware.php @@ -20,16 +20,16 @@ final class SpyMiddleware implements Middleware { - private $traceLog; - private $getTraceValue; + private \ArrayObject $traceLog; + private \Closure $getTraceValue; private function __construct(\Closure $getTraceValue, ?\ArrayObject $traceLog = null) { $this->getTraceValue = $getTraceValue; - $this->traceLog = $traceLog ?: new \ArrayObject(); + $this->traceLog = $traceLog ?? new \ArrayObject(); } - public static function fromTraceId($traceId, ?\ArrayObject $traceLog = null) : self + public static function fromTraceId(mixed $traceId, ?\ArrayObject $traceLog = null) : self { return new self(static function () use ($traceId) { return $traceId; diff --git a/tests/Unit/ClientFactoryTest.php b/tests/Unit/ClientFactoryTest.php index d437489d..c7a16b8a 100644 --- a/tests/Unit/ClientFactoryTest.php +++ b/tests/Unit/ClientFactoryTest.php @@ -13,16 +13,15 @@ namespace Tarantool\Client\Tests\Unit; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; use Tarantool\Client\Client; use Tarantool\Client\Packer\Packer; use Tarantool\Client\Packer\PurePacker; -use Tarantool\Client\Tests\PhpUnitCompat; final class ClientFactoryTest extends TestCase { - use PhpUnitCompat; - public function testFromDefaultsCreatesClientWithPurePacker() : void { $client = Client::fromDefaults(); @@ -60,20 +59,16 @@ public function testFromDsnCreatesClientWithCustomPacker() : void self::assertSame($packer, $client->getHandler()->getPacker()); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientArrayOptionsOfValidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfValidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testFromOptionsAcceptsOptionOfValidType(string $optionName, $optionValue, array $extraOptions = []) : void { Client::fromOptions([$optionName => $optionValue] + $extraOptions); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientArrayOptionsOfInvalidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfInvalidTypes - */ + #[DataProviderExternal(OptionsProvider::class, 'provideClientArrayOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] public function testFromOptionsRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType, array $extraOptions = []) : void { $this->expectException(\TypeError::class); @@ -82,18 +77,14 @@ public function testFromOptionsRejectsOptionOfInvalidType(string $optionName, $o Client::fromOptions([$optionName => $optionValue] + $extraOptions); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientDsnOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testFromDsnAcceptsOptionOfValidType(string $query) : void { Client::fromDsn("tcp://tnt/?$query"); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideClientDsnOptionsOfInvalidTypes - */ + #[DataProviderExternal(OptionsProvider::class, 'provideClientDsnOptionsOfInvalidTypes')] public function testFromDsnRejectsOptionOfInvalidType(string $query, string $optionName, string $expectedType) : void { $this->expectException(\TypeError::class); diff --git a/tests/Unit/Connection/GreetingTest.php b/tests/Unit/Connection/GreetingTest.php index ff3b37b7..ca815126 100644 --- a/tests/Unit/Connection/GreetingTest.php +++ b/tests/Unit/Connection/GreetingTest.php @@ -13,23 +13,21 @@ namespace Tarantool\Client\Tests\Unit\Connection; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\TestCase; use Tarantool\Client\Connection\Greeting; use Tarantool\Client\Tests\GreetingDataProvider; final class GreetingTest extends TestCase { - /** - * @dataProvider \Tarantool\Client\Tests\GreetingDataProvider::provideValidGreetings - */ + #[DataProviderExternal(GreetingDataProvider::class, 'provideValidGreetings')] public function testGetSalt(string $greeting, string $salt) : void { self::assertSame($salt, Greeting::parse($greeting)->getSalt()); } - /** - * @dataProvider provideServerVersionData - */ + #[DataProvider('provideServerVersionData')] public function testGetServerVersion(string $greeting, string $expectedVersion) : void { $greeting = Greeting::parse($greeting); @@ -37,7 +35,7 @@ public function testGetServerVersion(string $greeting, string $expectedVersion) self::assertSame($expectedVersion, $greeting->getServerVersion()); } - public function provideServerVersionData() : iterable + public static function provideServerVersionData() : iterable { return [ [GreetingDataProvider::generateGreeting('foobar'), ''], diff --git a/tests/Unit/Connection/StreamConnectionTest.php b/tests/Unit/Connection/StreamConnectionTest.php index 715e9c19..4f20ca0d 100644 --- a/tests/Unit/Connection/StreamConnectionTest.php +++ b/tests/Unit/Connection/StreamConnectionTest.php @@ -13,37 +13,31 @@ namespace Tarantool\Client\Tests\Unit\Connection; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; use PHPUnit\Framework\TestCase; use Tarantool\Client\Connection\StreamConnection; -use Tarantool\Client\Tests\PhpUnitCompat; +use Tarantool\Client\Tests\Unit\OptionsProvider; final class StreamConnectionTest extends TestCase { - use PhpUnitCompat; - - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfValidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testCreateTcpAcceptsOptionOfValidType(string $optionName, $optionValue) : void { StreamConnection::createTcp(StreamConnection::DEFAULT_TCP_URI, [$optionName => $optionValue]); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfValidTypes - * @doesNotPerformAssertions - */ + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfValidTypes')] + #[DoesNotPerformAssertions] public function testCreateUdsAcceptsOptionOfValidType(string $optionName, $optionValue) : void { StreamConnection::createUds('unix:///socket.sock', [$optionName => $optionValue]); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfInvalidTypes - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideTcpExtraConnectionArrayOptionsOfInvalidTypes - */ + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] + #[DataProviderExternal(OptionsProvider::class, 'provideTcpExtraConnectionArrayOptionsOfInvalidTypes')] public function testCreateTcpRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType) : void { $this->expectException(\TypeError::class); @@ -52,9 +46,7 @@ public function testCreateTcpRejectsOptionOfInvalidType(string $optionName, $opt StreamConnection::createTcp(StreamConnection::DEFAULT_TCP_URI, [$optionName => $optionValue]); } - /** - * @dataProvider \Tarantool\Client\Tests\Unit\OptionsProvider::provideConnectionArrayOptionsOfInvalidTypes - */ + #[DataProviderExternal(OptionsProvider::class, 'provideConnectionArrayOptionsOfInvalidTypes')] public function testCreateUdsRejectsOptionOfInvalidType(string $optionName, $optionValue, string $expectedType) : void { $this->expectException(\TypeError::class); diff --git a/tests/Unit/DsnTest.php b/tests/Unit/DsnTest.php index 3d2fd9f2..6bbb6c06 100644 --- a/tests/Unit/DsnTest.php +++ b/tests/Unit/DsnTest.php @@ -13,14 +13,13 @@ namespace Tarantool\Client\Tests\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Tarantool\Client\Dsn; final class DsnTest extends TestCase { - /** - * @dataProvider provideValidTcpDsns - */ + #[DataProvider('provideValidTcpDsns')] public function testParseValidTcpDsn(string $dsn, array $expectedResult) : void { $dsn = Dsn::parse($dsn); @@ -36,7 +35,7 @@ public function testParseValidTcpDsn(string $dsn, array $expectedResult) : void } } - public function provideValidTcpDsns() : iterable + public static function provideValidTcpDsns() : iterable { return [ ['tcp://127.0.0.1', ['uri' => 'tcp://127.0.0.1:3301', 'host' => '127.0.0.1', 'port' => 3301]], @@ -53,9 +52,7 @@ public function provideValidTcpDsns() : iterable ]; } - /** - * @dataProvider provideValidUdsDsns - */ + #[DataProvider('provideValidUdsDsns')] public function testParseValidUdsDsn(string $dsn, array $expected) : void { $dsn = Dsn::parse($dsn); @@ -71,7 +68,7 @@ public function testParseValidUdsDsn(string $dsn, array $expected) : void } } - public function provideValidUdsDsns() : iterable + public static function provideValidUdsDsns() : iterable { return [ ['unix:///path/to/socket.sock', ['uri' => 'unix:///path/to/socket.sock', 'path' => '/path/to/socket.sock']], @@ -83,9 +80,7 @@ public function provideValidUdsDsns() : iterable ]; } - /** - * @dataProvider provideInvalidDsns - */ + #[DataProvider('provideInvalidDsns')] public function testParseInvalidDsn(string $nonDsn) : void { $this->expectException(\InvalidArgumentException::class); @@ -93,7 +88,7 @@ public function testParseInvalidDsn(string $nonDsn) : void Dsn::parse($nonDsn); } - public function provideInvalidDsns() : iterable + public static function provideInvalidDsns() : iterable { return [ [''], @@ -116,16 +111,14 @@ public function provideInvalidDsns() : iterable ]; } - /** - * @dataProvider provideStringOptions - */ + #[DataProvider('provideStringOptions')] public function testGetString(string $dsn, string $option, ?string $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getString($option)); } - public function provideStringOptions() : iterable + public static function provideStringOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo', 'bar'], @@ -151,16 +144,14 @@ public function testGetStringDefault() : void self::assertSame('qux', $dsn->getString('baz', 'qux')); } - /** - * @dataProvider provideIntOptions - */ + #[DataProvider('provideIntOptions')] public function testGetInt(string $dsn, string $option, $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getInt($option)); } - public function provideIntOptions() : iterable + public static function provideIntOptions() : iterable { return [ ['tcp://host/?foo=42', 'foo', 42], @@ -178,9 +169,7 @@ public function testGetIntDefault() : void self::assertSame(42, $dsn->getInt('baz', 42)); } - /** - * @dataProvider provideNonIntOptions - */ + #[DataProvider('provideNonIntOptions')] public function testGetNonInt(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -190,7 +179,7 @@ public function testGetNonInt(string $dsn, string $option) : void $dsn->getInt($option); } - public function provideNonIntOptions() : iterable + public static function provideNonIntOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo'], @@ -204,16 +193,14 @@ public function provideNonIntOptions() : iterable ]; } - /** - * @dataProvider provideFloatOptions - */ + #[DataProvider('provideFloatOptions')] public function testGetFloat(string $dsn, string $option, $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getFloat($option)); } - public function provideFloatOptions() : iterable + public static function provideFloatOptions() : iterable { return [ ['tcp://host/?foo=42', 'foo', 42.0], @@ -233,9 +220,7 @@ public function testGetFloatDefault() : void self::assertSame(42.3, $dsn->getFloat('baz', 42.3)); } - /** - * @dataProvider provideNonFloatOptions - */ + #[DataProvider('provideNonFloatOptions')] public function testGetNonFloat(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -245,7 +230,7 @@ public function testGetNonFloat(string $dsn, string $option) : void $dsn->getFloat($option); } - public function provideNonFloatOptions() : iterable + public static function provideNonFloatOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo'], @@ -257,16 +242,14 @@ public function provideNonFloatOptions() : iterable ]; } - /** - * @dataProvider provideBoolOptions - */ + #[DataProvider('provideBoolOptions')] public function testGetBool(string $dsn, string $option, ?bool $expectedValue) : void { $dsn = Dsn::parse($dsn); self::assertSame($expectedValue, $dsn->getBool($option)); } - public function provideBoolOptions() : iterable + public static function provideBoolOptions() : iterable { return [ ['tcp://host/?foo=true', 'foo', true], @@ -294,9 +277,7 @@ public function testGetBoolDefault() : void self::assertTrue($dsn->getBool('baz', true)); } - /** - * @dataProvider provideNonBoolOptions - */ + #[DataProvider('provideNonBoolOptions')] public function testGetNonBool(string $dsn, string $option) : void { $dsn = Dsn::parse($dsn); @@ -306,7 +287,7 @@ public function testGetNonBool(string $dsn, string $option) : void $dsn->getBool($option); } - public function provideNonBoolOptions() : iterable + public static function provideNonBoolOptions() : iterable { return [ ['tcp://host/?foo=bar', 'foo'], diff --git a/tests/Unit/Handler/MiddlewareHandlerTest.php b/tests/Unit/Handler/MiddlewareHandlerTest.php index 693ac4f1..e65ed421 100644 --- a/tests/Unit/Handler/MiddlewareHandlerTest.php +++ b/tests/Unit/Handler/MiddlewareHandlerTest.php @@ -24,15 +24,8 @@ final class MiddlewareHandlerTest extends TestCase { use TestDoubleClient; - /** - * @var Request - */ - private $request; - - /** - * @var Handler - */ - private $handler; + private Request $request; + private Handler $handler; protected function setUp() : void { diff --git a/tests/Unit/Middleware/CustomErrorMiddlewareTest.php b/tests/Unit/Middleware/CustomErrorMiddlewareTest.php index ba84d17a..b875f5b5 100644 --- a/tests/Unit/Middleware/CustomErrorMiddlewareTest.php +++ b/tests/Unit/Middleware/CustomErrorMiddlewareTest.php @@ -26,10 +26,7 @@ final class CustomErrorMiddlewareTest extends TestCase { - /** - * @var Handler|MockObject - */ - private $handler; + private Handler&MockObject $handler; protected function setUp() : void { diff --git a/tests/Unit/Middleware/FirewallMiddlewareTest.php b/tests/Unit/Middleware/FirewallMiddlewareTest.php index 757f3c97..886a9bc9 100644 --- a/tests/Unit/Middleware/FirewallMiddlewareTest.php +++ b/tests/Unit/Middleware/FirewallMiddlewareTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Unit\Middleware; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Tarantool\Client\Exception\RequestDenied; @@ -30,10 +31,7 @@ final class FirewallMiddlewareTest extends TestCase { - /** - * @var Handler|MockObject - */ - private $handler; + private Handler&MockObject $handler; protected function setUp() : void { @@ -78,6 +76,18 @@ public function testAndAllow() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndAllowMultipleRequestTypes() : void + { + $this->handler->expects(self::exactly(2))->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::deny(RequestTypes::CALL) + ->andAllow(RequestTypes::PING, RequestTypes::SELECT); + + $middleware->process(new PingRequest(), $this->handler); + $middleware->process(new SelectRequest(1, 1, [], 0, 1, IteratorTypes::ALL), $this->handler); + } + public function testAndAllowForbids() : void { $middleware = FirewallMiddleware::deny(RequestTypes::CALL)->andAllow(RequestTypes::PING); @@ -98,6 +108,21 @@ public function testAndAllowOnly() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndAllowOnlyMultipleRequestTypes() : void + { + $this->handler->expects(self::exactly(2))->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::allow(RequestTypes::CALL) + ->andAllowOnly(RequestTypes::PING, RequestTypes::SELECT); + + $middleware->process(new PingRequest(), $this->handler); + $middleware->process(new SelectRequest(1, 1, [], 0, 1, IteratorTypes::ALL), $this->handler); + + $this->expectException(RequestDenied::class); + $middleware->process(new CallRequest('foo'), $this->handler); + } + public function testAndAllowOnlyForbids() : void { $middleware = FirewallMiddleware::allow(RequestTypes::CALL)->andAllowOnly(RequestTypes::PING); @@ -138,6 +163,20 @@ public function testAndDeny() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndDenyMultipleRequestTypes() : void + { + $this->handler->expects(self::once())->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::deny(RequestTypes::PING) + ->andDeny(RequestTypes::CALL, RequestTypes::EVALUATE); + + $middleware->process(new SelectRequest(1, 1, [], 0, 1, IteratorTypes::ALL), $this->handler); + + $this->expectException(RequestDenied::class); + $middleware->process(new EvaluateRequest('return 42'), $this->handler); + } + public function testAndDenyForbids() : void { $middleware = FirewallMiddleware::allow(RequestTypes::PING)->andDeny(RequestTypes::CALL); @@ -158,6 +197,20 @@ public function testAndDenyOnly() : void $middleware->process(new PingRequest(), $this->handler); } + public function testAndDenyOnlyMultipleRequestTypes() : void + { + $this->handler->expects(self::once())->method('handle') + ->willReturn(TestDoubleFactory::createEmptyResponse()); + + $middleware = FirewallMiddleware::deny(RequestTypes::PING) + ->andDenyOnly(RequestTypes::CALL, RequestTypes::EVALUATE); + + $middleware->process(new PingRequest(), $this->handler); + + $this->expectException(RequestDenied::class); + $middleware->process(new EvaluateRequest('return 42'), $this->handler); + } + public function testAndDenyOnlyForbids() : void { $middleware = FirewallMiddleware::deny(RequestTypes::PING)->andDenyOnly(RequestTypes::CALL); @@ -168,9 +221,7 @@ public function testAndDenyOnlyForbids() : void $middleware->process(new CallRequest('foo'), $this->handler); } - /** - * @dataProvider provideBlacklistPriorityData - */ + #[DataProvider('provideBlacklistPriorityData')] public function testDenyHasPriority(Middleware $middleware) : void { $this->expectException(RequestDenied::class); @@ -179,7 +230,7 @@ public function testDenyHasPriority(Middleware $middleware) : void $middleware->process(new PingRequest(), $this->handler); } - public function provideBlacklistPriorityData() : iterable + public static function provideBlacklistPriorityData() : iterable { yield [FirewallMiddleware::allow(RequestTypes::PING)->andDeny(RequestTypes::PING)]; yield [FirewallMiddleware::deny(RequestTypes::PING)->andAllow(RequestTypes::PING)]; diff --git a/tests/Unit/Middleware/LoggingMiddlewareTest.php b/tests/Unit/Middleware/LoggingMiddlewareTest.php new file mode 100644 index 00000000..64aa7e54 --- /dev/null +++ b/tests/Unit/Middleware/LoggingMiddlewareTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Tarantool\Client\Tests\Unit\Middleware; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Tarantool\Client\Handler\Handler; +use Tarantool\Client\Middleware\LoggingMiddleware; +use Tarantool\Client\Request\PingRequest; +use Tarantool\PhpUnit\Client\TestDoubleFactory; + +final class LoggingMiddlewareTest extends TestCase +{ + public function testLogsRequestAndResponseWhenHandlingSucceeds() : void + { + $request = new PingRequest(); + $response = TestDoubleFactory::createEmptyResponse(); + $handler = $this->createMock(Handler::class); + $handler->expects(self::once())->method('handle')->with($request)->willReturn($response); + + $messages = []; + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::exactly(2))->method('debug') + ->willReturnCallback(static function (string $message, array $context) use (&$messages) : void { + $messages[] = [$message, $context]; + }); + $logger->expects(self::never())->method('error'); + + $result = (new LoggingMiddleware($logger))->process($request, $handler); + + self::assertSame($response, $result); + self::assertSame('Starting handling request "ping"', $messages[0][0]); + self::assertSame(['request' => $request], $messages[0][1]); + self::assertSame('Finished handling request "ping"', $messages[1][0]); + self::assertSame($request, $messages[1][1]['request']); + self::assertSame($response, $messages[1][1]['response']); + self::assertIsNumeric($messages[1][1]['duration_ms']); + } + + public function testLogsAndRethrowsHandlerException() : void + { + $request = new PingRequest(); + $exception = new \RuntimeException('handler failed'); + $handler = $this->createMock(Handler::class); + $handler->expects(self::once())->method('handle')->with($request)->willThrowException($exception); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects(self::once())->method('debug') + ->with('Starting handling request "ping"', ['request' => $request]); + $logger->expects(self::once())->method('error') + ->with('Request "ping" failed', self::callback(static function (array $context) use ($request, $exception) : bool { + return $request === ($context['request'] ?? null) + && $exception === ($context['exception'] ?? null) + && isset($context['duration_ms']) + && is_numeric($context['duration_ms']); + })); + + try { + (new LoggingMiddleware($logger))->process($request, $handler); + self::fail('Expected the handler exception to be rethrown'); + } catch (\RuntimeException $actual) { + self::assertSame($exception, $actual); + } + } +} diff --git a/tests/Unit/Middleware/RetryMiddlewareTest.php b/tests/Unit/Middleware/RetryMiddlewareTest.php index b3f3721c..95d8e361 100644 --- a/tests/Unit/Middleware/RetryMiddlewareTest.php +++ b/tests/Unit/Middleware/RetryMiddlewareTest.php @@ -24,15 +24,8 @@ final class RetryMiddlewareTest extends TestCase { - /** - * @var Request|MockObject - */ - private $request; - - /** - * @var Handler|MockObject - */ - private $handler; + private Request&MockObject $request; + private Handler&MockObject $handler; protected function setUp() : void { @@ -79,6 +72,7 @@ public function testInfiniteRetriesBreak() : void $totalRetries = 0; $middleware = RetryMiddleware::custom(static function (int $retries) use (&$totalRetries) : int { $totalRetries = $retries; + // always returning a value other than null // leads to an infinite retry loop return 0; diff --git a/tests/Unit/OptionsProvider.php b/tests/Unit/OptionsProvider.php index 39b31389..c41f5bfb 100644 --- a/tests/Unit/OptionsProvider.php +++ b/tests/Unit/OptionsProvider.php @@ -38,7 +38,7 @@ public static function provideConnectionArrayOptionsOfInvalidTypes() : array ]; } - public function provideTcpExtraConnectionArrayOptionsOfValidTypes() : array + public static function provideTcpExtraConnectionArrayOptionsOfValidTypes() : array { return [ ['tcp_nodelay', false], diff --git a/tests/Unit/Packer/PurePackerTest.php b/tests/Unit/Packer/PurePackerTest.php index bffb9c1a..ff2f94c3 100644 --- a/tests/Unit/Packer/PurePackerTest.php +++ b/tests/Unit/Packer/PurePackerTest.php @@ -14,6 +14,7 @@ namespace Tarantool\Client\Tests\Unit\Packer; use MessagePack\Exception\UnpackingFailedException; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Tarantool\Client\Keys; use Tarantool\Client\Packer\Packer; @@ -22,17 +23,14 @@ final class PurePackerTest extends TestCase { - /** @var Packer */ - private $packer; + private Packer $packer; protected function setUp() : void { $this->packer = new PurePacker(); } - /** - * @dataProvider provideBadUnpackData - */ + #[DataProvider('provideBadUnpackData')] public function testThrowExceptionOnBadUnpackData(string $data) : void { $this->expectException(UnpackingFailedException::class); @@ -40,7 +38,7 @@ public function testThrowExceptionOnBadUnpackData(string $data) : void $this->packer->unpack($data)->tryGetBodyField(Keys::DATA); } - public function provideBadUnpackData() : iterable + public static function provideBadUnpackData() : iterable { return [ [''], diff --git a/tests/Unit/Schema/CriteriaTest.php b/tests/Unit/Schema/CriteriaTest.php index 83070055..fe9e2efe 100644 --- a/tests/Unit/Schema/CriteriaTest.php +++ b/tests/Unit/Schema/CriteriaTest.php @@ -13,6 +13,7 @@ namespace Tarantool\Client\Tests\Unit\Schema; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Tarantool\Client\Schema\Criteria; use Tarantool\Client\Schema\IteratorTypes; @@ -79,9 +80,7 @@ public function testAndIterator() : void self::assertSame(IteratorTypes::GE, Criteria::iterator(IteratorTypes::ALL)->andIterator(IteratorTypes::GE)->getIterator()); } - /** - * @dataProvider provideIteratorTypes - */ + #[DataProvider('provideIteratorTypes')] public function testIteratorTypeByName(string $name) : void { $method = str_replace('_', '', $name).'iterator'; @@ -90,9 +89,7 @@ public function testIteratorTypeByName(string $name) : void self::assertSame(constant(IteratorTypes::class.'::'.$name), $criteria->getIterator()); } - /** - * @dataProvider provideIteratorTypes - */ + #[DataProvider('provideIteratorTypes')] public function testAndIteratorTypeByName(string $name) : void { // Make sure we don't assign the same iterator twice @@ -103,7 +100,7 @@ public function testAndIteratorTypeByName(string $name) : void self::assertSame(constant(IteratorTypes::class.'::'.$name), $criteria->$andMethod()->getIterator()); } - public function provideIteratorTypes() : iterable + public static function provideIteratorTypes() : iterable { return [ ['EQ'],