diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index 5f6670f..4b2bf5e 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -1,31 +1,31 @@ -name: test-integration -on: [ push ] +name: Run QA tests (static analysis, lint and unit tests) +on: [pull_request] + jobs: - build: + run-qa-tests: runs-on: ubuntu-latest - continue-on-error: ${{ matrix.experimental }} + timeout-minutes: 15 strategy: matrix: - php-versions: [ '8.2' ] - experimental: [ false ] - include: - - php-versions: '8.3' - experimental: true - timeout-minutes: 30 - name: PHP ${{ matrix.php-versions }} on Ubuntu latest. Experimental == ${{ matrix.experimental }} + php: ['8.2', '8.4'] + steps: - - name: Install PHP + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - - name: Checkout - uses: actions/checkout@master - - name: Install dependencies + php-version: ${{ matrix.php }} + tools: composer:v2 + coverage: none + + - name: Composer install run: composer install - continue-on-error: ${{ matrix.experimental }} - - name: Run CI tests - run: composer check - continue-on-error: ${{ matrix.experimental }} + + - name: Run QA tests + run: composer check-ci + - name: Output log files on failure if: failure() run: tail -2000 /var/log/syslog diff --git a/.gitignore b/.gitignore index 08f3304..94a8168 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ composer.lock .idea .phpunit.result.cache +/var \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f867086..6ce8eee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 7.0.0 +Allow for Symfony 7 packages and drop Symfony 5 support. + +Changes include: +- Updated dev tooling & QA + # 6.0.0 Allow for Symfony 6 packages and drop PHP7 support diff --git a/README.md b/README.md index 19ee100..2cafee1 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,64 @@ # Step-up Bundle [![Build Status](https://travis-ci.org/OpenConext/Stepup-bundle.svg)](https://travis-ci.org/OpenConext/Stepup-bundle) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/OpenConext/Stepup-bundle/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/OpenConext/Stepup-bundle/?branch=develop) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/5b8b8d8b-e917-4954-818b-782d9e181c75/mini.png)](https://insight.sensiolabs.com/projects/5b8b8d8b-e917-4954-818b-782d9e181c75) -A Symfony 2 and 3 bundle that holds shared code and framework integration for all Step-up applications. See [Stepup-Deploy](https://github.com/OpenConext/Stepup-Deploy) for an overview of Stepup. +A Symfony bundle that holds shared code and framework integration for all Step-up applications. See [Stepup-Deploy](https://github.com/OpenConext/Stepup-Deploy) for an overview of Stepup. + +## Requirements + +- PHP 8.2 or higher +- Symfony 6.3+ or 7.0+ ## Installation - * Add the package to your Composer file (For Symfony 2 support, please use a version constraint "~3.5") + * Add the package to your Composer file ```sh composer require surfnet/stepup-bundle ``` - * Add the bundle to your kernel in `app/AppKernel.php` + * The bundle should be automatically registered in `config/bundles.php` (for Symfony Flex projects). If not, add it manually: ```php - public function registerBundles() - { + // config/bundles.php + return [ // ... - $bundles[] = new Surfnet\StepupBundle\SurfnetStepupBundle; - } + Surfnet\StepupBundle\SurfnetStepupBundle::class => ['all' => true], + ]; ``` * Copy and adjust the error templates to your application folder - * `src/Resources/views/Exception/error.html.twig` → `app/Resources/SurfnetStepupBundle/views/Exception/error.html.twig` - * `src/Resources/views/Exception/error404.html.twig` → `app/Resources/SurfnetStepupBundle/views/Exception/error404.html.twig` + * `src/Resources/views/Exception/error.html.twig` → `templates/bundles/SurfnetStepupBundle/Exception/error.html.twig` + * `src/Resources/views/Exception/error404.html.twig` → `templates/bundles/SurfnetStepupBundle/Exception/error404.html.twig` ### Install resources +For modern Symfony applications, you can use AssetMapper (recommended for Symfony 7.0+) or Webpack Encore to manage assets. + +#### Using AssetMapper (Symfony 7.0+) + +```bash +# Install AssetMapper if not already installed +composer require symfony/asset-mapper symfony/asset symfony/twig-pack +``` + +Copy the bundle's public assets to your project: +```bash +php bin/console assets:install --symlink +``` + +Then reference the assets in your templates: ```twig -{% stylesheets filter='less' -'@SurfnetStepupBundle/Resources/public/less/stepup.less' -%} - -{% endstylesheets %} -{% javascripts -'@SurfnetStepupBundle/Resources/public/js/stepup.js' -%} - -{% endjavascripts %} + + +``` + +#### Using Webpack Encore + +Import the bundle's assets in your JavaScript/CSS entry point: +```javascript +// assets/app.js +import '../vendor/surfnet/stepup-bundle/src/Resources/public/js/stepup.js'; + +// assets/app.css +@import '../vendor/surfnet/stepup-bundle/src/Resources/public/less/stepup.less'; ``` ## Using the locale switcher @@ -44,38 +67,34 @@ The locale switcher is a form that can be rendered with the help of a Twig funct ```twig {% if app.user %} - {% set locale_switcher = stepup_locale_switcher('handler_route', ['return-url' => app.request.uri]) %} + {% set locale_switcher = stepup_locale_switcher('handler_route', {'return-url': app.request.uri}) %} {{ form_start(locale_switcher, { attr: { class: 'form-inline' }}) }} {{ form_widget(locale_switcher.locale) }} {{ form_widget(locale_switcher.switch) }} {{ form_end(locale_switcher) }} {% endif %} -{% stylesheets filter='less' -'@SurfnetStepupBundle/Resources/public/less/style.less' -%} - -{% endstylesheets %} -{% javascripts -'@SurfnetStepupBundle/Resources/public/js/index.js' -%} - -{% endjavascripts %} +``` + +Include the required assets: +```twig + + ``` ## Release strategy ### CHANGELOG -The changelog for the bundle is kept in the `./CHANGELOG` file. A history of the releases can be found in this file. -Previous RMT release notes are kept in this file for history purposes. Please use markdown to style the changelog. +The changelog for the bundle is kept in the `CHANGELOG.md` file. A history of the releases can be found in this file. +Previous release notes are kept in this file for history purposes. Please use markdown to style the changelog. Please update the changelog with any notable changes that are introduced in an upcoming release. If you are not yet certain what the next release number will be, give the release title a generic value like `Upcoming release`. Make sure before merging the changes to the release branch to update the release title in the changelog. **Example CHANGELOG entry** -``` +```markdown # 2.5.23 -Brief explenation on the major changes of this release +Brief explanation of the major changes of this release ## New features * Title of PR of the new feature #30 @@ -86,7 +105,6 @@ Brief explenation on the major changes of this release ## Improvements * Title of PR of the improvement #29 - ``` When releasing a hotfix on a release branch, please update the changelog on the release branch and after releasing the diff --git a/ci/qa/docheader b/ci/qa/docheader new file mode 100755 index 0000000..55ed85d --- /dev/null +++ b/ci/qa/docheader @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +cd $(dirname $0)/../../ + +./vendor/bin/docheader --no-ansi --docheader=ci/qa/docheader.template check src/ + diff --git a/ci/qa/docheader.template b/ci/qa/docheader.template new file mode 100644 index 0000000..90cda86 --- /dev/null +++ b/ci/qa/docheader.template @@ -0,0 +1,16 @@ +/** + * Copyright %regexp:\d{4}% SURFnet %regexp:(B.V.|bv)% + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/ci/qa/phpcpd b/ci/qa/phpcpd index e9fec13..ab2aefe 100755 --- a/ci/qa/phpcpd +++ b/ci/qa/phpcpd @@ -4,4 +4,4 @@ cd $(dirname $0)/../../ # https://github.com/sebastianbergmann/phpcpd ./vendor/bin/phpcpd \ - ./src $1 + ./src $1 \ No newline at end of file diff --git a/ci/qa/phplint.yaml b/ci/qa/phplint.yaml index f07ad6c..1c15a21 100644 --- a/ci/qa/phplint.yaml +++ b/ci/qa/phplint.yaml @@ -1,6 +1,6 @@ path: [./src, ./tests] jobs: 10 -cache: /var/qa/phplint.cache +cache-dir: var/qa/phplint.cache extensions: - php exclude: diff --git a/ci/qa/phpstan-baseline.neon b/ci/qa/phpstan-baseline.neon index 4a95d34..2af98d8 100644 --- a/ci/qa/phpstan-baseline.neon +++ b/ci/qa/phpstan-baseline.neon @@ -1,301 +1,421 @@ parameters: ignoreErrors: - - message: "#^Method Surfnet\\\\StepupBundle\\\\Controller\\\\ExceptionController\\:\\:getPageTitleAndDescription\\(\\) return type has no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Controller\\ExceptionController\:\:getPageTitleAndDescription\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Controller/ExceptionController.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\DateTime\\\\RegistrationExpirationHelper\\:\\:__construct\\(\\) has parameter \\$expirationWindow with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\DateTime\\RegistrationExpirationHelper\:\:__construct\(\) has parameter \$expirationWindow with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/DateTime/RegistrationExpirationHelper.php - - message: "#^Parameter \\#1 \\$interval of method DateTime\\:\\:add\\(\\) expects DateInterval, DateInterval\\|null given\\.$#" + message: '#^Parameter \#1 \$interval of method DateTime\:\:add\(\) expects DateInterval, DateInterval\|null given\.$#' + identifier: argument.type count: 1 path: ../../src/DateTime/RegistrationExpirationHelper.php - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" + message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable count: 1 path: ../../src/DependencyInjection/Compiler/AttachRequestIdInjectorToGuzzleClientsPass.php - - message: "#^Parameter \\#1 \\$id of method Symfony\\\\Component\\\\DependencyInjection\\\\ContainerBuilder\\:\\:getDefinition\\(\\) expects string, mixed given\\.$#" + message: '#^Parameter \#1 \$id of method Symfony\\Component\\DependencyInjection\\ContainerBuilder\:\:getDefinition\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../src/DependencyInjection/Compiler/AttachRequestIdInjectorToGuzzleClientsPass.php - - message: "#^Cannot call method push\\(\\) on mixed\\.$#" + message: '#^Cannot call method push\(\) on mixed\.$#' + identifier: method.nonObject count: 1 path: ../../src/DependencyInjection/Configurator/GuzzleClientRequestIdConfigurator.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\DependencyInjection\\\\SurfnetStepupExtension\\:\\:configureGatewayApiClient\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\DependencyInjection\\SurfnetStepupExtension\:\:configureGatewayApiClient\(\) has parameter \$config with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/DependencyInjection/SurfnetStepupExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\DependencyInjection\\\\SurfnetStepupExtension\\:\\:configureLocaleCookieSettings\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\DependencyInjection\\SurfnetStepupExtension\:\:configureLocaleCookieSettings\(\) has parameter \$config with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/DependencyInjection/SurfnetStepupExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\DependencyInjection\\\\SurfnetStepupExtension\\:\\:configureLocaleSelectionWidget\\(\\) has parameter \\$loaDefinitions with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\DependencyInjection\\SurfnetStepupExtension\:\:configureLocaleSelectionWidget\(\) has parameter \$loaDefinitions with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/DependencyInjection/SurfnetStepupExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\DependencyInjection\\\\SurfnetStepupExtension\\:\\:configureSecondFactorTypeService\\(\\) has parameter \\$loaDefinitions with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\DependencyInjection\\SurfnetStepupExtension\:\:configureSecondFactorTypeService\(\) has parameter \$loaDefinitions with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/DependencyInjection/SurfnetStepupExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\DependencyInjection\\\\SurfnetStepupExtension\\:\\:configureSmsSecondFactorServices\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\DependencyInjection\\SurfnetStepupExtension\:\:configureSmsSecondFactorServices\(\) has parameter \$config with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/DependencyInjection/SurfnetStepupExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\DependencyInjection\\\\SurfnetStepupExtension\\:\\:defineLoas\\(\\) has parameter \\$loaDefinitions with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\DependencyInjection\\SurfnetStepupExtension\:\:defineLoas\(\) has parameter \$loaDefinitions with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/DependencyInjection/SurfnetStepupExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\EventListener\\\\BadJsonRequestExceptionListener\\:\\:onKernelException\\(\\) has no return type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\EventListener\\BadJsonRequestExceptionListener\:\:onKernelException\(\) has no return type specified\.$#' + identifier: missingType.return count: 1 path: ../../src/EventListener/BadJsonRequestExceptionListener.php - - message: "#^Parameter \\#1 \\$requestId of method Surfnet\\\\StepupBundle\\\\Request\\\\RequestId\\:\\:set\\(\\) expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$requestId of method Surfnet\\StepupBundle\\Request\\RequestId\:\:set\(\) expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: ../../src/EventListener/RequestIdRequestResponseListener.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Exception\\\\Art\\:\\:stripVariableArgumentsFromMessage\\(\\) has parameter \\$message with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Exception\\Art\:\:stripVariableArgumentsFromMessage\(\) has parameter \$message with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Exception/Art.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Exception\\\\BadJsonRequestException\\:\\:mapViolationsToErrorStrings\\(\\) return type has no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Exception\\BadJsonRequestException\:\:mapViolationsToErrorStrings\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Exception/BadJsonRequestException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Exception\\\\InvalidArgumentException\\:\\:invalidType\\(\\) has parameter \\$expectedType with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Exception\\InvalidArgumentException\:\:invalidType\(\) has parameter \$expectedType with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Exception/InvalidArgumentException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Exception\\\\InvalidArgumentException\\:\\:invalidType\\(\\) has parameter \\$parameter with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Exception\\InvalidArgumentException\:\:invalidType\(\) has parameter \$parameter with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Exception/InvalidArgumentException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Exception\\\\InvalidArgumentException\\:\\:invalidType\\(\\) has parameter \\$value with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Exception\\InvalidArgumentException\:\:invalidType\(\) has parameter \$value with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Exception/InvalidArgumentException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Exception\\\\JsonException\\:\\:withMessage\\(\\) has parameter \\$errorMessage with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Exception\\JsonException\:\:withMessage\(\) has parameter \$errorMessage with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Exception/JsonException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Form\\\\ChoiceList\\\\LocaleChoiceList\\:\\:create\\(\\) return type has no value type specified in iterable type array\\.$#" + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: ../../src/Form/ChoiceList/LocaleChoiceList.php - - message: "#^Parameter \\#1 \\$name of method Symfony\\\\Component\\\\Routing\\\\Generator\\\\UrlGeneratorInterface\\:\\:generate\\(\\) expects string, mixed given\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Form\\ChoiceList\\LocaleChoiceList\:\:create\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: ../../src/Form/ChoiceList/LocaleChoiceList.php + + - + message: '#^Parameter \#1 \$name of method Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface\:\:generate\(\) expects string, mixed given\.$#' + identifier: argument.type count: 1 path: ../../src/Form/Type/SwitchLocaleType.php - - message: "#^Parameter \\#2 \\$parameters of method Symfony\\\\Component\\\\Routing\\\\Generator\\\\UrlGeneratorInterface\\:\\:generate\\(\\) expects array, mixed given\\.$#" + message: '#^Parameter \#2 \$parameters of method Symfony\\Component\\Routing\\Generator\\UrlGeneratorInterface\:\:generate\(\) expects array, mixed given\.$#' + identifier: argument.type count: 1 path: ../../src/Form/Type/SwitchLocaleType.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Guzzle\\\\Middleware\\\\GuzzleRequestIdInjector\\:\\:__invoke\\(\\) has no return type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Guzzle\\Middleware\\GuzzleRequestIdInjector\:\:__invoke\(\) has no return type specified\.$#' + identifier: missingType.return count: 1 path: ../../src/Guzzle/Middleware/GuzzleRequestIdInjector.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Http\\\\CookieHelper\\:\\:createCookieWithValue\\(\\) has parameter \\$value with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Http\\CookieHelper\:\:createCookieWithValue\(\) has parameter \$value with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Http/CookieHelper.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Http\\\\JsonHelper\\:\\:decode\\(\\) has no return type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Http\\JsonHelper\:\:decode\(\) has no return type specified\.$#' + identifier: missingType.return count: 1 path: ../../src/Http/JsonHelper.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Http\\\\JsonHelper\\:\\:decode\\(\\) has parameter \\$json with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Http\\JsonHelper\:\:decode\(\) has parameter \$json with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Http/JsonHelper.php - - message: "#^Property Surfnet\\\\StepupBundle\\\\Http\\\\JsonHelper\\:\\:\\$jsonErrors type has no value type specified in iterable type array\\.$#" + message: '#^Property Surfnet\\StepupBundle\\Http\\JsonHelper\:\:\$jsonErrors type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Http/JsonHelper.php - - message: "#^Property Surfnet\\\\StepupBundle\\\\Monolog\\\\Handler\\\\PrimaryLogHandler\\:\\:\\$streamHandler is never written, only read\\.$#" + message: '#^Property Surfnet\\StepupBundle\\Monolog\\Handler\\PrimaryLogHandler\:\:\$streamHandler is never written, only read\.$#' + identifier: property.onlyRead count: 1 path: ../../src/Monolog/Handler/PrimaryLogHandler.php - - message: "#^PHPDoc tag @return with type array is incompatible with native type Monolog\\\\LogRecord\\.$#" + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../src/Monolog/Processor/ApplicationNameProcessor.php + + - + message: '#^PHPDoc tag @return with type array is incompatible with native type Monolog\\LogRecord\.$#' + identifier: return.phpDocType count: 1 path: ../../src/Monolog/Processor/ServerNameProcessor.php - - message: "#^Cannot access offset string on mixed\\.$#" + message: '#^Cannot access offset string on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible count: 1 path: ../../src/Request/JsonConvertibleResolver.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Request\\\\JsonConvertibleResolver\\:\\:resolve\\(\\) return type has no value type specified in iterable type iterable\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Request\\JsonConvertibleResolver\:\:resolve\(\) return type has no value type specified in iterable type iterable\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Request/JsonConvertibleResolver.php - - message: "#^Parameter \\#2 \\$offset of function substr expects int, float\\|int given\\.$#" + message: '#^Call to function is_int\(\) with int will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: ../../src/Security/OtpGenerator.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Service\\\\LoaResolutionService\\:\\:__construct\\(\\) has parameter \\$loaDefinitions with no value type specified in iterable type array\\.$#" + message: '#^Parameter \#2 \$offset of function substr expects int, float\|int given\.$#' + identifier: argument.type + count: 1 + path: ../../src/Security/OtpGenerator.php + + - + message: '#^Method Surfnet\\StepupBundle\\Service\\LoaResolutionService\:\:__construct\(\) has parameter \$loaDefinitions with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Service/LoaResolutionService.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Service\\\\SecondFactorTypeService\\:\\:__construct\\(\\) has parameter \\$gssfConfig with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Service\\SecondFactorTypeService\:\:__construct\(\) has parameter \$gssfConfig with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Service/SecondFactorTypeService.php - - message: "#^Property Surfnet\\\\StepupBundle\\\\Service\\\\SecondFactorTypeService\\:\\:\\$loaLevelTypeMap type has no value type specified in iterable type array\\.$#" + message: '#^Property Surfnet\\StepupBundle\\Service\\SecondFactorTypeService\:\:\$loaLevelTypeMap type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Service/SecondFactorTypeService.php - - message: "#^Property Surfnet\\\\StepupBundle\\\\Service\\\\SecondFactorTypeService\\:\\:\\$vettingTypeSubtractions type has no value type specified in iterable type array\\.$#" + message: '#^Property Surfnet\\StepupBundle\\Service\\SecondFactorTypeService\:\:\$vettingTypeSubtractions type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Service/SecondFactorTypeService.php - - message: "#^Access to an undefined property Surfnet\\\\StepupBundle\\\\Command\\\\SendSmsChallengeCommandInterface\\:\\:\\$body\\.$#" + message: '#^Access to an undefined property Surfnet\\StepupBundle\\Command\\SendSmsChallengeCommandInterface\:\:\$body\.$#' + identifier: property.notFound count: 1 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Access to an undefined property Surfnet\\\\StepupBundle\\\\Command\\\\SendSmsChallengeCommandInterface\\:\\:\\$identity\\.$#" + message: '#^Access to an undefined property Surfnet\\StepupBundle\\Command\\SendSmsChallengeCommandInterface\:\:\$identity\.$#' + identifier: property.notFound count: 1 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Access to an undefined property Surfnet\\\\StepupBundle\\\\Command\\\\SendSmsChallengeCommandInterface\\:\\:\\$institution\\.$#" + message: '#^Access to an undefined property Surfnet\\StepupBundle\\Command\\SendSmsChallengeCommandInterface\:\:\$institution\.$#' + identifier: property.notFound count: 1 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Access to an undefined property Surfnet\\\\StepupBundle\\\\Command\\\\SendSmsChallengeCommandInterface\\:\\:\\$phoneNumber\\.$#" + message: '#^Access to an undefined property Surfnet\\StepupBundle\\Command\\SendSmsChallengeCommandInterface\:\:\$phoneNumber\.$#' + identifier: property.notFound count: 2 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Access to an undefined property Surfnet\\\\StepupBundle\\\\Command\\\\SendSmsChallengeCommandInterface\\:\\:\\$recoveryTokenId\\.$#" + message: '#^Access to an undefined property Surfnet\\StepupBundle\\Command\\SendSmsChallengeCommandInterface\:\:\$recoveryTokenId\.$#' + identifier: property.notFound count: 1 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Access to an undefined property Surfnet\\\\StepupBundle\\\\Command\\\\VerifyPossessionOfPhoneCommandInterface\\:\\:\\$challenge\\.$#" + message: '#^Access to an undefined property Surfnet\\StepupBundle\\Command\\VerifyPossessionOfPhoneCommandInterface\:\:\$challenge\.$#' + identifier: property.notFound count: 1 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Access to an undefined property Surfnet\\\\StepupBundle\\\\Command\\\\VerifyPossessionOfPhoneCommandInterface\\:\\:\\$recoveryTokenId\\.$#" + message: '#^Access to an undefined property Surfnet\\StepupBundle\\Command\\VerifyPossessionOfPhoneCommandInterface\:\:\$recoveryTokenId\.$#' + identifier: property.notFound count: 1 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Service\\\\SmsRecoveryTokenService\\:\\:__construct\\(\\) has parameter \\$originator with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Service\\SmsRecoveryTokenService\:\:__construct\(\) has parameter \$originator with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Service/SmsRecoveryTokenService.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Service\\\\SmsSecondFactor\\\\Otp\\:\\:verify\\(\\) has parameter \\$userOtp with no type specified\\.$#" + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 2 + path: ../../src/Service/SmsSecondFactor/Otp.php + + - + message: '#^Method Surfnet\\StepupBundle\\Service\\SmsSecondFactor\\Otp\:\:verify\(\) has parameter \$userOtp with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Service/SmsSecondFactor/Otp.php - - message: "#^Parameter \\#1 \\$interval of method DateTime\\:\\:add\\(\\) expects DateInterval, DateInterval\\|null given\\.$#" + message: '#^Parameter \#1 \$interval of method DateTime\:\:add\(\) expects DateInterval, DateInterval\|null given\.$#' + identifier: argument.type count: 1 path: ../../src/Service/SmsSecondFactor/Otp.php - - message: "#^Parameter \\#1 \\$string of function strtoupper expects string, string\\|null given\\.$#" + message: '#^Parameter \#1 \$string of function strtoupper expects string, string\|null given\.$#' + identifier: argument.type count: 1 path: ../../src/Service/SmsSecondFactor/Otp.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Service\\\\SmsSecondFactor\\\\OtpVerification\\:\\:foundMatch\\(\\) has parameter \\$phoneNumber with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Service\\SmsSecondFactor\\OtpVerification\:\:foundMatch\(\) has parameter \$phoneNumber with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Service/SmsSecondFactor/OtpVerification.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Service\\\\SmsSecondFactor\\\\SmsVerificationStateHandler\\:\\:clearState\\(\\) has no return type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Service\\SmsSecondFactor\\SmsVerificationStateHandler\:\:clearState\(\) has no return type specified\.$#' + identifier: missingType.return count: 1 path: ../../src/Service/SmsSecondFactor/SmsVerificationStateHandler.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Twig\\\\LocaleExtension\\:\\:getLocalePreferenceForm\\(\\) has parameter \\$currentLocale with no type specified\\.$#" + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../src/Service/SmsSecondFactorService.php + + - + message: '#^Method Surfnet\\StepupBundle\\Twig\\LocaleExtension\:\:getLocalePreferenceForm\(\) has parameter \$currentLocale with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Twig/LocaleExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Twig\\\\LocaleExtension\\:\\:getLocalePreferenceForm\\(\\) has parameter \\$route with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Twig\\LocaleExtension\:\:getLocalePreferenceForm\(\) has parameter \$route with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Twig/LocaleExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Twig\\\\LocaleExtension\\:\\:getLocalePreferenceForm\\(\\) has parameter \\$routeParameters with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Twig\\LocaleExtension\:\:getLocalePreferenceForm\(\) has parameter \$routeParameters with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Twig/LocaleExtension.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Value\\\\Exception\\\\InvalidCountryCodeFormatException\\:\\:__construct\\(\\) has parameter \\$invalidCode with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Value\\Exception\\InvalidCountryCodeFormatException\:\:__construct\(\) has parameter \$invalidCode with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Value/Exception/InvalidCountryCodeFormatException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Value\\\\Exception\\\\InvalidPhoneNumberFormatException\\:\\:__construct\\(\\) has parameter \\$invalidFormat with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Value\\Exception\\InvalidPhoneNumberFormatException\:\:__construct\(\) has parameter \$invalidFormat with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Value/Exception/InvalidPhoneNumberFormatException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Value\\\\Exception\\\\UnknownCountryCodeException\\:\\:unknownCountryCode\\(\\) has parameter \\$code with no type specified\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Value\\Exception\\UnknownCountryCodeException\:\:unknownCountryCode\(\) has parameter \$code with no type specified\.$#' + identifier: missingType.parameter count: 1 path: ../../src/Value/Exception/UnknownCountryCodeException.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Value\\\\GssfConfig\\:\\:__construct\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Value\\GssfConfig\:\:__construct\(\) has parameter \$config with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Value/GssfConfig.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Value\\\\GssfConfig\\:\\:getLoaMap\\(\\) return type has no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Value\\GssfConfig\:\:getLoaMap\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Value/GssfConfig.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Value\\\\GssfConfig\\:\\:getSecondFactorTypes\\(\\) return type has no value type specified in iterable type array\\.$#" + message: '#^Method Surfnet\\StepupBundle\\Value\\GssfConfig\:\:getSecondFactorTypes\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue count: 1 path: ../../src/Value/GssfConfig.php - - message: "#^Method Surfnet\\\\StepupBundle\\\\Value\\\\PhoneNumber\\\\CountryCodeListing\\:\\:asArray\\(\\) should return array\\ but returns array\\\\.$#" + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../src/Value/PhoneNumber/CountryCode.php + + - + message: '#^Method Surfnet\\StepupBundle\\Value\\PhoneNumber\\CountryCodeListing\:\:asArray\(\) should return array\ but returns array\\.$#' + identifier: return.type count: 1 path: ../../src/Value/PhoneNumber/CountryCodeListing.php + + - + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../src/Value/PhoneNumber/InternationalPhoneNumber.php + + - + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../src/Value/PhoneNumber/PhoneNumber.php + + - + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../src/Value/SecondFactorType.php + + - + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../src/Value/YubikeyOtp.php diff --git a/ci/qa/phpunit.xml b/ci/qa/phpunit.xml index 6627a8a..a0f78de 100644 --- a/ci/qa/phpunit.xml +++ b/ci/qa/phpunit.xml @@ -1,7 +1,7 @@ withPaths([ + __DIR__ . '/../../src', + ]) +// ->withPhpSets() + ->withAttributesSets(all: true) + ->withComposerBased(phpunit: true, symfony: true, twig: true) + ->withTypeCoverageLevel(0) + ->withDeadCodeLevel(0) + ->withCodeQualityLevel(0); diff --git a/ci/qa/rector.sh b/ci/qa/rector.sh new file mode 100755 index 0000000..b2b5857 --- /dev/null +++ b/ci/qa/rector.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env sh + +# Ensure we run from project root +cd "$(dirname "$0")/../../" || exit 1 +./vendor/bin/rector --config=ci/qa/rector.php "$@" diff --git a/composer.json b/composer.json index 4179295..3aea29e 100644 --- a/composer.json +++ b/composer.json @@ -20,30 +20,37 @@ "ext-openssl": "*", "guzzlehttp/guzzle": "^7.8", "monolog/monolog": "^3", - "surfnet/stepup-saml-bundle": "^6.0", - "symfony/config": "^5.4|^6.3", - "symfony/dependency-injection": "^5.4|^6.3", - "symfony/form": "^5.4|^6.3", - "symfony/framework-bundle": "^5.4|^6.3", - "symfony/http-kernel": "^5.4|^6.3", - "symfony/twig-bridge": "^5.4|^6.3", - "symfony/validator": "^5.4|^6.3" + "surfnet/stepup-saml-bundle": "^7.0", + "symfony/config": "^6.3|^7.0", + "symfony/dependency-injection": "^6.3|^7.0", + "symfony/form": "^6.3|^7.0", + "symfony/framework-bundle": "^6.3|^7.0", + "symfony/http-kernel": "^6.3|^7.0", + "symfony/twig-bridge": "^6.3|^7.0", + "symfony/validator": "^6.3|^7.0" }, "require-dev": { + "irstea/phpcpd-shim": "^6.0", + "malukenho/docheader": "^1.1", "mockery/mockery": "^1.5", "overtrue/phplint": "*", "phpmd/phpmd": "^2.13", - "phpstan/phpstan": "^1.10", - "phpstan/phpstan-symfony": "^1.3", - "phpunit/phpunit": "^9.6", - "sebastian/phpcpd": "^6.0", - "slevomat/coding-standard": "^8.13", - "squizlabs/php_codesniffer": "^3.7.1", - "symfony/phpunit-bridge": "^5.4|^6.3" + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-symfony": "^2.0", + "phpunit/phpunit": "^11.0.0", + "rector/rector": "^2.2", + "slevomat/coding-standard": "^8.24", + "squizlabs/php_codesniffer": "^4.0", + "symfony/phpunit-bridge": "^7.3" }, "scripts": { "check": [ + "@check-ci", + "@rector" + ], + "check-ci": [ "@composer-validate", + "@license-headers", "@test", "@phplint", "@phpcpd", @@ -59,7 +66,10 @@ "phpstan": "./ci/qa/phpstan", "phpstan-baseline": "./ci/qa/phpstan-update-baseline", "test": "./ci/qa/phpunit", - "phpcbf": "./ci/qa/phpcbf" + "license-headers": "./ci/qa/docheader", + "phpcbf": "./ci/qa/phpcbf", + "rector": "./ci/qa/rector.sh --dry-run", + "rector-fix": "./ci/qa/rector.sh" }, "config": { "sort-packages": true, @@ -72,6 +82,10 @@ "includes": [ "./ci/qa/extension.neon" ] - } + }, + "symfony": { + "allow-contrib": false, + "require": "7.0.*" + } } } diff --git a/src/Command/SendSmsCommand.php b/src/Command/SendSmsCommand.php index 58a75aa..bec3ea4 100644 --- a/src/Command/SendSmsCommand.php +++ b/src/Command/SendSmsCommand.php @@ -25,14 +25,12 @@ class SendSmsCommand { /** - * @Assert\NotBlank(message="stepup.send_sms_command.recipient.may_not_be_empty") - * @Assert\Type(type="string", message="stepup.send_sms_command.recipient.must_be_string") - * @Assert\Regex(pattern="~^\d+$~", message="stepup.send_sms_command.recipient.must_consist_of_digits") - * - * The recipient as a string of digits (31612345678 for +31 6 1234 5678). * * @var string */ + #[Assert\NotBlank(message: 'stepup.send_sms_command.recipient.may_not_be_empty')] + #[Assert\Type(type: 'string', message: 'stepup.send_sms_command.recipient.must_be_string')] + #[Assert\Regex(pattern: '~^\d+$~', message: 'stepup.send_sms_command.recipient.must_consist_of_digits')] public $recipient; /** diff --git a/src/Command/SwitchLocaleCommand.php b/src/Command/SwitchLocaleCommand.php index 69fff41..511b691 100644 --- a/src/Command/SwitchLocaleCommand.php +++ b/src/Command/SwitchLocaleCommand.php @@ -30,10 +30,10 @@ class SwitchLocaleCommand public $identityId; /** - * @Assert\NotBlank() - * @Assert\Type(type="string") * * @var string */ + #[Assert\NotBlank] + #[Assert\Type(type: 'string')] public $locale; } diff --git a/src/Command/VerifyPossessionOfPhoneCommand.php b/src/Command/VerifyPossessionOfPhoneCommand.php index 3f7fe17..ea8ec9e 100644 --- a/src/Command/VerifyPossessionOfPhoneCommand.php +++ b/src/Command/VerifyPossessionOfPhoneCommand.php @@ -25,16 +25,16 @@ class VerifyPossessionOfPhoneCommand implements VerifyPossessionOfPhoneCommandInterface { /** - * @Assert\NotBlank(message="stepup.verify_possession_of_phone_command.challenge.may_not_be_empty") - * @Assert\Type(type="string", message="stepup.verify_possession_of_phone_command.challenge.must_be_string") * * @var string */ + #[Assert\NotBlank(message: 'stepup.verify_possession_of_phone_command.challenge.may_not_be_empty')] + #[Assert\Type(type: 'string', message: 'stepup.verify_possession_of_phone_command.challenge.must_be_string')] public $challenge; /** - * @Assert\Type(type="string", message="stepup.verify_possession_of_phone_command.second_factor_id.must_be_string") * @var string */ + #[Assert\Type(type: 'string', message: 'stepup.verify_possession_of_phone_command.second_factor_id.must_be_string')] public $secondFactorId; } diff --git a/src/Command/VerifyPossessionOfPhoneForRecoveryTokenCommand.php b/src/Command/VerifyPossessionOfPhoneForRecoveryTokenCommand.php index 0968f75..81e002e 100644 --- a/src/Command/VerifyPossessionOfPhoneForRecoveryTokenCommand.php +++ b/src/Command/VerifyPossessionOfPhoneForRecoveryTokenCommand.php @@ -25,16 +25,16 @@ class VerifyPossessionOfPhoneForRecoveryTokenCommand implements VerifyPossessionOfPhoneCommandInterface { /** - * @Assert\NotBlank(message="stepup.verify_possession_of_phone_command.challenge.may_not_be_empty") - * @Assert\Type(type="string", message="stepup.verify_possession_of_phone_command.challenge.must_be_string") * * @var string */ + #[Assert\NotBlank(message: 'stepup.verify_possession_of_phone_command.challenge.may_not_be_empty')] + #[Assert\Type(type: 'string', message: 'stepup.verify_possession_of_phone_command.challenge.must_be_string')] public $challenge; /** - * @Assert\Type(type="string", message="stepup.verify_possession_of_phone_command.recovery_token_id.must_be_string") * @var string */ + #[Assert\Type(type: 'string', message: 'stepup.verify_possession_of_phone_command.recovery_token_id.must_be_string')] public $recoveryTokenId; } diff --git a/src/Controller/ExceptionController.php b/src/Controller/ExceptionController.php index 9eccc18..a6cad8e 100644 --- a/src/Controller/ExceptionController.php +++ b/src/Controller/ExceptionController.php @@ -44,7 +44,7 @@ /** * @package Surfnet\StepupBundle\Controller * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) Contains extensive mapping for exceptions + * @SuppressWarnings("PHPMD.CouplingBetweenObjects") Contains extensive mapping for exceptions */ class ExceptionController extends FrameworkController { @@ -111,7 +111,7 @@ protected function getStatusCode(Throwable $exception): int /** * @return array View parameters 'title' and 'description' - * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings("PHPMD.CyclomaticComplexity") */ protected function getPageTitleAndDescription(Throwable $exception): array { diff --git a/src/DateTime/DateTime.php b/src/DateTime/DateTime.php index c1a445c..2e5a9c5 100644 --- a/src/DateTime/DateTime.php +++ b/src/DateTime/DateTime.php @@ -24,14 +24,8 @@ class DateTime { - /** - * @var CoreDateTime|null - */ - private static ?CoreDateTime $now = null; + protected static ?CoreDateTime $now = null; - /** - * @return CoreDateTime - */ public static function now(): CoreDateTime { return self::$now ?: new CoreDateTime; diff --git a/src/DependencyInjection/SurfnetStepupExtension.php b/src/DependencyInjection/SurfnetStepupExtension.php index 9b6d20a..b5cafcc 100644 --- a/src/DependencyInjection/SurfnetStepupExtension.php +++ b/src/DependencyInjection/SurfnetStepupExtension.php @@ -38,7 +38,7 @@ use function array_key_exists; /** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings("PHPMD.CouplingBetweenObjects") */ class SurfnetStepupExtension extends Extension { diff --git a/src/EventListener/CannotWriteToPrimaryLogExceptionExceptionListener.php b/src/EventListener/CannotWriteToPrimaryLogExceptionExceptionListener.php index 9413121..58d5835 100644 --- a/src/EventListener/CannotWriteToPrimaryLogExceptionExceptionListener.php +++ b/src/EventListener/CannotWriteToPrimaryLogExceptionExceptionListener.php @@ -1,5 +1,21 @@ + */ final class SwitchLocaleType extends AbstractType { public function __construct(private readonly LocaleChoiceList $localeChoiceList, private readonly UrlGeneratorInterface $urlGenerator) diff --git a/src/Request/JsonConvertibleResolver.php b/src/Request/JsonConvertibleResolver.php index 546c914..fe126a8 100644 --- a/src/Request/JsonConvertibleResolver.php +++ b/src/Request/JsonConvertibleResolver.php @@ -30,7 +30,7 @@ * ParamConverter that converts JSON objects with underscore notation mapped to snake-cased, public properties of * classes that implement JsonConvertible. * - * @SuppressWarnings(PHPMD.MissingImport) + * @SuppressWarnings("PHPMD.MissingImport") * @see JsonConvertible */ class JsonConvertibleResolver implements ValueResolverInterface diff --git a/src/Tests/DateTimeHelper.php b/src/Tests/DateTimeMock.php similarity index 54% rename from src/Tests/DateTimeHelper.php rename to src/Tests/DateTimeMock.php index d0d9d97..289156d 100644 --- a/src/Tests/DateTimeHelper.php +++ b/src/Tests/DateTimeMock.php @@ -1,9 +1,7 @@ setAccessible(true); - $nowProperty->setValue($now); + self::$now = $date; } -} +} \ No newline at end of file diff --git a/src/Tests/DependencyInjection/Configurator/GuzzleClientRequestIdConfiguratorTest.php b/src/Tests/DependencyInjection/Configurator/GuzzleClientRequestIdConfiguratorTest.php index 71dcecf..471681c 100644 --- a/src/Tests/DependencyInjection/Configurator/GuzzleClientRequestIdConfiguratorTest.php +++ b/src/Tests/DependencyInjection/Configurator/GuzzleClientRequestIdConfiguratorTest.php @@ -30,10 +30,8 @@ class GuzzleClientRequestIdConfiguratorTest extends UnitTest { use m\Adapter\Phpunit\MockeryPHPUnitIntegration; - /** - * @group Configurator - * @group Guzzle - */ + #[\PHPUnit\Framework\Attributes\Group('Configurator')] + #[\PHPUnit\Framework\Attributes\Group('Guzzle')] public function testTheRequestIdInjectorIsAttachedToTheGuzzleClient(): void { $requestIdInjector = m::mock(GuzzleRequestIdInjector::class); diff --git a/src/Tests/Exception/ArtTest.php b/src/Tests/Exception/ArtTest.php index 269fbff..d15cbd8 100644 --- a/src/Tests/Exception/ArtTest.php +++ b/src/Tests/Exception/ArtTest.php @@ -27,10 +27,8 @@ class ArtTest extends UnitTest { - /** - * @test - * @group art - */ + #[\PHPUnit\Framework\Attributes\Group('art')] + #[\PHPUnit\Framework\Attributes\Test] public function art_code_is_distinct_per_exception_type(): void { $art1 = new Exception(); @@ -39,10 +37,8 @@ public function art_code_is_distinct_per_exception_type(): void $this->assertNotEquals($art1, $art2, 'Expected different art code for different exception type'); } - /** - * @test - * @group art - */ + #[\PHPUnit\Framework\Attributes\Group('art')] + #[\PHPUnit\Framework\Attributes\Test] public function art_code_is_distinct_per_message(): void { $art1 = new Exception('one'); @@ -51,11 +47,9 @@ public function art_code_is_distinct_per_message(): void $this->assertNotEquals($art1, $art2, 'Expected different art code for different exception message'); } - /** - * @test - * @group art - * @dataProvider artCodeWithStrippedVariables - */ + #[\PHPUnit\Framework\Attributes\Group('art')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('artCodeWithStrippedVariables')] public function exception_translates_to_art_code_with_variables_stripped(Exception $exception, string $expectedArtCode): void { $this->assertEquals( @@ -64,7 +58,7 @@ public function exception_translates_to_art_code_with_variables_stripped(Excepti ); } - public function artCodeWithStrippedVariables(): array + public static function artCodeWithStrippedVariables(): array { $artCode = Art::forException( new Exception('This is a \'good\' message') diff --git a/src/Tests/Guzzle/Middleware/GuzzleRequestIdInjectorTest.php b/src/Tests/Guzzle/Middleware/GuzzleRequestIdInjectorTest.php index 7871267..0729192 100644 --- a/src/Tests/Guzzle/Middleware/GuzzleRequestIdInjectorTest.php +++ b/src/Tests/Guzzle/Middleware/GuzzleRequestIdInjectorTest.php @@ -37,9 +37,7 @@ class GuzzleRequestIdInjectorTest extends UnitTest { use m\Adapter\Phpunit\MockeryPHPUnitIntegration; - /** - * @group Guzzle - */ + #[\PHPUnit\Framework\Attributes\Group('Guzzle')] public function testItSetsTheRequestIdAsHeader(): void { $expectedRequestId = 'my-request-id'; diff --git a/src/Tests/Http/JsonHelperTest.php b/src/Tests/Http/JsonHelperTest.php index 7edb308..7ff6532 100644 --- a/src/Tests/Http/JsonHelperTest.php +++ b/src/Tests/Http/JsonHelperTest.php @@ -1,5 +1,21 @@ expectException(InvalidArgumentException::class); JsonHelper::decode($nonString); } - /** - * @test - * @group json - */ + #[\PHPUnit\Framework\Attributes\Group('json')] + #[\PHPUnit\Framework\Attributes\Test] public function jsonHelperDecodesStringsToArrays(): void { $expectedDecodedResult = ['hello' => 'world']; @@ -36,10 +47,8 @@ public function jsonHelperDecodesStringsToArrays(): void $this->assertSame($expectedDecodedResult, $actualDecodedResult); } - /** - * @test - * @group json - */ + #[\PHPUnit\Framework\Attributes\Group('json')] + #[\PHPUnit\Framework\Attributes\Test] public function jsonHelperThrowsAnExceptionWhenThereIsASyntaxError(): void { $this->expectException(JsonException::class); @@ -47,7 +56,7 @@ public function jsonHelperThrowsAnExceptionWhenThereIsASyntaxError(): void JsonHelper::decode($jsonWithMissingDoubleQuotes); } - public function nonStringProvider(): array + public static function nonStringProvider(): array { return [ 'null' => [null], diff --git a/src/Tests/Security/OtpGeneratorTest.php b/src/Tests/Security/OtpGeneratorTest.php index b606ea1..148c0e0 100644 --- a/src/Tests/Security/OtpGeneratorTest.php +++ b/src/Tests/Security/OtpGeneratorTest.php @@ -26,10 +26,8 @@ final class OtpGeneratorTest extends TestCase { - /** - * @test - * @group security - */ + #[\PHPUnit\Framework\Attributes\Group('security')] + #[\PHPUnit\Framework\Attributes\Test] public function it_generates_eight_character_otp_strings(): void { $otp = OtpGenerator::generate(8); @@ -38,7 +36,7 @@ public function it_generates_eight_character_otp_strings(): void $this->assertSame(8, strlen($otp), 'OTP is not eight characters long'); } - public function nonPositiveIntegers(): array + public static function nonPositiveIntegers(): array { return [ 'null' => [null], @@ -52,11 +50,9 @@ public function nonPositiveIntegers(): array ]; } - /** - * @test - * @group security - * @dataProvider nonPositiveIntegers - */ + #[\PHPUnit\Framework\Attributes\Group('security')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('nonPositiveIntegers')] public function it_cannot_generate_otp_strings_of_negative_or_non_integer_length(mixed $length): void { $this->expectException(InvalidArgumentException::class); diff --git a/src/Tests/Service/LoaResolutionServiceTest.php b/src/Tests/Service/LoaResolutionServiceTest.php index b21cb88..c177c1a 100644 --- a/src/Tests/Service/LoaResolutionServiceTest.php +++ b/src/Tests/Service/LoaResolutionServiceTest.php @@ -40,11 +40,9 @@ public function setUp(): void } } - /** - * @test - * @group service - * @dataProvider loaProvider - */ + #[\PHPUnit\Framework\Attributes\Group('service')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('loaProvider')] public function it_allows_to_get_the_correct_loa_by_identifier(float $level, string $identifier): void { $expectedLoa = new Loa($level, $identifier); @@ -53,10 +51,8 @@ public function it_allows_to_get_the_correct_loa_by_identifier(float $level, str $this->assertEquals($expectedLoa, $loaResolutionService->getLoa($identifier)); } - /** - * @test - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] + #[\PHPUnit\Framework\Attributes\Test] public function if_the_loa_definition_does_not_exist_null_is_returned(): void { $loaResolutionService = new LoaResolutionService($this->loas); @@ -64,11 +60,9 @@ public function if_the_loa_definition_does_not_exist_null_is_returned(): void $this->assertNull($loaResolutionService->getLoa('An unknown identifier')); } - /** - * @test - * @group service - * @dataProvider loaProvider - */ + #[\PHPUnit\Framework\Attributes\Group('service')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('loaProvider')] public function it_allows_to_get_the_correct_loa_by_the_loa_level(float $level, string $identifier): void { $expectedLoa = new Loa($level, $identifier); @@ -77,10 +71,8 @@ public function it_allows_to_get_the_correct_loa_by_the_loa_level(float $level, $this->assertEquals($expectedLoa, $loaResoltionService->getLoaByLevel($level)); } - /** - * @test - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] + #[\PHPUnit\Framework\Attributes\Test] public function if_the_loa_level_does_not_exist_null_is_returned(): void { $loaResolutionService = new LoaResolutionService($this->loas); @@ -88,7 +80,7 @@ public function if_the_loa_level_does_not_exist_null_is_returned(): void $this->assertNull($loaResolutionService->getLoaByLevel(999)); } - public function loaProvider(): array + public static function loaProvider(): array { return [ 'Loa of Level 1' => [Loa::LOA_1, 'http://some.url.tld/authentication/loa1'], diff --git a/src/Tests/Service/SecondFactorTypeServiceTest.php b/src/Tests/Service/SecondFactorTypeServiceTest.php index 766f068..9b3ffe0 100644 --- a/src/Tests/Service/SecondFactorTypeServiceTest.php +++ b/src/Tests/Service/SecondFactorTypeServiceTest.php @@ -39,18 +39,14 @@ protected function setUp(): void $this->vettingTypeSelfAsserted = new VettingType(VettingType::TYPE_SELF_ASSERTED_REGISTRATION); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testItCanBeCreated(): void { $service = new SecondFactorTypeService([]); $this->assertInstanceOf(SecondFactorTypeService::class, $service); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testItCanBeAskedForEnabledSecondFactorTypes(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); @@ -62,27 +58,21 @@ public function testItCanBeAskedForEnabledSecondFactorTypes(): void $this->assertContains('yubikey', $types); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testGetLevel(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); $this->assertEquals(2, $service->getLevel(new SecondFactorType('sms'), $this->vettingTypeOnPremise)); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testGetLevelSubtractedOnSelfAssertedRegistration(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); $this->assertEquals(1.5, $service->getLevel(new SecondFactorType('sms'), $this->vettingTypeSelfAsserted)); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testGetLevelCannotGetLevelOfNonExistingSecondFactorType(): void { $this->expectExceptionMessage("The Loa level of this type: u3f can't be retrieved."); @@ -92,9 +82,7 @@ public function testGetLevelCannotGetLevelOfNonExistingSecondFactorType(): void $service->getLevel(new SecondFactorType('u3f'), $this->vettingTypeOnPremise); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testItRejectsInvalidVettingType(): void { $this->expectExceptionMessage('The provided vetting type "self-righteous-registration" is not permitted. Use one of on-premise, self-asserted-registration, self-vet, unknown'); @@ -104,9 +92,7 @@ public function testItRejectsInvalidVettingType(): void $service->getLevel(new SecondFactorType('yubikey'), new VettingType('self-righteous-registration')); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testItCanBeAskedForEnabledSecondFactorTypesWhenNoGssfSet(): void { $service = new SecondFactorTypeService([]); @@ -117,9 +103,7 @@ public function testItCanBeAskedForEnabledSecondFactorTypesWhenNoGssfSet(): void $this->assertContains('yubikey', $types); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testItCanTestForSatisfactoryLoaLevel(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); @@ -142,9 +126,7 @@ public function testItCanTestForSatisfactoryLoaLevel(): void $this->assertFalse($service->canSatisfy($yubikey, $loa2, $this->vettingTypeSelfAsserted)); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testIsSatisfiedBy(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); @@ -168,9 +150,7 @@ public function testIsSatisfiedBy(): void $this->assertTrue($service->isSatisfiedBy($sms, $loa3, $this->vettingTypeSelfAsserted)); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testHasEqualOrHigherLoaComparedTo(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); @@ -204,9 +184,7 @@ public function testHasEqualOrHigherLoaComparedTo(): void $this->assertTrue($service->hasEqualOrHigherLoaComparedTo($sms, $this->vettingTypeSelfAsserted, $sms, $this->vettingTypeSelfAsserted)); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testHasEqualOrLowerLoaComparedTo(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); @@ -240,9 +218,7 @@ public function testHasEqualOrLowerLoaComparedTo(): void $this->assertTrue($service->hasEqualOrLowerLoaComparedTo($sms, $this->vettingTypeSelfAsserted, $sms, $this->vettingTypeSelfAsserted)); } - /** - * @group service - */ + #[\PHPUnit\Framework\Attributes\Group('service')] public function testItCanDetermineSecondFactorTypeIsGssf(): void { $service = new SecondFactorTypeService($this->getAvailableSecondFactorTypes()); diff --git a/src/Tests/Service/SmsSecondFactor/OtpTest.php b/src/Tests/Service/SmsSecondFactor/OtpTest.php index 0629ae8..3f8d54a 100644 --- a/src/Tests/Service/SmsSecondFactor/OtpTest.php +++ b/src/Tests/Service/SmsSecondFactor/OtpTest.php @@ -28,7 +28,7 @@ class OtpTest extends TestCase { - public function non_strings(): array + public static function non_strings(): array { return [ 'array' => [[]], @@ -40,7 +40,7 @@ public function non_strings(): array ]; } - public function non_non_empty_strings(): array + public static function non_non_empty_strings(): array { return [ 'empty string' => [''], @@ -53,10 +53,8 @@ public function non_non_empty_strings(): array ]; } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function can_be_created(): void { $otp = Otp::create('ABCDEFG', '123', new DateInterval('PT5M')); @@ -64,11 +62,9 @@ public function can_be_created(): void $this->assertInstanceOf(Otp::class, $otp); } - /** - * @test - * @group sms - * @dataProvider non_non_empty_strings - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('non_non_empty_strings')] public function only_accepts_string_otps(mixed $nonString): void { $this->expectException(InvalidArgumentException::class); @@ -77,11 +73,9 @@ public function only_accepts_string_otps(mixed $nonString): void Otp::create($nonString, '123', new DateInterval('PT5M')); } - /** - * @test - * @group sms - * @dataProvider non_non_empty_strings - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('non_non_empty_strings')] public function only_accepts_string_phone_numbers(mixed $nonString): void { $this->expectException(InvalidArgumentException::class); @@ -90,11 +84,9 @@ public function only_accepts_string_phone_numbers(mixed $nonString): void Otp::create('ABCDEFG', $nonString, new DateInterval('PT5M')); } - /** - * @test - * @group sms - * @dataProvider non_strings - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('non_strings')] public function it_verifies_only_string_otps(mixed $nonString): void { $this->expectException(InvalidArgumentException::class); diff --git a/src/Tests/Service/SmsSecondFactor/SmsVerificationStateTest.php b/src/Tests/Service/SmsSecondFactor/SmsVerificationStateTest.php index 03267ca..78f6b44 100644 --- a/src/Tests/Service/SmsSecondFactor/SmsVerificationStateTest.php +++ b/src/Tests/Service/SmsSecondFactor/SmsVerificationStateTest.php @@ -26,17 +26,13 @@ use Surfnet\StepupBundle\Exception\InvalidArgumentException; use Surfnet\StepupBundle\Service\Exception\TooManyChallengesRequestedException; use Surfnet\StepupBundle\Service\SmsSecondFactor\SmsVerificationState; -use Surfnet\StepupBundle\Tests\DateTimeHelper; +use Surfnet\StepupBundle\Tests\DateTimeMock; -/** - * @runTestsInSeparateProcesses - */ +#[\PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses] class SmsVerificationStateTest extends TestCase { - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function it_can_be_matched(): void { $state = new SmsVerificationState(new DateInterval('PT15M'), 3); @@ -45,17 +41,15 @@ public function it_can_be_matched(): void $this->assertTrue($state->verify($otp)->wasSuccessful(), 'OTP should have matched'); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function it_can_expire(): void { - DateTimeHelper::setCurrentTime(new DateTime('@0')); + DateTimeMock::setTime(new DateTime('@0')); $state = new SmsVerificationState(new DateInterval('PT1S'), 3); $otp = $state->requestNewOtp('123'); - DateTimeHelper::setCurrentTime(new DateTime('@1')); + DateTimeMock::setTime(new DateTime('@1')); $verification = $state->verify($otp); $this->assertFalse($verification->wasSuccessful(), "Verification shouldn't be successful"); @@ -63,33 +57,29 @@ public function it_can_expire(): void $this->assertTrue($verification->didOtpMatch(), 'OTP should have matched'); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function the_expiration_time_is_pushed_back_with_each_new_otp(): void { // Set a challenge - DateTimeHelper::setCurrentTime(new DateTime('@0')); + DateTimeMock::setTime(new DateTime('@0')); $state = new SmsVerificationState(new DateInterval('PT5S'), 3); $otp = $state->requestNewOtp('123'); // Try after 3 seconds - DateTimeHelper::setCurrentTime(new DateTime('@3')); + DateTimeMock::setTime(new DateTime('@3')); $this->assertTrue($state->verify($otp)->wasSuccessful(), "OTP should've matched"); // Set a new challenge $otp = $state->requestNewOtp('123'); // Try after 4 seconds (total of 7 seconds, longer than 5-second expiry interval) - DateTimeHelper::setCurrentTime(new DateTime('@7')); + DateTimeMock::setTime(new DateTime('@7')); $this->assertTrue($state->verify($otp)->wasSuccessful(), "OTP should've matched"); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function the_consumer_can_request_too_many_otps_but_can_keep_track_of_remaining_requests(): void { $state = new SmsVerificationState(new DateInterval('PT10S'), 3); @@ -111,16 +101,14 @@ public function the_consumer_can_request_too_many_otps_but_can_keep_track_of_rem $this->assertSame(0, $state->getOtpRequestsRemainingCount()); } - public function lteZeroMaximumTries(): array + public static function lteZeroMaximumTries(): array { return [[0], [-1], [-1000]]; } - /** - * @test - * @group sms - * @dataProvider lteZeroMaximumTries - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('lteZeroMaximumTries')] public function maximum_challenges_must_be_gte_1(int $maximumTries): void { $this->expectException(InvalidArgumentException::class); @@ -129,13 +117,11 @@ public function maximum_challenges_must_be_gte_1(int $maximumTries): void new SmsVerificationState(new DateInterval('PT15M'), $maximumTries); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function a_previous_otp_can_be_matched(): void { - DateTimeHelper::setCurrentTime(new DateTime('@0')); + DateTimeMock::setTime(new DateTime('@0')); $state = new SmsVerificationState(new DateInterval('PT5S'), 3); $otp1 = $state->requestNewOtp('123'); $otp2 = $state->requestNewOtp('123'); @@ -144,13 +130,11 @@ public function a_previous_otp_can_be_matched(): void $this->assertTrue($state->verify($otp2)->wasSuccessful(), "OTP should've matched"); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function otp_matching_is_case_insensitive(): void { - DateTimeHelper::setCurrentTime(new DateTime('@0')); + DateTimeMock::setTime(new DateTime('@0')); $state = new SmsVerificationState(new DateInterval('PT5S'), 3); $otp = $state->requestNewOtp('123'); @@ -158,10 +142,8 @@ public function otp_matching_is_case_insensitive(): void $this->assertTrue($state->verify(strtoupper($otp))->wasSuccessful(), "OTP should've matched"); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function no_more_than_10_attempts_can_be_made_overall(): void { $state = new SmsVerificationState(new DateInterval('PT5S'), 3); @@ -175,10 +157,8 @@ public function no_more_than_10_attempts_can_be_made_overall(): void $this->assertTrue($state->verify('3')->wasAttemptedTooManyTimes(), 'Failed to assert maximum attempts achieved'); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function no_more_than_10_attempts_can_be_made_overall_even_when_multiple_otps_requested(): void { $state = new SmsVerificationState(new DateInterval('PT5S'), 99999); @@ -193,10 +173,8 @@ public function no_more_than_10_attempts_can_be_made_overall_even_when_multiple_ $this->assertTrue($state->verify('3')->wasAttemptedTooManyTimes(), 'Failed to assert maximum attempts achieved'); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function no_more_than_10_attempts_can_be_made_overall_even_when_no_otp_requested(): void { $state = new SmsVerificationState(new DateInterval('PT5S'), 3); @@ -209,10 +187,8 @@ public function no_more_than_10_attempts_can_be_made_overall_even_when_no_otp_re $this->assertTrue($state->verify('3')->wasAttemptedTooManyTimes(), 'Failed to assert maximum attempts achieved'); } - /** - * @test - * @group sms - */ + #[\PHPUnit\Framework\Attributes\Group('sms')] + #[\PHPUnit\Framework\Attributes\Test] public function requesting_an_otp_with_a_different_phone_number_clears_otps_for_other_phone_numbers(): void { $state = new SmsVerificationState(new DateInterval('PT5S'), 3); diff --git a/src/Tests/Value/LoaTest.php b/src/Tests/Value/LoaTest.php index d911b07..d46b16c 100644 --- a/src/Tests/Value/LoaTest.php +++ b/src/Tests/Value/LoaTest.php @@ -28,11 +28,9 @@ class LoaTest extends UnitTest { - /** - * @test - * @group value - * @dataProvider wrongTypeLevelProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('wrongTypeLevelProvider')] public function it_cannot_be_created_with_a_wrong_loa_data_type(mixed $invalidLevel): void { self::expectException(Error::class); @@ -40,11 +38,9 @@ public function it_cannot_be_created_with_a_wrong_loa_data_type(mixed $invalidLe new Loa($invalidLevel, 'identifier'); } - /** - * @test - * @group value - * @dataProvider invalidLevelProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalidLevelProvider')] public function it_cannot_be_created_with_an_invalid_loa_type(mixed $invalidLevel): void { $this->expectException(DomainException::class); @@ -52,10 +48,8 @@ public function it_cannot_be_created_with_an_invalid_loa_type(mixed $invalidLeve new Loa($invalidLevel, 'identifier'); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function it_cannot_be_created_when_the_identifier_is_not_a_string(): void { // Using a data provider causes PHP to type cast certain values. Resulting in false test results @@ -72,10 +66,8 @@ public function it_cannot_be_created_when_the_identifier_is_not_a_string(): void new Loa(Loa::LOA_1, new stdClass()); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function the_loa_can_be_asked_whether_or_not_it_has_a_particular_identifier(): void { $correctIdentifier = 'correct identifier'; @@ -87,10 +79,8 @@ public function the_loa_can_be_asked_whether_or_not_it_has_a_particular_identifi $this->assertFalse($loa->isIdentifiedBy($otherIdentifier)); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function it_correctly_compares_lower_or_equal_to_level(): void { $loa = new Loa(Loa::LOA_2, 'a'); @@ -101,10 +91,8 @@ public function it_correctly_compares_lower_or_equal_to_level(): void $this->assertFalse($loa->levelIsLowerOrEqualTo(Loa::LOA_SELF_VETTED), 'Loa 2 !<= Loa 1.5'); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function it_correctly_compares_higher_or_equal_to_level(): void { $loa = new Loa(Loa::LOA_2, 'a'); @@ -115,10 +103,8 @@ public function it_correctly_compares_higher_or_equal_to_level(): void $this->assertTrue($loa->levelIsHigherOrEqualTo(Loa::LOA_1), 'Loa 2 >= Loa 1'); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function in_order_to_be_able_to_satisfy_a_loa_the_loa_must_have_a_level_higher_or_equal_to_the_other_level(): void { $loa1 = new Loa(Loa::LOA_1, '1'); @@ -132,10 +118,8 @@ public function in_order_to_be_able_to_satisfy_a_loa_the_loa_must_have_a_level_h $this->assertTrue($loa2->canSatisfyLoa($loa1), 'Loa 2 can satisfy Loa 1'); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function it_can_check_whether_or_not_it_is_of_a_particuler_level(): void { $loa = new Loa(Loa::LOA_2, '2'); @@ -146,7 +130,7 @@ public function it_can_check_whether_or_not_it_is_of_a_particuler_level(): void $this->assertFalse($loa->isOfLevel(Loa::LOA_3), 'Loa 2 is not of level 3'); } - public function invalidLevelProvider(): array + public static function invalidLevelProvider(): array { return [ 'unknown level' => [4], @@ -154,7 +138,7 @@ public function invalidLevelProvider(): array ]; } - public function wrongTypeLevelProvider(): array + public static function wrongTypeLevelProvider(): array { return [ 'string' => ['a'], diff --git a/src/Tests/Value/PhoneNumber/CountryCodeTest.php b/src/Tests/Value/PhoneNumber/CountryCodeTest.php index 8a9b8b8..e787579 100644 --- a/src/Tests/Value/PhoneNumber/CountryCodeTest.php +++ b/src/Tests/Value/PhoneNumber/CountryCodeTest.php @@ -28,11 +28,9 @@ class CountryCodeTest extends UnitTest { - /** - * @test - * @group value - * @dataProvider invalidConstructorArgumentProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalidConstructorArgumentProvider')] public function a_country_code_cannot_be_constructed_with_anything_but_a_string(mixed $invalidArgument): void { $this->expectException(InvalidArgumentException::class); @@ -40,11 +38,9 @@ public function a_country_code_cannot_be_constructed_with_anything_but_a_string( new CountryCode($invalidArgument); } - /** - * @test - * @group value - * @dataProvider invalidStringArgumentProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalidStringArgumentProvider')] public function a_phone_number_can_only_be_created_if_the_string_contains_digits_only(string $invalidArgument): void { $this->expectException(InvalidArgumentException::class); @@ -52,10 +48,8 @@ public function a_phone_number_can_only_be_created_if_the_string_contains_digits new CountryCode($invalidArgument); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function a_country_code_cannot_be_created_with_a_country_code_that_does_not_exist(): void { $this->expectException(UnknownCountryCodeException::class); @@ -63,10 +57,8 @@ public function a_country_code_cannot_be_created_with_a_country_code_that_does_n new CountryCode('99999'); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function the_country_code_returns_the_country_code_upon_request(): void { $definition = '1649'; @@ -75,10 +67,8 @@ public function the_country_code_returns_the_country_code_upon_request(): void $this->assertEquals($definition, $countryCode->getCountryCode()); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function country_codes_are_equal_when_the_given_country_code_is_equal(): void { $base = new CountryCode('1787'); @@ -89,18 +79,16 @@ public function country_codes_are_equal_when_the_given_country_code_is_equal(): $this->assertFalse($base->equals($different), 'Country codes with a different definition should not be equal'); } - /** - * @test - * @group value - * @dataProvider toStringProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('toStringProvider')] public function to_string_renders_a_correctly_formattted_string_representation(string $definition, string $stringRepresentation): void { $countryCode = new CountryCode($definition); $this->assertSame($stringRepresentation, $countryCode->__toString()); } - public function invalidConstructorArgumentProvider(): array + public static function invalidConstructorArgumentProvider(): array { return [ 'int' => [0], @@ -112,7 +100,7 @@ public function invalidConstructorArgumentProvider(): array ]; } - public function toStringProvider(): array + public static function toStringProvider(): array { return [ '4 digits' => ['1787', '+1 787'], @@ -124,7 +112,7 @@ public function toStringProvider(): array ]; } - public function invalidStringArgumentProvider(): array + public static function invalidStringArgumentProvider(): array { return [ 'with characters' => ['3AB8'], diff --git a/src/Tests/Value/PhoneNumber/InternationalPhoneNumberTest.php b/src/Tests/Value/PhoneNumber/InternationalPhoneNumberTest.php index 41c2994..5690952 100644 --- a/src/Tests/Value/PhoneNumber/InternationalPhoneNumberTest.php +++ b/src/Tests/Value/PhoneNumber/InternationalPhoneNumberTest.php @@ -30,10 +30,8 @@ class InternationalPhoneNumberTest extends UnitTest { - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function equality_is_based_on_country_code_and_phone_number_contents(): void { $base = new InternationalPhoneNumber(new CountryCode('31'), new PhoneNumber('123')); @@ -50,10 +48,8 @@ public function equality_is_based_on_country_code_and_phone_number_contents(): v $this->assertFalse($base->equals($different), 'Not equal with different Country Code and different number'); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function it_can_be_cast_to_string_and_recreated_equally_from_that_string(): void { $phoneNumber = new InternationalPhoneNumber(new CountryCode('1808'), new PhoneNumber('0612345678')); @@ -66,10 +62,8 @@ public function it_can_be_cast_to_string_and_recreated_equally_from_that_string( $this->assertTrue($phoneNumber->equals($phoneNumberFromString)); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function msisdn_representation_is_formatted_correctly_as_a_continuous_string_of_digits(): void { $phoneNumber = new InternationalPhoneNumber(new CountryCode('31'), new PhoneNumber('0612345678')); @@ -77,7 +71,7 @@ public function msisdn_representation_is_formatted_correctly_as_a_continuous_str $this->assertEquals('31612345678', $phoneNumber->toMSISDN()); } - public function invalid_types(): array + public static function invalid_types(): array { return [ 'array' => [[]], @@ -89,11 +83,9 @@ public function invalid_types(): array ]; } - /** - * @test - * @dataProvider invalid_types - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalid_types')] public function it_rejects_invalid_types(mixed $invalidType): void { $this->expectException(InvalidArgumentException::class); @@ -101,7 +93,7 @@ public function it_rejects_invalid_types(mixed $invalidType): void InternationalPhoneNumber::fromStringFormat($invalidType); } - public function invalid_phone_numbers(): array + public static function invalid_phone_numbers(): array { return [ 'garbage before phone number' => ['garbage+31 (0) 681819571'], @@ -111,11 +103,9 @@ public function invalid_phone_numbers(): array ]; } - /** - * @test - * @dataProvider invalid_phone_numbers - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalid_phone_numbers')] public function it_rejects_invalid_phone_numbers(mixed $invalidPhoneNumber): void { $this->expectException(InvalidPhoneNumberFormatException::class); diff --git a/src/Tests/Value/PhoneNumber/PhoneNumberTest.php b/src/Tests/Value/PhoneNumber/PhoneNumberTest.php index a1a39a1..f9fd298 100644 --- a/src/Tests/Value/PhoneNumber/PhoneNumberTest.php +++ b/src/Tests/Value/PhoneNumber/PhoneNumberTest.php @@ -28,11 +28,9 @@ class PhoneNumberTest extends UnitTest { - /** - * @test - * @group value - * @dataProvider invalidConstructorArgumentProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalidConstructorArgumentProvider')] public function a_phone_number_cannot_be_created_with_anything_but_a_string(mixed $invalidArgument): void { $this->expectException(InvalidArgumentException::class); @@ -40,11 +38,9 @@ public function a_phone_number_cannot_be_created_with_anything_but_a_string(mixe new PhoneNumber($invalidArgument); } - /** - * @test - * @group value - * @dataProvider invalidStringArgumentProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalidStringArgumentProvider')] public function a_phone_number_can_only_be_created_if_the_string_contains_digits_only(string $invalidArgument): void { $this->expectException(InvalidPhoneNumberFormatException::class); @@ -52,10 +48,8 @@ public function a_phone_number_can_only_be_created_if_the_string_contains_digits new PhoneNumber($invalidArgument); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function the_original_phone_number_is_returned_upon_request(): void { $original = '0612345678'; @@ -65,11 +59,9 @@ public function the_original_phone_number_is_returned_upon_request(): void $this->assertEquals($original, $phoneNumber->getNumber()); } - /** - * @test - * @group value - * @dataProvider formatAsMsisdnPartProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('formatAsMsisdnPartProvider')] public function format_as_msisdn_part_strips_exactly_one_leading_zero_if_it_has_one(string $given, string $expectedMsisdnPart): void { $phoneNumber = new PhoneNumber($given); @@ -77,10 +69,8 @@ public function format_as_msisdn_part_strips_exactly_one_leading_zero_if_it_has_ $this->assertEquals($expectedMsisdnPart, $phoneNumber->formatAsMsisdnPart()); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function phone_numbers_are_equal_if_the_given_numbers_match_as_msisdn_part(): void { $base = new PhoneNumber('0612345678'); @@ -95,11 +85,9 @@ public function phone_numbers_are_equal_if_the_given_numbers_match_as_msisdn_par $this->assertFalse($base->equals($differentWithoutLeadingZero)); } - /** - * @test - * @group value - * @dataProvider toStringProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('toStringProvider')] public function as_string_the_phone_number_is_rendered_with_a_replaced_leading_zero_between_brackets( string $given, string $expected @@ -109,7 +97,7 @@ public function as_string_the_phone_number_is_rendered_with_a_replaced_leading_z $this->assertEquals($expected, $phoneNumber->__toString()); } - public function invalidConstructorArgumentProvider(): array + public static function invalidConstructorArgumentProvider(): array { return [ 'int' => [0], @@ -121,7 +109,7 @@ public function invalidConstructorArgumentProvider(): array ]; } - public function invalidStringArgumentProvider(): array + public static function invalidStringArgumentProvider(): array { return [ 'with characters' => ['06123AB78'], @@ -132,7 +120,7 @@ public function invalidStringArgumentProvider(): array ]; } - public function formatAsMsisdnPartProvider(): array + public static function formatAsMsisdnPartProvider(): array { return [ //given, expected output 'no leading zero' => ['612345678', '612345678'], @@ -142,7 +130,7 @@ public function formatAsMsisdnPartProvider(): array ]; } - public function toStringProvider(): array + public static function toStringProvider(): array { return [ //given, expected output 'no leading zero' => ['612345678', '(0) 612345678'], diff --git a/src/Tests/Value/SecondFactorTypeTest.php b/src/Tests/Value/SecondFactorTypeTest.php index a743125..eb7da2a 100644 --- a/src/Tests/Value/SecondFactorTypeTest.php +++ b/src/Tests/Value/SecondFactorTypeTest.php @@ -26,7 +26,7 @@ final class SecondFactorTypeTest extends TestCase { - public function validTypes(): array + public static function validTypes(): array { return [ 'sms' => ['sms'], @@ -36,11 +36,9 @@ public function validTypes(): array ]; } - /** - * @test - * @group value - * @dataProvider validTypes - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('validTypes')] public function it_can_be_constructed(string $type): void { $secondFactorType = new SecondFactorType($type); @@ -48,10 +46,8 @@ public function it_can_be_constructed(string $type): void $this->assertInstanceOf(SecondFactorType::class, $secondFactorType); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function it_doesnt_accept_integers(): void { $this->expectException(InvalidArgumentException::class); @@ -59,17 +55,13 @@ public function it_doesnt_accept_integers(): void new SecondFactorType(9); } - /** - * @test - */ + #[\PHPUnit\Framework\Attributes\Test] public function its_equality_is_determined_by_its_type(): void { $this->assertTrue((new SecondFactorType('sms'))->equals(new SecondFactorType('sms'))); } - /** - * @test - */ + #[\PHPUnit\Framework\Attributes\Test] public function its_type_can_be_verified(): void { $this->assertTrue((new SecondFactorType('sms'))->isSms()); diff --git a/src/Tests/Value/YubikeyOtpTest.php b/src/Tests/Value/YubikeyOtpTest.php index 585292d..22ca5bf 100644 --- a/src/Tests/Value/YubikeyOtpTest.php +++ b/src/Tests/Value/YubikeyOtpTest.php @@ -27,7 +27,7 @@ class YubikeyOtpTest extends TestCase { - public function otpStrings(): array + public static function otpStrings(): array { return [ 'Regular OTP' => [ @@ -82,9 +82,7 @@ public function otpStrings(): array ]; } - /** - * @dataProvider otpStrings - */ + #[\PHPUnit\Framework\Attributes\DataProvider('otpStrings')] public function testItParsesFromString(string $string, string $otpString, string $password, string $publicId, string $cipherText): void { $otp = YubikeyOtp::fromString($string); @@ -95,17 +93,13 @@ public function testItParsesFromString(string $string, string $otpString, string $this->assertSame($cipherText, $otp->cipherText); } - /** - * @dataProvider otpStrings - */ + #[\PHPUnit\Framework\Attributes\DataProvider('otpStrings')] public function testItValidatesCorrectOtps(string $string): void { $this->assertTrue(YubikeyOtp::isValid($string)); } - /** - * @dataProvider nonStrings - */ + #[\PHPUnit\Framework\Attributes\DataProvider('nonStrings')] public function testItThrowsAnExceptionWhenGivenArgumentIsNotAString(mixed $nonString): void { $this->expectException(InvalidArgumentException::class); @@ -114,7 +108,7 @@ public function testItThrowsAnExceptionWhenGivenArgumentIsNotAString(mixed $nonS YubikeyOtp::fromString($nonString); } - public function nonStrings(): array + public static function nonStrings(): array { return [ 'integer' => [1], @@ -126,9 +120,7 @@ public function nonStrings(): array ]; } - /** - * @dataProvider nonOtpStrings - */ + #[\PHPUnit\Framework\Attributes\DataProvider('nonOtpStrings')] public function testItThrowsAnExceptionWhenGivenStringIsNotAnOtpString(mixed $nonOtpString): void { $this->expectException(InvalidArgumentException::class); @@ -137,15 +129,13 @@ public function testItThrowsAnExceptionWhenGivenStringIsNotAnOtpString(mixed $no YubikeyOtp::fromString($nonOtpString); } - /** - * @dataProvider nonOtpStrings - */ + #[\PHPUnit\Framework\Attributes\DataProvider('nonOtpStrings')] public function testItDoesntAcceptInvalidOtps(string $string): void { $this->assertFalse(YubikeyOtp::isValid($string)); } - public function nonOtpStrings(): array + public static function nonOtpStrings(): array { return [ 'Has invalid characters' => ['abcdefghijklmnopqrstuvwxyz123456789'], diff --git a/src/Tests/Value/YubikeyPublicIdTest.php b/src/Tests/Value/YubikeyPublicIdTest.php index 52b4994..518a546 100644 --- a/src/Tests/Value/YubikeyPublicIdTest.php +++ b/src/Tests/Value/YubikeyPublicIdTest.php @@ -21,14 +21,13 @@ namespace Surfnet\StepupBundle\Tests\Value; use PHPUnit\Framework\TestCase; -use stdClass; use Surfnet\StepupBundle\Exception\InvalidArgumentException; use Surfnet\StepupBundle\Value\YubikeyOtp; use Surfnet\StepupBundle\Value\YubikeyPublicId; final class YubikeyPublicIdTest extends TestCase { - public function invalidFormatProvider(): array + public static function invalidFormatProvider(): array { return [ '7-character unpadded ID' => ['1906381'], @@ -42,18 +41,16 @@ public function invalidFormatProvider(): array ]; } - /** - * @test - * @group value - * @dataProvider invalidFormatProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('invalidFormatProvider')] public function it_cannot_be_constructed_with_an_invalid_format(mixed $invalidFormat): void { $this->expectException(InvalidArgumentException::class); new YubikeyPublicId($invalidFormat); } - public function validFormatProvider(): array + public static function validFormatProvider(): array { return [ '8-character ID' => ['01906381'], @@ -64,11 +61,9 @@ public function validFormatProvider(): array ]; } - /** - * @test - * @group value - * @dataProvider validFormatProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('validFormatProvider')] public function its_value_matches_its_input_value(string $validFormat): void { $id = new YubikeyPublicId($validFormat); @@ -76,7 +71,7 @@ public function its_value_matches_its_input_value(string $validFormat): void $this->assertEquals($validFormat, $id->getYubikeyPublicId()); } - public function otpProvider(): array + public static function otpProvider(): array { return [ 'Maximum value' => ['vvvvvvvvvvvvvvvvbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', '18446744073709551615'], @@ -85,11 +80,9 @@ public function otpProvider(): array ]; } - /** - * @test - * @group value - * @dataProvider otpProvider - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] + #[\PHPUnit\Framework\Attributes\DataProvider('otpProvider')] public function it_accepts_valid_modhex_formats(string $otpString, string $yubikeyPublicId): void { $otp = YubikeyOtp::fromString($otpString); @@ -98,10 +91,8 @@ public function it_accepts_valid_modhex_formats(string $otpString, string $yubik $this->assertEquals($yubikeyPublicId, $id->getYubikeyPublicId()); } - /** - * @test - * @group value - */ + #[\PHPUnit\Framework\Attributes\Group('value')] + #[\PHPUnit\Framework\Attributes\Test] public function it_can_check_for_equality(): void { $id = new YubikeyPublicId('01908382'); diff --git a/src/Value/Loa.php b/src/Value/Loa.php index fb5b2fb..6e7fbc5 100644 --- a/src/Value/Loa.php +++ b/src/Value/Loa.php @@ -52,10 +52,6 @@ public function __construct(float $level, string $identifier) )); } - if (!is_string($identifier)) { - throw InvalidArgumentException::invalidType('string', 'identifier', $identifier); - } - $this->level = $level; $this->identifier = $identifier; }