diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3116f52b712..ff9522acd1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: env: COMPOSER_ALLOW_SUPERUSER: '1' # https://getcomposer.org/doc/03-cli.md#composer-allow-superuser COMPOSER_INSTALLER_COMMIT: fb22b78362d31c0d2bf516d1f8cdfd2745caa431 - COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} COVERAGE: '0' EXT_MONGODB_VERSION: '1.7.5' EXT_PCOV_VERSION: '1.0.6' @@ -251,10 +251,17 @@ jobs: - name: Install PHPUnit run: vendor/bin/simple-phpunit --version - name: Clear test app cache + if: (!startsWith(matrix.php, 'rc')) run: | mkdir -p /tmp/api-platform/core/var ln -s /tmp/api-platform/core/var tests/Fixtures/app/var tests/Fixtures/app/console cache:clear --ansi + - name: Clear test app cache (PHP 8) + if: (startsWith(matrix.php, 'rc')) + run: | + mkdir -p /tmp/api-platform/core/var + ln -s /tmp/api-platform/core/var tests/Fixtures/app/var + rm -Rf tests/Fixtures/app/var/cache/* - name: Enable code coverage if: matrix.coverage run: echo '::set-env name=COVERAGE::1' @@ -667,251 +674,6 @@ jobs: path: build/out/openapi continue-on-error: true - behat-legacy: - name: Behat (PHP ${{ matrix.php }}) (legacy) - runs-on: ubuntu-latest - container: - image: php:${{ matrix.php }}-alpine - options: >- - --tmpfs /tmp:exec - --tmpfs /var/tmp:exec - strategy: - matrix: - php: - - '7.1' - - '7.2' - - '7.3' - include: - - php: '7.3' - coverage: true - fail-fast: false - timeout-minutes: 20 - env: - LEGACY: '1' - SYMFONY_REQUIRE: '^3.4 || ^4.0' - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: Install system packages - run: | - apk add \ - bash \ - unzip \ - git openssh - - name: Cache mongodb PHP extension build - if: (!startsWith(matrix.php, '7.1')) - uses: actions/cache@v2 - with: - path: /var/tmp/build/ext-mongodb-${{ env.EXT_MONGODB_VERSION }} - key: ext-mongodb-${{ env.EXT_MONGODB_VERSION }}-php${{ matrix.php }}-${{ github.sha }} - restore-keys: | - ext-mongodb-${{ env.EXT_MONGODB_VERSION }}-php${{ matrix.php }}- - continue-on-error: true - - name: Install mongodb PHP extension - if: (!startsWith(matrix.php, '7.1')) - env: - BUILD_DIR: /var/tmp/build/ext-mongodb-${{ env.EXT_MONGODB_VERSION }} - SRC_DIR: /usr/src/php/ext/mongodb - run: | - apk add \ - $PHPIZE_DEPS - mkdir -p "$SRC_DIR" "$BUILD_DIR" - cd "$SRC_DIR" - curl -fsSL "https://pecl.php.net/get/mongodb-$EXT_MONGODB_VERSION.tgz" | tar -zx --strip-components 1 - phpize - cd "$BUILD_DIR" - "$SRC_DIR"/configure --config-cache - make -j"$(nproc)" - make -j"$(nproc)" install - docker-php-ext-enable mongodb - - name: Install pcov PHP extension - if: matrix.coverage - env: - BUILD_DIR: /var/tmp/build/ext-pcov-${{ env.EXT_PCOV_VERSION }} - SRC_DIR: /usr/src/php/ext/pcov - run: | - apk add \ - $PHPIZE_DEPS - mkdir -p "$SRC_DIR" "$BUILD_DIR" - cd "$SRC_DIR" - curl -fsSL "https://pecl.php.net/get/pcov-$EXT_PCOV_VERSION.tgz" | tar -zx --strip-components 1 - phpize - cd "$BUILD_DIR" - "$SRC_DIR"/configure --config-cache - make -j"$(nproc)" - make -j"$(nproc)" install - docker-php-ext-enable pcov - - name: Disable PHP memory limit - run: echo 'memory_limit=-1' >> /usr/local/etc/php/php.ini - - name: Install Composer - run: wget -qO - https://raw.githubusercontent.com/composer/getcomposer.org/$COMPOSER_INSTALLER_COMMIT/web/installer | php -- --install-dir=/usr/local/bin --filename=composer --quiet - - name: Cache Composer packages - uses: actions/cache@v2 - with: - path: ~/.composer/cache - key: composer-php${{ matrix.php }}-legacy-${{ github.sha }} - restore-keys: | - composer-php${{ matrix.php }}-legacy- - composer-php${{ matrix.php }}- - composer- - continue-on-error: true - - name: Install Symfony Flex - run: | - composer global require --prefer-dist --no-progress --no-suggest --ansi \ - symfony/flex - - name: Remove Doctrine MongoDB ODM - if: startsWith(matrix.php, '7.1') - run: | - composer remove --dev --no-progress --no-update --ansi \ - doctrine/mongodb-odm \ - doctrine/mongodb-odm-bundle \ - - name: Update project dependencies - run: | - mkdir -p /tmp/api-platform/core/vendor - ln -s /tmp/api-platform/core/vendor vendor - composer update --no-progress --no-suggest --ansi - - name: Install PHPUnit - run: vendor/bin/simple-phpunit --version - - name: Clear test app cache - run: | - mkdir -p /tmp/api-platform/core/var - ln -s /tmp/api-platform/core/var tests/Fixtures/app/var - tests/Fixtures/app/console cache:clear --ansi - - name: Enable code coverage - if: matrix.coverage - run: echo '::set-env name=COVERAGE::1' - - name: Run Behat tests - run: | - mkdir -p build/logs/behat - if [ "$COVERAGE" = '1' ]; then - vendor/bin/behat --format=progress --out=std --format=junit --out=build/logs/behat/junit --profile=default-legacy-coverage --no-interaction --colors - else - vendor/bin/behat --format=progress --out=std --format=junit --out=build/logs/behat/junit --profile=default-legacy --no-interaction --colors - fi - - name: Merge code coverage reports - if: matrix.coverage - run: | - wget -qO /usr/local/bin/phpcov https://phar.phpunit.de/phpcov.phar - chmod +x /usr/local/bin/phpcov - phpcov merge --clover build/logs/behat/clover.xml build/coverage - continue-on-error: true - - name: Upload test artifacts - if: always() - uses: actions/upload-artifact@v1 - with: - name: behat-logs-php${{ matrix.php }}-legacy - path: build/logs/behat - continue-on-error: true - - name: Upload coverage results to Codecov - if: matrix.coverage - uses: codecov/codecov-action@v1 - with: - name: behat-php${{ matrix.php }}-legacy - flags: behat_legacy - fail_ci_if_error: true - continue-on-error: true - - name: Upload coverage results to Coveralls - if: matrix.coverage - env: - COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - composer global require --prefer-dist --no-progress --no-suggest --ansi cedx/coveralls - export PATH="$PATH:$HOME/.composer/vendor/bin" - coveralls build/logs/behat/clover.xml - continue-on-error: true - - behat-lowest-deps-legacy: - name: Behat (PHP ${{ matrix.php }}) (lowest dependencies) (legacy) - runs-on: ubuntu-latest - container: - image: php:${{ matrix.php }}-alpine - options: >- - --tmpfs /tmp:exec - --tmpfs /var/tmp:exec - strategy: - matrix: - php: - - '7.3' - fail-fast: false - timeout-minutes: 20 - env: - LEGACY: '1' - SYMFONY_REQUIRE: '^3.4 || ^4.0' - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: Install system packages - run: | - apk add \ - unzip \ - git openssh - - name: Cache mongodb PHP extension build - uses: actions/cache@v2 - with: - path: /var/tmp/build/ext-mongodb-${{ env.EXT_MONGODB_VERSION }} - key: ext-mongodb-${{ env.EXT_MONGODB_VERSION }}-php${{ matrix.php }}-${{ github.sha }} - restore-keys: | - ext-mongodb-${{ env.EXT_MONGODB_VERSION }}-php${{ matrix.php }}- - continue-on-error: true - - name: Install mongodb PHP extension - env: - BUILD_DIR: /var/tmp/build/ext-mongodb-${{ env.EXT_MONGODB_VERSION }} - SRC_DIR: /usr/src/php/ext/mongodb - run: | - apk add \ - $PHPIZE_DEPS - mkdir -p "$SRC_DIR" "$BUILD_DIR" - cd "$SRC_DIR" - curl -fsSL "https://pecl.php.net/get/mongodb-$EXT_MONGODB_VERSION.tgz" | tar -zx --strip-components 1 - phpize - cd "$BUILD_DIR" - "$SRC_DIR"/configure --config-cache - make -j"$(nproc)" - make -j"$(nproc)" install - docker-php-ext-enable mongodb - - name: Disable PHP memory limit - run: echo 'memory_limit=-1' >> /usr/local/etc/php/php.ini - - name: Install Composer - run: wget -qO - https://raw.githubusercontent.com/composer/getcomposer.org/$COMPOSER_INSTALLER_COMMIT/web/installer | php -- --install-dir=/usr/local/bin --filename=composer --quiet - - name: Cache Composer packages - uses: actions/cache@v2 - with: - path: ~/.composer/cache - key: composer-php${{ matrix.php }}-lowest-deps-legacy-${{ github.sha }} - restore-keys: | - composer-php${{ matrix.php }}-lowest-deps-legacy- - composer-php${{ matrix.php }}-lowest-deps- - composer-php${{ matrix.php }}- - composer- - continue-on-error: true - - name: Install Symfony Flex - run: | - composer global require --prefer-dist --no-progress --no-suggest --ansi \ - symfony/flex - - name: Update project dependencies - run: | - mkdir -p /tmp/api-platform/core/vendor - ln -s /tmp/api-platform/core/vendor vendor - composer update --no-progress --no-suggest --prefer-stable --prefer-lowest --ansi - - name: Install PHPUnit - run: vendor/bin/simple-phpunit --version - - name: Clear test app cache - run: | - mkdir -p /tmp/api-platform/core/var - ln -s /tmp/api-platform/core/var tests/Fixtures/app/var - tests/Fixtures/app/console cache:clear --ansi - - name: Run Behat tests - run: | - mkdir -p build/logs/behat - vendor/bin/behat --format=progress --out=std --format=junit --out=build/logs/behat/junit --profile=default-legacy --no-interaction --colors - - name: Upload test artifacts - if: always() - uses: actions/upload-artifact@v1 - with: - name: behat-logs-php${{ matrix.php }}-lowest-deps-legacy - path: build/logs/behat - continue-on-error: true - phpunit-postgresql: name: PHPUnit (PHP ${{ matrix.php }}) (PostgreSQL) runs-on: ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb2f1ec3a54..cc6e77496e0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,6 @@ When you send a PR, just make sure that: * You make the PR on the same branch you based your changes on. If you see commits that you did not make in your PR, you're doing it wrong. * Also don't forget to add a comment when you update a PR with a ping to [the maintainers](https://github.com/orgs/api-platform/people), so he/she will get a notification. -* Squash your commits into one commit (see the next chapter). All Pull Requests must include [this header](.github/PULL_REQUEST_TEMPLATE.md). @@ -105,28 +104,6 @@ If you want to launch Behat tests for MongoDB, the command is: To get more details about an error, replace `--format=progress` by `-vvv`. -## Squash your Commits - -If you have 3 commits, start with: - - git rebase -i HEAD~3 - -An editor will be opened with your 3 commits, all prefixed by `pick`. - -Replace all `pick` prefixes by `fixup` (or `f`) **except the first commit** of the list. - -Save and quit the editor. - -After that, all your commits will be squashed into the first one and the commit message will be the first one. - -If you would like to rename your commit message, type: - - git commit --amend - -Now force push to update your PR: - - git push --force-with-lease - # License and Copyright Attribution When you open a Pull Request to the API Platform project, you agree to license your code under the [MIT license](LICENSE) diff --git a/behat.yml.dist b/behat.yml.dist index 781a5c47882..72a33b5ac06 100644 --- a/behat.yml.dist +++ b/behat.yml.dist @@ -2,37 +2,33 @@ default: suites: default: contexts: - - 'CommandContext' - - 'DoctrineContext': - doctrine: '@doctrine' - passwordEncoder: '@security.password_encoder' - - 'GraphqlContext' - - 'JsonContext' - - 'HydraContext' - - 'SwaggerContext' - - 'HttpCacheContext' - - 'JsonApiContext': - doctrine: '@doctrine' - jsonApiSchemaFile: '%paths.base%/tests/Fixtures/JsonSchema/jsonapi.json' - - 'JsonHalContext': - schemaFile: '%paths.base%/tests/Fixtures/JsonHal/jsonhal.json' + - 'ApiPlatform\Core\Tests\Behat\CommandContext' + - 'ApiPlatform\Core\Tests\Behat\DoctrineContext' + - 'ApiPlatform\Core\Tests\Behat\GraphqlContext' + - 'ApiPlatform\Core\Tests\Behat\JsonContext' + - 'ApiPlatform\Core\Tests\Behat\HydraContext' + - 'ApiPlatform\Core\Tests\Behat\OpenApiContext' + - 'ApiPlatform\Core\Tests\Behat\HttpCacheContext' + - 'ApiPlatform\Core\Tests\Behat\JsonApiContext' + - 'ApiPlatform\Core\Tests\Behat\JsonHalContext' - 'Behat\MinkExtension\Context\MinkContext' - - 'Behatch\Context\RestContext' + - 'behatch:context:rest' filters: - tags: '~@postgres&&~@mongodb&&~@elasticsearch&&~@legacy' + tags: '~@postgres&&~@mongodb&&~@elasticsearch' extensions: - 'Behat\Symfony2Extension': + 'FriendsOfBehat\SymfonyExtension': + bootstrap: 'tests/Fixtures/app/bootstrap.php' kernel: - env: 'test' - debug: 'true' + environment: 'test' + debug: true + class: AppKernel path: 'tests/Fixtures/app/AppKernel.php' - bootstrap: 'tests/Fixtures/app/bootstrap.php' 'Behat\MinkExtension': base_url: 'http://example.com/' files_path: 'features/files' sessions: default: - symfony2: ~ + symfony: ~ 'Behatch\Extension': ~ postgres: @@ -40,48 +36,38 @@ postgres: default: false postgres: &postgres-suite contexts: - - 'CommandContext' - - 'DoctrineContext': - doctrine: '@doctrine' - passwordEncoder: '@security.password_encoder' - - 'GraphqlContext' - - 'JsonContext' - - 'HydraContext' - - 'SwaggerContext' - - 'HttpCacheContext' - - 'JsonApiContext': - doctrine: '@doctrine' - jsonApiSchemaFile: '%paths.base%/tests/Fixtures/JsonSchema/jsonapi.json' - - 'JsonHalContext': - schemaFile: '%paths.base%/tests/Fixtures/JsonHal/jsonhal.json' + - 'ApiPlatform\Core\Tests\Behat\CommandContext' + - 'ApiPlatform\Core\Tests\Behat\DoctrineContext' + - 'ApiPlatform\Core\Tests\Behat\GraphqlContext' + - 'ApiPlatform\Core\Tests\Behat\JsonContext' + - 'ApiPlatform\Core\Tests\Behat\HydraContext' + - 'ApiPlatform\Core\Tests\Behat\OpenApiContext' + - 'ApiPlatform\Core\Tests\Behat\HttpCacheContext' + - 'ApiPlatform\Core\Tests\Behat\JsonApiContext' + - 'ApiPlatform\Core\Tests\Behat\JsonHalContext' - 'Behat\MinkExtension\Context\MinkContext' - - 'Behatch\Context\RestContext' + - 'behatch:context:rest' filters: - tags: '~@sqlite&&~@mongodb&&~@elasticsearch&&~@legacy' + tags: '~@sqlite&&~@mongodb&&~@elasticsearch' mongodb: suites: default: false mongodb: &mongodb-suite contexts: - - 'CommandContext' - - 'DoctrineContext': - doctrine: '@doctrine_mongodb' - passwordEncoder: '@security.password_encoder' - - 'GraphqlContext' - - 'JsonContext' - - 'HydraContext' - - 'SwaggerContext' - - 'HttpCacheContext' - - 'JsonApiContext': - doctrine: '@doctrine_mongodb' - jsonApiSchemaFile: '%paths.base%/tests/Fixtures/JsonSchema/jsonapi.json' - - 'JsonHalContext': - schemaFile: '%paths.base%/tests/Fixtures/JsonHal/jsonhal.json' + - 'ApiPlatform\Core\Tests\Behat\CommandContext' + - 'ApiPlatform\Core\Tests\Behat\DoctrineContext' + - 'ApiPlatform\Core\Tests\Behat\GraphqlContext' + - 'ApiPlatform\Core\Tests\Behat\JsonContext' + - 'ApiPlatform\Core\Tests\Behat\HydraContext' + - 'ApiPlatform\Core\Tests\Behat\OpenApiContext' + - 'ApiPlatform\Core\Tests\Behat\HttpCacheContext' + - 'ApiPlatform\Core\Tests\Behat\JsonApiContext' + - 'ApiPlatform\Core\Tests\Behat\JsonHalContext' - 'Behat\MinkExtension\Context\MinkContext' - - 'Behatch\Context\RestContext' + - 'behatch:context:rest' filters: - tags: '~@sqlite&&~@elasticsearch&&~@!mongodb&&~@legacy' + tags: '~@sqlite&&~@elasticsearch&&~@!mongodb&&' elasticsearch: suites: @@ -90,38 +76,30 @@ elasticsearch: paths: - '%paths.base%/features/elasticsearch' contexts: - - 'CommandContext' - - 'ElasticsearchContext': - client: '@test.api_platform.elasticsearch.client' - elasticsearchMappingsPath: '%paths.base%/tests/Fixtures/Elasticsearch/Mappings/' - elasticsearchFixturesPath: '%paths.base%/tests/Fixtures/Elasticsearch/Fixtures/' - - 'JsonContext' - - 'Behatch\Context\RestContext' + - 'ApiPlatform\Core\Tests\Behat\CommandContext' + - 'ApiPlatform\Core\Tests\Behat\ElasticsearchContext' + - 'ApiPlatform\Core\Tests\Behat\JsonContext' - 'Behat\MinkExtension\Context\MinkContext' + - 'behatch:context:rest' filters: - tags: '@elasticsearch&&~@legacy' + tags: '@elasticsearch' default-coverage: suites: default: &default-coverage-suite contexts: - - 'CommandContext' - - 'DoctrineContext': - doctrine: '@doctrine' - passwordEncoder: '@security.password_encoder' - - 'GraphqlContext' - - 'JsonContext' - - 'HydraContext' - - 'SwaggerContext' - - 'HttpCacheContext' - - 'JsonApiContext': - doctrine: '@doctrine' - jsonApiSchemaFile: '%paths.base%/tests/Fixtures/JsonSchema/jsonapi.json' - - 'JsonHalContext': - schemaFile: '%paths.base%/tests/Fixtures/JsonHal/jsonhal.json' - - 'CoverageContext' + - 'ApiPlatform\Core\Tests\Behat\CommandContext' + - 'ApiPlatform\Core\Tests\Behat\DoctrineContext' + - 'ApiPlatform\Core\Tests\Behat\GraphqlContext' + - 'ApiPlatform\Core\Tests\Behat\JsonContext' + - 'ApiPlatform\Core\Tests\Behat\HydraContext' + - 'ApiPlatform\Core\Tests\Behat\OpenApiContext' + - 'ApiPlatform\Core\Tests\Behat\HttpCacheContext' + - 'ApiPlatform\Core\Tests\Behat\JsonApiContext' + - 'ApiPlatform\Core\Tests\Behat\JsonHalContext' + - 'ApiPlatform\Core\Tests\Behat\CoverageContext' - 'Behat\MinkExtension\Context\MinkContext' - - 'Behatch\Context\RestContext' + - 'behatch:context:rest' mongodb-coverage: suites: @@ -129,23 +107,18 @@ mongodb-coverage: mongodb: &mongodb-coverage-suite <<: *mongodb-suite contexts: - - 'CommandContext' - - 'DoctrineContext': - doctrine: '@doctrine_mongodb' - passwordEncoder: '@security.password_encoder' - - 'GraphqlContext' - - 'JsonContext' - - 'HydraContext' - - 'SwaggerContext' - - 'HttpCacheContext' - - 'JsonApiContext': - doctrine: '@doctrine_mongodb' - jsonApiSchemaFile: '%paths.base%/tests/Fixtures/JsonSchema/jsonapi.json' - - 'JsonHalContext': - schemaFile: '%paths.base%/tests/Fixtures/JsonHal/jsonhal.json' - - 'CoverageContext' + - 'ApiPlatform\Core\Tests\Behat\CommandContext' + - 'ApiPlatform\Core\Tests\Behat\DoctrineContext' + - 'ApiPlatform\Core\Tests\Behat\GraphqlContext' + - 'ApiPlatform\Core\Tests\Behat\JsonContext' + - 'ApiPlatform\Core\Tests\Behat\HydraContext' + - 'ApiPlatform\Core\Tests\Behat\OpenApiContext' + - 'ApiPlatform\Core\Tests\Behat\HttpCacheContext' + - 'ApiPlatform\Core\Tests\Behat\JsonApiContext' + - 'ApiPlatform\Core\Tests\Behat\JsonHalContext' + - 'ApiPlatform\Core\Tests\Behat\CoverageContext' - 'Behat\MinkExtension\Context\MinkContext' - - 'Behatch\Context\RestContext' + - 'behatch:context:rest' elasticsearch-coverage: suites: @@ -153,25 +126,9 @@ elasticsearch-coverage: elasticsearch: &elasticsearch-coverage-suite <<: *elasticsearch-suite contexts: - - 'CommandContext' - - 'ElasticsearchContext': - client: '@test.api_platform.elasticsearch.client' - elasticsearchMappingsPath: '%paths.base%/tests/Fixtures/Elasticsearch/Mappings/' - elasticsearchFixturesPath: '%paths.base%/tests/Fixtures/Elasticsearch/Fixtures/' - - 'JsonContext' - - 'CoverageContext' - - 'Behatch\Context\RestContext' + - 'ApiPlatform\Core\Tests\Behat\CommandContext' + - 'ApiPlatform\Core\Tests\Behat\ElasticsearchContext' + - 'ApiPlatform\Core\Tests\Behat\JsonContext' + - 'ApiPlatform\Core\Tests\Behat\CoverageContext' - 'Behat\MinkExtension\Context\MinkContext' - -default-legacy: - suites: - default: - filters: - tags: '~@postgres&&~@mongodb&&~@elasticsearch' - -default-legacy-coverage: - suites: - default: - <<: *default-coverage-suite - filters: - tags: '~@postgres&&~@mongodb&&~@elasticsearch' + - 'behatch:context:rest' diff --git a/composer.json b/composer.json index c459bf72afa..54dda7e0795 100644 --- a/composer.json +++ b/composer.json @@ -18,12 +18,12 @@ "fig/link-util": "^1.0", "psr/cache": "^1.0", "psr/container": "^1.0", - "symfony/http-foundation": "^4.3.6 || ^5.0", - "symfony/http-kernel": "^4.3.7 || ^5.0", - "symfony/property-access": "^3.4 || ^4.0 || ^5.0", - "symfony/property-info": "^3.4 || ^4.0 || ^5.0", - "symfony/serializer": "^4.3 || ^5.0", - "symfony/web-link": "^4.1 || ^5.0", + "symfony/http-foundation": "^4.4 || ^5.1", + "symfony/http-kernel": "^4.4 || ^5.1", + "symfony/property-access": "^3.4.19 || ^4.4 || ^5.1", + "symfony/property-info": "^3.4 || ^4.4 || ^5.1", + "symfony/serializer": "^4.4 || ^5.1", + "symfony/web-link": "^4.4 || ^5.1", "willdurand/negotiation": "^2.0.3 || 3.0.x-dev" }, "require-dev": { @@ -31,60 +31,57 @@ "behat/mink": "^1.7", "friends-of-behat/mink-browserkit-driver": "^1.3.1", "friends-of-behat/mink-extension": "^2.2", - "behat/symfony2-extension": "^2.1.1", - "behatch/contexts": "dev-fix/symfony-33393", + "friends-of-behat/symfony-extension": "^2.1", + "behatch/contexts": "dev-api-platform", "doctrine/annotations": "^1.7", - "doctrine/common": "^2.11", + "doctrine/common": "^2.11 || ^3.0", "doctrine/data-fixtures": "^1.2.2", - "doctrine/doctrine-bundle": "^1.8 || ^2.0", - "doctrine/doctrine-cache-bundle": "^1.3.5", + "doctrine/doctrine-bundle": "^1.12 || ^2.0", "doctrine/mongodb-odm": "^2.0", "doctrine/mongodb-odm-bundle": "^4.0", - "doctrine/orm": "^2.6.4", - "elasticsearch/elasticsearch": "^6.0", - "friendsofsymfony/user-bundle": "2.2.x-dev#157b53bd7d6c347148a90e723981a43f9c897bf5", - "guzzlehttp/guzzle": "^6.0", - "jangregor/phpstan-prophecy": "^0.6", + "doctrine/orm": "^2.6.4 || ^3.0", + "elasticsearch/elasticsearch": "^6.0 || ^7.0", + "guzzlehttp/guzzle": "^6.0 || ^7.0", + "jangregor/phpstan-prophecy": "^0.8", "justinrainbow/json-schema": "^5.2.1", - "nelmio/api-doc-bundle": "^2.13.4", - "phpdocumentor/reflection-docblock": "^3.0 || ^4.0 || ^5.0", - "phpdocumentor/type-resolver": "^0.3 || ^0.4 || ^1.0", + "phpdocumentor/reflection-docblock": "^3.0 || ^4.0 || ^5.1", + "phpdocumentor/type-resolver": "^0.3 || ^0.4 || ^1.4", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.4", + "phpstan/phpstan": "^0.12.53@dev", "phpstan/phpstan-doctrine": "^0.12.7", "phpstan/phpstan-phpunit": "^0.12.4", "phpstan/phpstan-symfony": "^0.12.4", "psr/log": "^1.0", - "ramsey/uuid": "^3.7", + "ramsey/uuid": "^3.7 || ^4.0", "ramsey/uuid-doctrine": "^1.4", - "symfony/asset": "^3.4 || ^4.0 || ^5.0", - "symfony/browser-kit": "^4.3 || ^5.0", - "symfony/cache": "^3.4 || ^4.0 || ^5.0", - "symfony/config": "^3.4 || ^4.0 || ^5.0", - "symfony/console": "^3.4 || ^4.0 || ^5.0", - "symfony/css-selector": "^3.4 || ^4.0 || ^5.0", - "symfony/debug": "^3.4 || ^4.0", - "symfony/dependency-injection": "^3.4 || ^4.0 || ^5.0", - "symfony/doctrine-bridge": "^3.4 || ^4.0 || ^5.0", - "symfony/dom-crawler": "^3.4 || ^4.0 || ^5.0", - "symfony/event-dispatcher": "^3.4 || ^4.0 || ^5.0", - "symfony/expression-language": "^3.4 || ^4.0 || ^5.0", - "symfony/finder": "^3.4 || ^4.0 || ^5.0", - "symfony/form": "^3.4 || ^4.0 || ^5.0", - "symfony/framework-bundle": "^4.3.2 || ^5.0", - "symfony/http-client": "^4.3 || ^5.0", + "soyuka/stubs-mongodb": "^1.0", + "symfony/asset": "^3.4 || ^4.4 || ^5.1", + "symfony/browser-kit": "^4.4 || ^5.1", + "symfony/cache": "^3.4 || ^4.4 || ^5.1", + "symfony/config": "^3.4 || ^4.4 || ^5.1", + "symfony/console": "^3.4 || ^4.4 || ^5.1", + "symfony/css-selector": "^3.4 || ^4.4 || ^5.1", + "symfony/debug": "^3.4 || ^4.4 || ^5.1", + "symfony/dependency-injection": "^3.4 || ^4.4 || ^5.1", + "symfony/doctrine-bridge": "^3.4 || ^4.4 || ^5.1", + "symfony/dom-crawler": "^3.4 || ^4.4 || ^5.1", + "symfony/event-dispatcher": "^3.4 || ^4.4 || ^5.1", + "symfony/expression-language": "^3.4 || ^4.4 || ^5.1", + "symfony/finder": "^3.4 || ^4.4 || ^5.1", + "symfony/form": "^3.4 || ^4.4 || ^5.1", + "symfony/framework-bundle": "^4.4 || ^5.1", + "symfony/http-client": "^4.4 || ^5.1", "symfony/mercure-bundle": "*", - "symfony/messenger": "^4.3 || ^5.0", + "symfony/messenger": "^4.4 || ^5.1", "symfony/phpunit-bridge": "^5.1.7", - "symfony/routing": "^3.4 || ^4.3 || ^5.0", - "symfony/security-bundle": "^3.4 || ^4.0 || ^5.0", - "symfony/security-core": "^4.3 || ^5.0", - "symfony/twig-bundle": "^3.4 || ^4.0 || ^5.0", - "symfony/validator": "^3.4 || ^4.0 || ^5.0", - "symfony/web-profiler-bundle": "^4.2 || ^5.0", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0", - "teohhanhui/stubs-mongodb": "@dev", - "twig/twig": "^1.42.3 || ^2.12", + "symfony/routing": "^3.4 || ^4.4 || ^5.1", + "symfony/security-bundle": "^3.4 || ^4.4 || ^5.1", + "symfony/security-core": "^4.4 || ^5.1", + "symfony/twig-bundle": "^3.4 || ^4.4 || ^5.1", + "symfony/validator": "^3.4 || ^4.4 || ^5.1", + "symfony/web-profiler-bundle": "^4.4 || ^5.1", + "symfony/yaml": "^3.4 || ^4.4 || ^5.1", + "twig/twig": "^1.42.3 || ^2.12 || ^3.0", "webonyx/graphql-php": "^14.0" }, "conflict": { @@ -118,10 +115,6 @@ } }, "repositories": [ - { - "type": "vcs", - "url": "https://github.com/teohhanhui/stubs-mongodb" - }, { "type": "vcs", "url": "https://github.com/dunglas/contexts" @@ -138,7 +131,7 @@ "dev-master": "2.5.x-dev" }, "symfony": { - "require": "^3.4 || ^4.0 || ^5.0" + "require": "^3.4 || ^4.4 || ^5.1" } } } diff --git a/features/legacy/fos_user.feature b/features/legacy/fos_user.feature deleted file mode 100644 index c665839303c..00000000000 --- a/features/legacy/fos_user.feature +++ /dev/null @@ -1,37 +0,0 @@ -@legacy -Feature: FOSUser integration - In order to use FOSUserBundle - As an API software developer - I need to be able manage users - - @createSchema - Scenario: Create a user - When I add "Content-Type" header equal to "application/ld+json" - And I send a "POST" request to "/users" with body: - """ - { - "fullname": "Dummy User", - "username": "dummy.user", - "email": "dummy.user@example.com", - "plainPassword": "azerty" - } - """ - Then the response status code should be 201 - And the response should be in JSON - And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8" - And the JSON should be equal to: - """ - { - "@context": "/contexts/User", - "@id": "/users/1", - "@type": "User", - "email": "dummy.user@example.com", - "fullname": "Dummy User", - "username": "dummy.user" - } - """ - And the password "azerty" for user 1 should be hashed - - Scenario: Delete a user - When I send a "DELETE" request to "/users/1" - Then the response status code should be 204 diff --git a/features/legacy/nelmio_api_doc.feature b/features/legacy/nelmio_api_doc.feature deleted file mode 100644 index 846547c2169..00000000000 --- a/features/legacy/nelmio_api_doc.feature +++ /dev/null @@ -1,17 +0,0 @@ -@legacy -Feature: NelmioApiDoc integration - In order to use NelmioApiDocBundle - As an API software developer - I need to see the generated documentation - - Scenario: Test if the NelmioApiDoc integration works - When I send a "GET" request to "/nelmioapidoc" - Then the response status code should be 200 - And I should see text matching "AbstractDummy" - And I should see text matching "Dummy" - And I should see text matching "User" - And I should see text matching "Retrieves the collection of Dummy resources." - And I should see text matching "Creates a Dummy resource." - And I should see text matching "Deletes the Dummy resource." - And I should see text matching "Updates the Dummy resource." - And I should see text matching "Replaces the Dummy resource." diff --git a/phpstan.neon.dist b/phpstan.neon.dist index aefdb545835..86461c1a5d0 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,7 +6,7 @@ parameters: - tests/Fixtures/app/console inferPrivatePropertyTypeFromConstructor: true symfony: - container_xml_path: tests/Fixtures/app/var/cache/test/appAppKernelTestDebugContainer.xml + container_xml_path: tests/Fixtures/app/var/cache/test/AppKernelTestDebugContainer.xml constant_hassers: false bootstrapFiles: - vendor/bin/.phpunit/phpunit/vendor/autoload.php @@ -14,7 +14,14 @@ parameters: - src/Bridge/Symfony/Bundle/Test/Constraint/ArraySubset.php - tests/Fixtures/app/AppKernel.php excludes_analyse: + # Symfony cache - tests/Fixtures/app/var/cache + # Deprecated integrations (will be removed in API Platform 3) + - src/Bridge/NelmioApiDoc/* + - tests/Bridge/NelmioApiDoc/* + - src/Bridge/FosUser/* + # BC layer + - tests/Fixtures/TestBundle/BrowserKit/Client.php # The Symfony Configuration API isn't good enough to be analysed - src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php # Phpstan runs on phpunit > 9, a signature changed in this file @@ -29,10 +36,6 @@ parameters: ignoreErrors: # Real problems, hard to fix - '#Parameter \#2 \$dqlPart of method Doctrine\\ORM\\QueryBuilder::add\(\) expects array\|object, string given\.#' - - - message: '#Return type \(mixed\) of method ApiPlatform\\Core\\Identifier\\Normalizer\\IntegerDenormalizer::denormalize\(\) should be compatible with return type \(array\|object\) of method Symfony\\Component\\Serializer\\Normalizer\\DenormalizerInterface::denormalize\(\)#' - path: src/Identifier/Normalizer/IntegerDenormalizer.php - # False positives - message: '#Strict comparison using !== between .+ and .+ will always evaluate to false\.#' @@ -52,10 +55,6 @@ parameters: - message: '#Call to an undefined method Negotiation\\AcceptHeader::getType\(\)\.#' path: src/EventListener/AddFormatListener.php - # https://github.com/symfony/symfony/issues/31814#issuecomment-498749590 - - - message: '#Call to an undefined method Symfony\\Component\\Security\\Core\\Role\\RoleHierarchyInterface::getReachableRoles\(\)\.#' - path: src/Security/ResourceAccessChecker.php - '#Parameter \#1 \$vars of class GraphQL\\Language\\AST\\(IntValue|ObjectField|ObjectValue|BooleanValue|ListValue|StringValue)Node constructor expects array, array given\.#' - '#Parameter \#1 \$defaultContext of class Symfony\\Component\\Serializer\\Encoder\\Json(De|En)code constructor expects array, (int|true) given\.#' - '#Parameter \#(2|3) \$(resourceMetadataFactory|pagination) of class ApiPlatform\\Core\\Bridge\\Doctrine\\Orm\\Extension\\PaginationExtension constructor expects (ApiPlatform\\Core\\Metadata\\Resource\\Factory\\ResourceMetadataFactoryInterface\|Symfony\\Component\\HttpFoundation\\RequestStack|ApiPlatform\\Core\\DataProvider\\Pagination\|ApiPlatform\\Core\\Metadata\\Resource\\Factory\\ResourceMetadataFactoryInterface), stdClass given\.#' @@ -63,7 +62,6 @@ parameters: message: '#Parameter \#[0-9] \$filterLocator of class .+ constructor expects ApiPlatform\\Core\\Api\\FilterCollection|Psr\\Container\\ContainerInterface, ArrayObject given\.#' paths: - tests/Bridge/Doctrine/Orm/Extension/FilterExtensionTest.php - - tests/Bridge/NelmioApiDoc/Extractor/AnnotationsProvider/ApiPlatformProviderTest.php - tests/Hydra/Serializer/CollectionFiltersNormalizerTest.php - tests/Swagger/Serializer/DocumentationNormalizerV2Test.php - tests/Swagger/Serializer/DocumentationNormalizerV3Test.php @@ -121,7 +119,6 @@ parameters: - message: "#Call to function method_exists\\(\\) with ApiPlatform\\\\Core\\\\JsonApi\\\\Serializer\\\\ItemNormalizer and 'setCircularReferenc…' will always evaluate to false\\.#" path: tests/JsonApi/Serializer/ItemNormalizerTest.php - # Waiting to be fixed by https://github.com/Roave/BetterReflection/issues/663 - message: '#Call to private method getNestedFieldPath\(\) of class ApiPlatform\\Core\\Bridge\\Elasticsearch\\DataProvider\\Filter\\AbstractFilter\.#' diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 22df90c7d87..a24d73d3f0f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -32,6 +32,8 @@ features tests vendor + src/Bridge/NelmioApiDoc + src/Bridge/FosUser src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php diff --git a/phpunit_mongodb.xml b/phpunit_mongodb.xml index 051f8f9e583..0ef9e7e4d5b 100644 --- a/phpunit_mongodb.xml +++ b/phpunit_mongodb.xml @@ -29,6 +29,7 @@ features tests vendor + src/Bridge/NelmioApiDoc src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php diff --git a/src/Bridge/Symfony/Bundle/CacheWarmer/CachePoolClearerCacheWarmer.php b/src/Bridge/Symfony/Bundle/CacheWarmer/CachePoolClearerCacheWarmer.php index 6cb59ecb51d..497e5821aa1 100644 --- a/src/Bridge/Symfony/Bundle/CacheWarmer/CachePoolClearerCacheWarmer.php +++ b/src/Bridge/Symfony/Bundle/CacheWarmer/CachePoolClearerCacheWarmer.php @@ -37,13 +37,15 @@ public function __construct(Psr6CacheClearer $poolClearer, array $pools = []) /** * {@inheritdoc} */ - public function warmUp($cacheDirectory): void + public function warmUp($cacheDirectory) { foreach ($this->pools as $pool) { if ($this->poolClearer->hasPool($pool)) { $this->poolClearer->clearPool($pool); } } + + return []; } /** diff --git a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php index b07b99e2b51..b9c3b38812f 100644 --- a/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php +++ b/src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php @@ -107,7 +107,11 @@ public function getConfigTreeBuilder() ->booleanNode('force_eager')->defaultTrue()->info('Force join on every relation. If disabled, it will only join relations having the EAGER fetch mode.')->end() ->end() ->end() - ->booleanNode('enable_fos_user')->defaultValue(class_exists(FOSUserBundle::class))->info('Enable the FOSUserBundle integration.')->end() + ->booleanNode('enable_fos_user') + ->defaultValue(class_exists(FOSUserBundle::class)) + ->setDeprecated(...$this->buildDeprecationArgs('2.5', 'FOSUserBundle is not actively maintained anymore. Enabling the FOSUserBundle integration has been deprecated in 2.5 and will be removed in 3.0.')) + ->info('Enable the FOSUserBundle integration.') + ->end() ->booleanNode('enable_nelmio_api_doc') ->defaultFalse() ->setDeprecated(...$this->buildDeprecationArgs('2.2', 'Enabling the NelmioApiDocBundle integration has been deprecated in 2.2 and will be removed in 3.0. NelmioApiDocBundle 3 has native support for API Platform.')) diff --git a/src/Bridge/Symfony/Validator/EventListener/ValidationExceptionListener.php b/src/Bridge/Symfony/Validator/EventListener/ValidationExceptionListener.php index 7d9e45cd348..5f72211c5e5 100644 --- a/src/Bridge/Symfony/Validator/EventListener/ValidationExceptionListener.php +++ b/src/Bridge/Symfony/Validator/EventListener/ValidationExceptionListener.php @@ -40,7 +40,7 @@ public function __construct(SerializerInterface $serializer, array $errorFormats */ public function onKernelException(ExceptionEvent $event): void { - $exception = method_exists($event, 'getThrowable') ? $event->getThrowable() : $event->getException(); + $exception = method_exists($event, 'getThrowable') ? $event->getThrowable() : $event->getException(); // @phpstan-ignore-line if (!$exception instanceof ValidationException) { return; } diff --git a/src/EventListener/ExceptionListener.php b/src/EventListener/ExceptionListener.php index d58d2bf52c7..e089ff370ba 100644 --- a/src/EventListener/ExceptionListener.php +++ b/src/EventListener/ExceptionListener.php @@ -27,11 +27,14 @@ */ final class ExceptionListener { + /** + * @var ErrorListener + */ private $exceptionListener; public function __construct($controller, LoggerInterface $logger = null, $debug = false, ErrorListener $errorListener = null) { - $this->exceptionListener = $errorListener ? new ErrorListener($controller, $logger, $debug) : new LegacyExceptionListener($controller, $logger, $debug); + $this->exceptionListener = $errorListener ? new ErrorListener($controller, $logger, $debug) : new LegacyExceptionListener($controller, $logger, $debug); // @phpstan-ignore-line } public function onKernelException(ExceptionEvent $event): void diff --git a/src/EventListener/SerializeListener.php b/src/EventListener/SerializeListener.php index b68cc1fef00..b3abea328b2 100644 --- a/src/EventListener/SerializeListener.php +++ b/src/EventListener/SerializeListener.php @@ -60,7 +60,7 @@ public function onKernelView(ViewEvent $event): void if ( $controllerResult instanceof Response || !(($attributes = RequestAttributesExtractor::extractAttributes($request))['respond'] ?? $request->attributes->getBoolean('_api_respond', false)) - || $attributes && $this->isOperationAttributeDisabled($attributes, self::OPERATION_ATTRIBUTE_KEY) + || ($attributes && $this->isOperationAttributeDisabled($attributes, self::OPERATION_ATTRIBUTE_KEY)) ) { return; } diff --git a/src/Identifier/Normalizer/IntegerDenormalizer.php b/src/Identifier/Normalizer/IntegerDenormalizer.php index d75e1e9cf00..80888972819 100644 --- a/src/Identifier/Normalizer/IntegerDenormalizer.php +++ b/src/Identifier/Normalizer/IntegerDenormalizer.php @@ -21,6 +21,8 @@ final class IntegerDenormalizer implements DenormalizerInterface, CacheableSuppo { /** * {@inheritdoc} + * + * @phpstan-ignore-next-line this is a real problem, the parent interface cannot return int, but it's hard to fix, we'll try in v3 */ public function denormalize($data, $class, $format = null, array $context = []): int { diff --git a/src/JsonApi/Serializer/ItemNormalizer.php b/src/JsonApi/Serializer/ItemNormalizer.php index afb27e57edd..3efc74135c7 100644 --- a/src/JsonApi/Serializer/ItemNormalizer.php +++ b/src/JsonApi/Serializer/ItemNormalizer.php @@ -216,6 +216,7 @@ protected function normalizeRelation(PropertyMetadata $propertyMetadata, $relate } $normalizedRelatedObject = $this->serializer->normalize($relatedObject, $format, $context); + // @phpstan-ignore-next-line throwing an explicit exception helps debugging if (!\is_string($normalizedRelatedObject) && !\is_array($normalizedRelatedObject) && !$normalizedRelatedObject instanceof \ArrayObject && null !== $normalizedRelatedObject) { throw new UnexpectedValueException('Expected normalized relation to be an IRI, array, \ArrayObject or null'); } diff --git a/src/Security/ResourceAccessChecker.php b/src/Security/ResourceAccessChecker.php index c516de8f56a..6b308141307 100644 --- a/src/Security/ResourceAccessChecker.php +++ b/src/Security/ResourceAccessChecker.php @@ -81,15 +81,15 @@ private function getVariables(TokenInterface $token): array private function getEffectiveRoles(TokenInterface $token): array { if (null === $this->roleHierarchy) { - return method_exists($token, 'getRoleNames') ? $token->getRoleNames() : array_map('strval', $token->getRoles()); + return method_exists($token, 'getRoleNames') ? $token->getRoleNames() : array_map('strval', $token->getRoles()); // @phpstan-ignore-line } if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) { return $this->roleHierarchy->getReachableRoleNames($token->getRoleNames()); } - return array_map(function (Role $role): string { - return $role->getRole(); - }, $this->roleHierarchy->getReachableRoles($token->getRoles())); + return array_map(function (Role $role): string { // @phpstan-ignore-line + return $role->getRole(); // @phpstan-ignore-line + }, $this->roleHierarchy->getReachableRoles($token->getRoles())); // @phpstan-ignore-line } } diff --git a/src/Serializer/AbstractItemNormalizer.php b/src/Serializer/AbstractItemNormalizer.php index bdd14483f4e..20e230287a9 100644 --- a/src/Serializer/AbstractItemNormalizer.php +++ b/src/Serializer/AbstractItemNormalizer.php @@ -607,6 +607,7 @@ protected function normalizeRelation(PropertyMetadata $propertyMetadata, $relate } $normalizedRelatedObject = $this->serializer->normalize($relatedObject, $format, $context); + // @phpstan-ignore-next-line throwing an explicit exception helps debugging if (!\is_string($normalizedRelatedObject) && !\is_array($normalizedRelatedObject) && !$normalizedRelatedObject instanceof \ArrayObject && null !== $normalizedRelatedObject) { throw new UnexpectedValueException('Expected normalized relation to be an IRI, array, \ArrayObject or null'); } diff --git a/src/Util/ReflectionClassRecursiveIterator.php b/src/Util/ReflectionClassRecursiveIterator.php index 1c35d72f609..fc27c1e8c39 100644 --- a/src/Util/ReflectionClassRecursiveIterator.php +++ b/src/Util/ReflectionClassRecursiveIterator.php @@ -45,7 +45,12 @@ public static function getReflectionClassesFromDirectories(array $directories): $sourceFile = realpath($sourceFile); } - require_once $sourceFile; + try { + require_once $sourceFile; + } catch (\Throwable $t) { + // invalid PHP file (example: missing parent class) + continue; + } $includedFiles[$sourceFile] = true; } diff --git a/tests/Action/ExceptionActionTest.php b/tests/Action/ExceptionActionTest.php index 794b2b8ff9b..6d7a7164958 100644 --- a/tests/Action/ExceptionActionTest.php +++ b/tests/Action/ExceptionActionTest.php @@ -17,7 +17,8 @@ use ApiPlatform\Core\Exception\InvalidArgumentException; use ApiPlatform\Core\Tests\ProphecyTrait; use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\Exception\FlattenException; +use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Serializer\Exception\ExceptionInterface; @@ -39,8 +40,7 @@ public function testActionWithCatchableException() if (!is_a(ExceptionInterface::class, \Throwable::class, true)) { $serializerException->willExtend(\Exception::class); } - $flattenException = FlattenException::create($serializerException->reveal()); - + $flattenException = class_exists(FlattenException::class) ? FlattenException::create($serializerException->reveal()) : LegacyFlattenException::create($serializerException->reveal()); /** @phpstan-ignore-line */ $serializer = $this->prophesize(SerializerInterface::class); $serializer->serialize($flattenException, 'jsonproblem', ['statusCode' => Response::HTTP_BAD_REQUEST])->willReturn(); @@ -64,8 +64,7 @@ public function testActionWithUncatchableException() $serializerException->willExtend(\Exception::class); } - $flattenException = FlattenException::create($serializerException->reveal()); - + $flattenException = class_exists(FlattenException::class) ? FlattenException::create($serializerException->reveal()) : LegacyFlattenException::create($serializerException->reveal()); /** @phpstan-ignore-line */ $serializer = $this->prophesize(SerializerInterface::class); $serializer->serialize($flattenException, 'jsonproblem', ['statusCode' => $flattenException->getStatusCode()])->willReturn(); diff --git a/features/bootstrap/CommandContext.php b/tests/Behat/CommandContext.php similarity index 91% rename from features/bootstrap/CommandContext.php rename to tests/Behat/CommandContext.php index 5d0e7624f88..c1417b51443 100644 --- a/features/bootstrap/CommandContext.php +++ b/tests/Behat/CommandContext.php @@ -11,9 +11,11 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + +use Behat\Behat\Context\Context; use Behat\Gherkin\Node\PyStringNode; use Behat\Gherkin\Node\TableNode; -use Behat\Symfony2Extension\Context\KernelAwareContext; use PHPUnit\Framework\Assert; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Command\Command; @@ -25,11 +27,8 @@ * * @author Alan Poulain */ -final class CommandContext implements KernelAwareContext +final class CommandContext implements Context { - /** - * @var KernelInterface - */ private $kernel; /** @@ -42,6 +41,11 @@ final class CommandContext implements KernelAwareContext */ private $commandTester; + public function __construct(KernelInterface $kernel) + { + $this->kernel = $kernel; + } + /** * @When I run the command :command */ diff --git a/features/bootstrap/CoverageContext.php b/tests/Behat/CoverageContext.php similarity index 97% rename from features/bootstrap/CoverageContext.php rename to tests/Behat/CoverageContext.php index da47854ffcd..05bf6589dee 100644 --- a/features/bootstrap/CoverageContext.php +++ b/tests/Behat/CoverageContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use Behat\Behat\Context\Context; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use SebastianBergmann\CodeCoverage\CodeCoverage; diff --git a/features/bootstrap/DoctrineContext.php b/tests/Behat/DoctrineContext.php similarity index 98% rename from features/bootstrap/DoctrineContext.php rename to tests/Behat/DoctrineContext.php index 5bd8487d67b..d0bafa2ed69 100644 --- a/features/bootstrap/DoctrineContext.php +++ b/tests/Behat/DoctrineContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Address as AddressDocument; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Answer as AnswerDocument; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\CompositeItem as CompositeItemDocument; @@ -131,10 +133,11 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\UuidIdentifierDummy; use Behat\Behat\Context\Context; use Behat\Gherkin\Node\PyStringNode; -use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Tools\SchemaTool; +use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\ObjectManager; use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; /** @@ -143,7 +146,7 @@ final class DoctrineContext implements Context { /** - * @var EntityManagerInterface|DocumentManager + * @var ObjectManager */ private $manager; private $doctrine; @@ -174,10 +177,16 @@ public function __construct(ManagerRegistry $doctrine, UserPasswordEncoderInterf */ public function createDatabase() { - $this->isOrm() && $this->schemaTool->dropSchema($this->classes); - $this->isOdm() && $this->schemaManager->dropDatabases(); + if ($this->isOrm()) { + $this->schemaTool->dropSchema($this->classes); + $this->schemaTool->createSchema($this->classes); + } + + if ($this->isOdm()) { + $this->schemaManager->dropDatabases(); + } + $this->doctrine->getManager()->clear(); - $this->isOrm() && $this->schemaTool->createSchema($this->classes); } /** @@ -458,7 +467,7 @@ public function thereAreDummyDtoNoOutputObjects(int $nb) for ($i = 1; $i <= $nb; ++$i) { $dummyDto = $this->buildDummyDtoNoOutput(); $dummyDto->lorem = 'DummyDtoNoOutput foo #'.$i; - $dummyDto->ipsum = $i / 3; + $dummyDto->ipsum = (string) ($i / 3); $this->manager->persist($dummyDto); } @@ -617,9 +626,9 @@ public function thereAreDummyObjectsWithDummyDateAndDummyBoolean(int $nb, string { $descriptions = ['Smart dummy.', 'Not so smart dummy.']; - if (in_array($bool, ['true', '1', 1], true)) { + if (\in_array($bool, ['true', '1', 1], true)) { $bool = true; - } elseif (in_array($bool, ['false', '0', 0], true)) { + } elseif (\in_array($bool, ['false', '0', 0], true)) { $bool = false; } else { $expected = ['true', 'false', '1', '0']; @@ -787,9 +796,9 @@ public function thereAreDummyObjectsWithDummyPrice(int $nb) */ public function thereAreDummyObjectsWithDummyBoolean(int $nb, string $bool) { - if (in_array($bool, ['true', '1', 1], true)) { + if (\in_array($bool, ['true', '1', 1], true)) { $bool = true; - } elseif (in_array($bool, ['false', '0', 0], true)) { + } elseif (\in_array($bool, ['false', '0', 0], true)) { $bool = false; } else { $expected = ['true', 'false', '1', '0']; @@ -815,9 +824,9 @@ public function thereAreDummyObjectsWithDummyBoolean(int $nb, string $bool) */ public function thereAreDummyObjectsWithEmbeddedDummyBoolean(int $nb, string $bool) { - if (in_array($bool, ['true', '1', 1], true)) { + if (\in_array($bool, ['true', '1', 1], true)) { $bool = true; - } elseif (in_array($bool, ['false', '0', 0], true)) { + } elseif (\in_array($bool, ['false', '0', 0], true)) { $bool = false; } else { $expected = ['true', 'false', '1', '0']; @@ -842,9 +851,9 @@ public function thereAreDummyObjectsWithEmbeddedDummyBoolean(int $nb, string $bo */ public function thereAreDummyObjectsWithRelationEmbeddedDummyBoolean(int $nb, string $bool) { - if (in_array($bool, ['true', '1', 1], true)) { + if (\in_array($bool, ['true', '1', 1], true)) { $bool = true; - } elseif (in_array($bool, ['false', '0', 0], true)) { + } elseif (\in_array($bool, ['false', '0', 0], true)) { $bool = false; } else { $expected = ['true', 'false', '1', '0']; @@ -1354,7 +1363,7 @@ public function thereAreNbDummyDtoCustom($nb) for ($i = 0; $i < $nb; ++$i) { $dto = $this->isOrm() ? new DummyDtoCustom() : new DummyDtoCustomDocument(); $dto->lorem = 'test'; - $dto->ipsum = (string) $i + 1; + $dto->ipsum = (string) ($i + 1); $this->manager->persist($dto); } diff --git a/features/bootstrap/ElasticsearchContext.php b/tests/Behat/ElasticsearchContext.php similarity index 97% rename from features/bootstrap/ElasticsearchContext.php rename to tests/Behat/ElasticsearchContext.php index be613807263..d3f4e8f1384 100644 --- a/features/bootstrap/ElasticsearchContext.php +++ b/tests/Behat/ElasticsearchContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use ApiPlatform\Core\Bridge\Elasticsearch\Metadata\Document\DocumentMetadata; use Behat\Behat\Context\Context; use Elasticsearch\Client; @@ -126,7 +128,7 @@ private function loadFixtures(): void $bulk[] = $document; - if (0 === (count($bulk) % 50)) { + if (0 === (\count($bulk) % 50)) { $this->client->bulk(['body' => $bulk]); $bulk = []; } diff --git a/features/bootstrap/GraphqlContext.php b/tests/Behat/GraphqlContext.php similarity index 89% rename from features/bootstrap/GraphqlContext.php rename to tests/Behat/GraphqlContext.php index 3541f25005a..813bcd9f94f 100644 --- a/features/bootstrap/GraphqlContext.php +++ b/tests/Behat/GraphqlContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use Behat\Behat\Context\Context; use Behat\Behat\Context\Environment\InitializedContextEnvironment; use Behat\Behat\Hook\Scope\BeforeScenarioScope; @@ -57,9 +59,15 @@ public function __construct(Request $request) */ public function gatherContexts(BeforeScenarioScope $scope) { - /** @var InitializedContextEnvironment $environment */ + /** + * @var InitializedContextEnvironment $environment + */ $environment = $scope->getEnvironment(); - $this->restContext = $environment->getContext(RestContext::class); + /** + * @var RestContext $restContext + */ + $restContext = $environment->getContext(RestContext::class); + $this->restContext = $restContext; } /** @@ -110,7 +118,7 @@ public function iHaveTheFollowingFilesForAGraphqlRequest(TableNode $table) throw new \InvalidArgumentException('You must provide a "name" and "file" column in your table node.'); } - $files[$row['name']] = $this->restContext->getMinkParameter('files_path').DIRECTORY_SEPARATOR.$row['file']; + $files[$row['name']] = $this->restContext->getMinkParameter('files_path').\DIRECTORY_SEPARATOR.$row['file']; } $this->graphqlRequest['files'] = $files; @@ -133,8 +141,8 @@ public function iSendTheFollowingGraphqlMultipartRequestOperations(PyStringNode $params['operations'] = $string->getRaw(); $params['map'] = $this->graphqlRequest['map']; - $this->request->setHttpHeader('Content-type', 'multipart/form-data'); - $this->request->send('POST', '/graphql', $params, $this->graphqlRequest['files']); + $this->request->setHttpHeader('Content-type', 'multipart/form-data'); // @phpstan-ignore-line + $this->request->send('POST', '/graphql', $params, $this->graphqlRequest['files']); // @phpstan-ignore-line } /** @@ -151,7 +159,7 @@ public function ISendTheQueryToIntrospectTheSchema() */ public function theGraphQLFieldIsDeprecatedForTheReason(string $fieldName, string $reason) { - foreach (json_decode($this->request->getContent(), true)['data']['__type']['fields'] as $field) { + foreach (json_decode($this->request->getContent(), true)['data']['__type']['fields'] as $field) { // @phpstan-ignore-line if ($fieldName === $field['name'] && $field['isDeprecated'] && $reason === $field['deprecationReason']) { return; } diff --git a/features/bootstrap/HttpCacheContext.php b/tests/Behat/HttpCacheContext.php similarity index 73% rename from features/bootstrap/HttpCacheContext.php rename to tests/Behat/HttpCacheContext.php index b4d4452b552..26e49e83e20 100644 --- a/features/bootstrap/HttpCacheContext.php +++ b/tests/Behat/HttpCacheContext.php @@ -11,21 +11,20 @@ declare(strict_types=1); -use Behat\Symfony2Extension\Context\KernelAwareContext; +namespace ApiPlatform\Core\Tests\Behat; + +use Behat\Behat\Context\Context; use PHPUnit\Framework\ExpectationFailedException; use Symfony\Component\HttpKernel\KernelInterface; /** * @author Kévin Dunglas */ -final class HttpCacheContext implements KernelAwareContext +final class HttpCacheContext implements Context { - /** - * @var KernelInterface - */ private $kernel; - public function setKernel(KernelInterface $kernel) + public function __construct(KernelInterface $kernel) { $this->kernel = $kernel; } @@ -35,7 +34,7 @@ public function setKernel(KernelInterface $kernel) */ public function irisShouldBePurged(string $iris) { - $purger = $this->kernel->getContainer()->get('test.api_platform.http_cache.purger'); + $purger = $this->kernel->getContainer()->get('behat.driver.service_container')->get('test.api_platform.http_cache.purger'); $purgedIris = implode(',', $purger->getIris()); $purger->clear(); diff --git a/features/bootstrap/HydraContext.php b/tests/Behat/HydraContext.php similarity index 92% rename from features/bootstrap/HydraContext.php rename to tests/Behat/HydraContext.php index 7f0c0868a66..9ac151d6148 100644 --- a/features/bootstrap/HydraContext.php +++ b/tests/Behat/HydraContext.php @@ -11,13 +11,15 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use Behat\Behat\Context\Context; use Behat\Behat\Context\Environment\InitializedContextEnvironment; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Behatch\Context\RestContext; use PHPUnit\Framework\Assert; use PHPUnit\Framework\ExpectationFailedException; -use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; final class HydraContext implements Context { @@ -27,9 +29,9 @@ final class HydraContext implements Context private $restContext; private $propertyAccessor; - public function __construct() + public function __construct(PropertyAccessorInterface $propertyAccessor) { - $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); + $this->propertyAccessor = $propertyAccessor; } /** @@ -39,9 +41,15 @@ public function __construct() */ public function gatherContexts(BeforeScenarioScope $scope) { - /** @var InitializedContextEnvironment $environment */ + /** + * @var InitializedContextEnvironment $environment + */ $environment = $scope->getEnvironment(); - $this->restContext = $environment->getContext(RestContext::class); + /** + * @var RestContext $restContext + */ + $restContext = $environment->getContext(RestContext::class); + $this->restContext = $restContext; } /** @@ -142,7 +150,7 @@ public function assertOperationNodeValueContains(string $nodeName, string $opera */ public function assertNbOperationsExist(int $nb, string $className) { - Assert::assertEquals($nb, count($this->getOperations($className))); + Assert::assertEquals($nb, \count($this->getOperations($className))); } /** @@ -150,7 +158,7 @@ public function assertNbOperationsExist(int $nb, string $className) */ public function assertNbPropertiesExist(int $nb, string $className) { - Assert::assertEquals($nb, count($this->getProperties($className))); + Assert::assertEquals($nb, \count($this->getProperties($className))); } /** @@ -222,7 +230,7 @@ public function assertPropertyIsNotRequired(string $propertyName, string $classN * * @throws \InvalidArgumentException */ - private function getPropertyInfo(string $propertyName, string $className): stdClass + private function getPropertyInfo(string $propertyName, string $className): \stdClass { foreach ($this->getProperties($className) as $property) { if ($property->{'hydra:title'} === $propertyName) { @@ -238,7 +246,7 @@ private function getPropertyInfo(string $propertyName, string $className): stdCl * * @throws \InvalidArgumentException */ - private function getOperation(string $method, string $className): stdClass + private function getOperation(string $method, string $className): \stdClass { foreach ($this->getOperations($className) as $operation) { if ($operation->{'hydra:method'} === $method) { @@ -270,7 +278,7 @@ private function getProperties(string $className): array * * @throws \InvalidArgumentException */ - private function getClassInfo(string $className): stdClass + private function getClassInfo(string $className): \stdClass { $json = $this->getLastJsonResponse(); @@ -290,7 +298,7 @@ private function getClassInfo(string $className): stdClass * * @throws \RuntimeException */ - private function getLastJsonResponse(): stdClass + private function getLastJsonResponse(): \stdClass { if (null === $decoded = json_decode($this->restContext->getMink()->getSession()->getDriver()->getContent())) { throw new \RuntimeException('JSON response seems to be invalid'); diff --git a/features/bootstrap/JsonApiContext.php b/tests/Behat/JsonApiContext.php similarity index 94% rename from features/bootstrap/JsonApiContext.php rename to tests/Behat/JsonApiContext.php index ff89b039704..805e74525a7 100644 --- a/features/bootstrap/JsonApiContext.php +++ b/tests/Behat/JsonApiContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\CircularReference as CircularReferenceDocument; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\DummyFriend as DummyFriendDocument; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\RelatedDummy as RelatedDummyDocument; @@ -23,8 +25,8 @@ use Behatch\Context\RestContext; use Behatch\Json\Json; use Behatch\Json\JsonInspector; -use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\Persistence\ManagerRegistry; use JsonSchema\Validator; use PHPUnit\Framework\ExpectationFailedException; @@ -58,9 +60,15 @@ public function __construct(ManagerRegistry $doctrine, string $jsonApiSchemaFile */ public function gatherContexts(BeforeScenarioScope $scope) { - /** @var InitializedContextEnvironment $environment */ + /** + * @var InitializedContextEnvironment $environment + */ $environment = $scope->getEnvironment(); - $this->restContext = $environment->getContext(RestContext::class); + /** + * @var RestContext $restContext + */ + $restContext = $environment->getContext(RestContext::class); + $this->restContext = $restContext; } /** diff --git a/features/bootstrap/JsonContext.php b/tests/Behat/JsonContext.php similarity index 91% rename from features/bootstrap/JsonContext.php rename to tests/Behat/JsonContext.php index 93b6c9c1927..5cb109b7b6c 100644 --- a/features/bootstrap/JsonContext.php +++ b/tests/Behat/JsonContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase; use Behat\Gherkin\Node\PyStringNode; use Behatch\Context\JsonContext as BaseJsonContext; @@ -55,20 +57,19 @@ public function theJsonIsASupersetOf(PyStringNode $content) $array = json_decode($this->httpCallResultPool->getResult()->getValue(), true); $subset = json_decode($content->getRaw(), true); - // Compatibility with PHPUnit 7 - method_exists(Assert::class, 'assertArraySubset') ? Assert::assertArraySubset($subset, $array) : ApiTestCase::assertArraySubset($subset, $array); + method_exists(Assert::class, 'assertArraySubset') ? Assert::assertArraySubset($subset, $array) : ApiTestCase::assertArraySubset($subset, $array); // @phpstan-ignore-line Compatibility with PHPUnit 7 } private function sortArrays($obj) { - $isObject = is_object($obj); + $isObject = \is_object($obj); foreach ($obj as $key => $value) { if (null === $value || is_scalar($value)) { continue; } - if (is_array($value)) { + if (\is_array($value)) { sort($value); } diff --git a/features/bootstrap/JsonHalContext.php b/tests/Behat/JsonHalContext.php similarity index 86% rename from features/bootstrap/JsonHalContext.php rename to tests/Behat/JsonHalContext.php index 3026069d8d2..48a2c325490 100644 --- a/features/bootstrap/JsonHalContext.php +++ b/tests/Behat/JsonHalContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use Behat\Behat\Context\Context; use Behat\Behat\Context\Environment\InitializedContextEnvironment; use Behat\Behat\Hook\Scope\BeforeScenarioScope; @@ -45,9 +47,15 @@ public function __construct(string $schemaFile) */ public function gatherContexts(BeforeScenarioScope $scope) { - /** @var InitializedContextEnvironment $environment */ + /** + * @var InitializedContextEnvironment $environment + */ $environment = $scope->getEnvironment(); - $this->restContext = $environment->getContext(RestContext::class); + /** + * @var RestContext $restContext + */ + $restContext = $environment->getContext(RestContext::class); + $this->restContext = $restContext; } /** diff --git a/features/bootstrap/SwaggerContext.php b/tests/Behat/OpenApiContext.php similarity index 86% rename from features/bootstrap/SwaggerContext.php rename to tests/Behat/OpenApiContext.php index 61c333788c6..59d9035b5a4 100644 --- a/features/bootstrap/SwaggerContext.php +++ b/tests/Behat/OpenApiContext.php @@ -11,6 +11,8 @@ declare(strict_types=1); +namespace ApiPlatform\Core\Tests\Behat; + use Behat\Behat\Context\Context; use Behat\Behat\Context\Environment\InitializedContextEnvironment; use Behat\Behat\Hook\Scope\BeforeScenarioScope; @@ -18,7 +20,7 @@ use PHPUnit\Framework\Assert; use PHPUnit\Framework\ExpectationFailedException; -final class SwaggerContext implements Context +final class OpenApiContext implements Context { /** * @var RestContext @@ -32,9 +34,15 @@ final class SwaggerContext implements Context */ public function gatherContexts(BeforeScenarioScope $scope) { - /** @var InitializedContextEnvironment $environment */ + /** + * @var InitializedContextEnvironment $environment + */ $environment = $scope->getEnvironment(); - $this->restContext = $environment->getContext(RestContext::class); + /** + * @var RestContext $restContext + */ + $restContext = $environment->getContext(RestContext::class); + $this->restContext = $restContext; } /** @@ -129,7 +137,7 @@ public function assertPropertyExistForTheOpenApiClass(string $propertyName, stri */ public function assertPropertyIsRequiredForSwagger(string $propertyName, string $className) { - if (!in_array($propertyName, $this->getClassInfo($className)->required, true)) { + if (!\in_array($propertyName, $this->getClassInfo($className)->required, true)) { throw new ExpectationFailedException(sprintf('Property "%s" of class "%s" should be required', $propertyName, $className)); } } @@ -139,7 +147,7 @@ public function assertPropertyIsRequiredForSwagger(string $propertyName, string */ public function assertPropertyIsRequiredForOpenAPi(string $propertyName, string $className) { - if (!in_array($propertyName, $this->getClassInfo($className, 3)->required, true)) { + if (!\in_array($propertyName, $this->getClassInfo($className, 3)->required, true)) { throw new ExpectationFailedException(sprintf('Property "%s" of class "%s" should be required', $propertyName, $className)); } } @@ -149,9 +157,13 @@ public function assertPropertyIsRequiredForOpenAPi(string $propertyName, string * * @throws \InvalidArgumentException */ - private function getPropertyInfo(string $propertyName, string $className, int $specVersion = 2): stdClass + private function getPropertyInfo(string $propertyName, string $className, int $specVersion = 2): \stdClass { - foreach ($this->getProperties($className, $specVersion) as $classPropertyName => $property) { + /** + * @var iterable $properties + */ + $properties = $this->getProperties($className, $specVersion); + foreach ($properties as $classPropertyName => $property) { if ($classPropertyName === $propertyName) { return $property; } @@ -163,7 +175,7 @@ private function getPropertyInfo(string $propertyName, string $className, int $s /** * Gets all operations of a given class. */ - private function getProperties(string $className, int $specVersion = 2): stdClass + private function getProperties(string $className, int $specVersion = 2): \stdClass { return $this->getClassInfo($className, $specVersion)->{'properties'} ?? new \stdClass(); } @@ -173,7 +185,7 @@ private function getProperties(string $className, int $specVersion = 2): stdClas * * @throws \InvalidArgumentException */ - private function getClassInfo(string $className, int $specVersion = 2): stdClass + private function getClassInfo(string $className, int $specVersion = 2): \stdClass { $nodes = 2 === $specVersion ? $this->getLastJsonResponse()->{'definitions'} : $this->getLastJsonResponse()->{'components'}->{'schemas'}; foreach ($nodes as $classTitle => $classData) { @@ -190,7 +202,7 @@ private function getClassInfo(string $className, int $specVersion = 2): stdClass * * @throws \RuntimeException */ - private function getLastJsonResponse(): stdClass + private function getLastJsonResponse(): \stdClass { if (null === ($decoded = json_decode($this->restContext->getMink()->getSession()->getDriver()->getContent()))) { throw new \RuntimeException('JSON response seems to be invalid'); diff --git a/tests/Bridge/Doctrine/EventListener/WriteListenerTest.php b/tests/Bridge/Doctrine/EventListener/WriteListenerTest.php index 393724e5a72..3507d91e1be 100644 --- a/tests/Bridge/Doctrine/EventListener/WriteListenerTest.php +++ b/tests/Bridge/Doctrine/EventListener/WriteListenerTest.php @@ -72,12 +72,9 @@ public function testOnKernelViewWithControllerResultAndDeleteMethod() $request = new Request(); $request->setMethod('DELETE'); $request->attributes->set('_api_resource_class', 'Dummy'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->setControllerResult(null)->shouldBeCalled(); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->getControllerResult()->willReturn($dummy); - $writeListener->onKernelView($eventProphecy->reveal()); + $event = new ViewEvent($this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, $dummy); + $writeListener->onKernelView($event); } /** diff --git a/tests/Bridge/FosUser/EventListenerTest.php b/tests/Bridge/FosUser/EventListenerTest.php deleted file mode 100644 index 1e24a888f21..00000000000 --- a/tests/Bridge/FosUser/EventListenerTest.php +++ /dev/null @@ -1,117 +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 ApiPlatform\Core\Tests\Bridge\FosUser; - -use ApiPlatform\Core\Bridge\FosUser\EventListener; -use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\User; -use ApiPlatform\Core\Tests\ProphecyTrait; -use FOS\UserBundle\Model\UserInterface; -use FOS\UserBundle\Model\UserManagerInterface; -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\ViewEvent; - -/** - * @author Kévin Dunglas - */ -class EventListenerTest extends TestCase -{ - use ProphecyTrait; - - public function testDelete() - { - $user = $this->prophesize(UserInterface::class); - - $request = new Request([], [], ['_api_resource_class' => User::class, '_api_item_operation_name' => 'delete']); - $request->setMethod('DELETE'); - - $manager = $this->prophesize(UserManagerInterface::class); - $manager->deleteUser($user)->shouldBeCalled(); - - $event = $this->prophesize(ViewEvent::class); - $event->getControllerResult()->willReturn($user)->shouldBeCalled(); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->setControllerResult(null)->shouldBeCalled(); - - $listener = new EventListener($manager->reveal()); - $listener->onKernelView($event->reveal()); - } - - public function testUpdate() - { - $user = $this->prophesize(UserInterface::class); - - $request = new Request([], [], ['_api_resource_class' => User::class, '_api_item_operation_name' => 'put']); - $request->setMethod('PUT'); - - $manager = $this->prophesize(UserManagerInterface::class); - $manager->updateUser($user)->shouldBeCalled(); - - $event = $this->prophesize(ViewEvent::class); - $event->getControllerResult()->willReturn($user)->shouldBeCalled(); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->setControllerResult()->shouldNotBeCalled(); - - $listener = new EventListener($manager->reveal()); - $listener->onKernelView($event->reveal()); - } - - public function testNotApiRequest() - { - $request = new Request(); - - $manager = $this->prophesize(UserManagerInterface::class); - $manager->deleteUser()->shouldNotBeCalled(); - $manager->updateUser()->shouldNotBeCalled(); - - $event = $this->prophesize(ViewEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - - $listener = new EventListener($manager->reveal()); - $listener->onKernelView($event->reveal()); - } - - public function testNotUser() - { - $request = new Request([], [], ['_api_resource_class' => User::class, '_api_item_operation_name' => 'put']); - $request->setMethod('PUT'); - - $manager = $this->prophesize(UserManagerInterface::class); - $manager->deleteUser()->shouldNotBeCalled(); - $manager->updateUser()->shouldNotBeCalled(); - - $event = $this->prophesize(ViewEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getControllerResult()->willReturn(new \stdClass()); - - $listener = new EventListener($manager->reveal()); - $listener->onKernelView($event->reveal()); - } - - public function testSafeMethod() - { - $request = new Request([], [], ['_api_resource_class' => User::class, '_api_item_operation_name' => 'put']); - - $manager = $this->prophesize(UserManagerInterface::class); - $manager->deleteUser()->shouldNotBeCalled(); - $manager->updateUser()->shouldNotBeCalled(); - - $event = $this->prophesize(ViewEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getControllerResult()->willReturn(new User()); - - $listener = new EventListener($manager->reveal()); - $listener->onKernelView($event->reveal()); - } -} diff --git a/tests/Bridge/NelmioApiDoc/Extractor/AnnotationsProvider/ApiPlatformProviderTest.php b/tests/Bridge/NelmioApiDoc/Extractor/AnnotationsProvider/ApiPlatformProviderTest.php index e27c1c3b712..525a71e3e47 100644 --- a/tests/Bridge/NelmioApiDoc/Extractor/AnnotationsProvider/ApiPlatformProviderTest.php +++ b/tests/Bridge/NelmioApiDoc/Extractor/AnnotationsProvider/ApiPlatformProviderTest.php @@ -28,6 +28,7 @@ use ApiPlatform\Core\Tests\ProphecyTrait; use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Extractor\AnnotationsProviderInterface; +use Nelmio\ApiDocBundle\NelmioApiDocBundle; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Symfony\Component\Routing\Route; @@ -42,6 +43,13 @@ class ApiPlatformProviderTest extends TestCase { use ProphecyTrait; + protected function setUp(): void + { + if (!class_exists(NelmioApiDocBundle::class)) { + $this->markTestSkipped('NelmioApiDocBundle is not installed.'); + } + } + /** * @expectedDeprecation The ApiPlatform\Core\Bridge\NelmioApiDoc\Extractor\AnnotationsProvider\ApiPlatformProvider class is deprecated since version 2.2 and will be removed in 3.0. NelmioApiDocBundle 3 has native support for API Platform. */ diff --git a/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php b/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php index 3e041c8678e..0b35c0c68f6 100644 --- a/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php +++ b/tests/Bridge/NelmioApiDoc/Parser/ApiPlatformParserTest.php @@ -43,6 +43,13 @@ class ApiPlatformParserTest extends TestCase { use ProphecyTrait; + protected function setUp(): void + { + if (!class_exists(NelmioApiDocBundle::class)) { + $this->markTestSkipped('NelmioApiDocBundle is not installed.'); + } + } + /** * @expectedDeprecation The ApiPlatform\Core\Bridge\NelmioApiDoc\Parser\ApiPlatformParser class is deprecated since version 2.2 and will be removed in 3.0. NelmioApiDocBundle 3 has native support for API Platform. */ diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php index 0e079a02f79..1376d38586d 100644 --- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php +++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php @@ -83,14 +83,12 @@ use ApiPlatform\Core\Validator\ValidatorInterface; use Doctrine\Bundle\DoctrineBundle\DoctrineBundle; use Doctrine\ORM\OptimisticLockException; -use FOS\UserBundle\FOSUserBundle; use Nelmio\ApiDocBundle\NelmioApiDocBundle; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\Exception\Doubler\MethodNotFoundException; use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Resource\DirectoryResource; use Symfony\Component\Config\Resource\ResourceInterface; use Symfony\Component\DependencyInjection\Alias; @@ -101,7 +99,6 @@ use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\Response; @@ -244,25 +241,6 @@ public function testSetNameConverter() $this->extension->load($config, $containerBuilder); } - public function testEnableFosUser() - { - $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); - $containerBuilderProphecy->hasParameter('kernel.debug')->willReturn(true); - $containerBuilderProphecy->getParameter('kernel.debug')->willReturn(false); - $containerBuilderProphecy->getParameter('kernel.bundles')->willReturn([ - 'DoctrineBundle' => DoctrineBundle::class, - 'FOSUserBundle' => FOSUserBundle::class, - ])->shouldBeCalled(); - $containerBuilderProphecy->setDefinition('api_platform.fos_user.event_listener', Argument::type(Definition::class))->shouldBeCalled(); - - $containerBuilder = $containerBuilderProphecy->reveal(); - - $config = self::DEFAULT_CONFIG; - $config['api_platform']['enable_fos_user'] = true; - - $this->extension->load($config, $containerBuilder); - } - public function testDisableProfiler() { $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); @@ -292,34 +270,19 @@ public function testEnableProfilerWithDebug() $this->extension->load($config, $containerBuilder); } - public function testFosUserPriority() - { - $builder = new ContainerBuilder(); - - $loader = new XmlFileLoader($builder, new FileLocator(\dirname(__DIR__).'/../../../../src/Bridge/Symfony/Bundle/Resources/config')); - $loader->load('api.xml'); - $loader->load('fos_user.xml'); - - $fosListener = $builder->getDefinition('api_platform.fos_user.event_listener'); - $viewListener = $builder->getDefinition('api_platform.listener.view.serialize'); - - // Ensure FOSUser event listener priority is always greater than the view serialize listener - $this->assertGreaterThan( - $viewListener->getTag('kernel.event_listener')[0]['priority'], - $fosListener->getTag('kernel.event_listener')[0]['priority'], - 'api_platform.fos_user.event_listener priority needs to be greater than that of api_platform.listener.view.serialize' - ); - } - /** * @group legacy */ public function testEnableNelmioApiDoc() { + if (!class_exists(NelmioApiDocBundle::class)) { + $this->markTestSkipped('NelmioApiDocBundle is not installed.'); + } + $containerBuilderProphecy = $this->getBaseContainerBuilderProphecy(); $containerBuilderProphecy->getParameter('kernel.bundles')->willReturn([ 'DoctrineBundle' => DoctrineBundle::class, - 'NelmioApiDocBundle' => NelmioApiDocBundle::class, + 'NelmioApiDocBundle' => NelmioApiDocBundle::class, // @phpstan-ignore-line ])->shouldBeCalled(); $containerBuilderProphecy->setDefinition('api_platform.nelmio_api_doc.annotations_provider', Argument::type(Definition::class))->shouldBeCalled(); $containerBuilderProphecy->setDefinition('api_platform.nelmio_api_doc.parser', Argument::type(Definition::class))->shouldBeCalled(); diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php index 92fef8a6ec6..e8c07bfb8b1 100644 --- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php +++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ConfigurationTest.php @@ -107,7 +107,7 @@ private function runDefaultConfigTests(array $doctrineIntegrationsToLoad = ['orm 'serialize_payload_fields' => [], ], 'name_converter' => null, - 'enable_fos_user' => true, + 'enable_fos_user' => false, 'enable_nelmio_api_doc' => false, 'enable_swagger' => true, 'enable_swagger_ui' => true, diff --git a/tests/Bridge/Symfony/Validator/EventListener/ValidateListenerTest.php b/tests/Bridge/Symfony/Validator/EventListener/ValidateListenerTest.php index 8e79a7abf56..28b51dfc205 100644 --- a/tests/Bridge/Symfony/Validator/EventListener/ValidateListenerTest.php +++ b/tests/Bridge/Symfony/Validator/EventListener/ValidateListenerTest.php @@ -49,11 +49,10 @@ public function testNotAnApiPlatformRequest() $request = new Request(); $request->setMethod('POST'); - $event = $this->prophesize(ViewEvent::class); - $event->getRequest()->willReturn($request); - $listener = new ValidateListener($validator, $resourceMetadataFactory); - $listener->onKernelView($event->reveal()); + + $event = new ViewEvent($this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, []); + $listener->onKernelView($event); } public function testValidatorIsCalled() diff --git a/tests/Bridge/Symfony/Validator/EventListener/ValidationExceptionListenerTest.php b/tests/Bridge/Symfony/Validator/EventListener/ValidationExceptionListenerTest.php index 0d7248b994a..7151e553f36 100644 --- a/tests/Bridge/Symfony/Validator/EventListener/ValidationExceptionListenerTest.php +++ b/tests/Bridge/Symfony/Validator/EventListener/ValidationExceptionListenerTest.php @@ -17,10 +17,10 @@ use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException; use ApiPlatform\Core\Tests\ProphecyTrait; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ExceptionEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Validator\ConstraintViolationList; @@ -33,18 +33,13 @@ class ValidationExceptionListenerTest extends TestCase public function testNotValidationException() { - $eventProphecy = $this->prophesize(ExceptionEvent::class); - if (method_exists(ExceptionEvent::class, 'getThrowable')) { - $eventProphecy->getThrowable()->willReturn(new \Exception())->shouldBeCalled(); - } else { - $eventProphecy->getException()->willReturn(new \Exception())->shouldBeCalled(); - } - $eventProphecy->setResponse()->shouldNotBeCalled(); + $listener = new ValidationExceptionListener( + $this->prophesize(SerializerInterface::class)->reveal(), + ['hydra' => ['application/ld+json']]); - $serializerProphecy = $this->prophesize(SerializerInterface::class); - - $listener = new ValidationExceptionListener($serializerProphecy->reveal(), ['hydra' => ['application/ld+json']]); - $listener->onKernelException($eventProphecy->reveal()); + $event = new ExceptionEvent($this->prophesize(HttpKernelInterface::class)->reveal(), new Request(), HttpKernelInterface::MASTER_REQUEST, new \Exception()); + $listener->onKernelException($event); + $this->assertNull($event->getResponse()); } public function testValidationException() @@ -52,29 +47,19 @@ public function testValidationException() $exceptionJson = '{"foo": "bar"}'; $list = new ConstraintViolationList([]); - $eventProphecy = $this->prophesize(ExceptionEvent::class); - if (method_exists(ExceptionEvent::class, 'getThrowable')) { - $eventProphecy->getThrowable()->willReturn(new ValidationException($list))->shouldBeCalled(); - } else { - $eventProphecy->getException()->willReturn(new ValidationException($list))->shouldBeCalled(); - } - $eventProphecy->getRequest()->willReturn(new Request())->shouldBeCalled(); - $eventProphecy->setResponse(Argument::allOf( - Argument::type(Response::class), - Argument::which('getContent', $exceptionJson), - Argument::which('getStatusCode', Response::HTTP_BAD_REQUEST), - Argument::that(function (Response $response): bool { - return - 'application/ld+json; charset=utf-8' === $response->headers->get('Content-Type') - && 'nosniff' === $response->headers->get('X-Content-Type-Options') - && 'deny' === $response->headers->get('X-Frame-Options'); - }) - ))->shouldBeCalled(); - $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->serialize($list, 'hydra')->willReturn($exceptionJson)->shouldBeCalled(); $listener = new ValidationExceptionListener($serializerProphecy->reveal(), ['hydra' => ['application/ld+json']]); - $listener->onKernelException($eventProphecy->reveal()); + $event = new ExceptionEvent($this->prophesize(HttpKernelInterface::class)->reveal(), new Request(), HttpKernelInterface::MASTER_REQUEST, new ValidationException($list)); + $listener->onKernelException($event); + + $response = $event->getResponse(); + $this->assertInstanceOf(Response::class, $response); + $this->assertSame($exceptionJson, $response->getContent()); + $this->assertSame(Response::HTTP_BAD_REQUEST, $response->getStatusCode()); + $this->assertSame('application/ld+json; charset=utf-8', $response->headers->get('Content-Type')); + $this->assertSame('nosniff', $response->headers->get('X-Content-Type-Options')); + $this->assertSame('deny', $response->headers->get('X-Frame-Options')); } } diff --git a/tests/EventListener/ExceptionListenerTest.php b/tests/EventListener/ExceptionListenerTest.php index 206fe80663e..9edfec97f14 100644 --- a/tests/EventListener/ExceptionListenerTest.php +++ b/tests/EventListener/ExceptionListenerTest.php @@ -38,18 +38,11 @@ public function testOnKernelException(Request $request) $kernel = $this->prophesize(HttpKernelInterface::class); $kernel->handle(Argument::type(Request::class), HttpKernelInterface::SUB_REQUEST, false)->willReturn(new Response())->shouldBeCalled(); - $eventProphecy = $this->prophesize(ExceptionEvent::class); - $eventProphecy->getRequest()->willReturn($request); - if (method_exists(ExceptionEvent::class, 'getThrowable')) { - $eventProphecy->getThrowable()->willReturn(new \Exception()); - } else { - $eventProphecy->getException()->willReturn(new \Exception()); - } - $eventProphecy->getKernel()->willReturn($kernel); - $eventProphecy->setResponse(Argument::type(Response::class))->shouldBeCalled(); - $listener = new ExceptionListener('foo:bar', null, false, class_exists(ErrorListener::class) ? $this->prophesize(ErrorListener::class)->reveal() : null); - $listener->onKernelException($eventProphecy->reveal()); + $event = new ExceptionEvent($kernel->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, new \Exception()); + $listener->onKernelException($event); + + $this->assertInstanceOf(Response::class, $event->getResponse()); } public function getRequest() @@ -62,12 +55,11 @@ public function getRequest() public function testDoNothingWhenNotAnApiCall() { - $eventProphecy = $this->prophesize(ExceptionEvent::class); - $eventProphecy->getRequest()->willReturn(new Request()); - $eventProphecy->setResponse(Argument::type(Response::class))->shouldNotBeCalled(); - $listener = new ExceptionListener('foo:bar', null, false, class_exists(ErrorListener::class) ? $this->prophesize(ErrorListener::class)->reveal() : null); - $listener->onKernelException($eventProphecy->reveal()); + $event = new ExceptionEvent($this->prophesize(HttpKernelInterface::class)->reveal(), new Request(), HttpKernelInterface::MASTER_REQUEST, new \Exception()); + $listener->onKernelException($event); + + $this->assertNull($event->getResponse()); } public function testDoNothingWhenHtmlRequested() @@ -75,11 +67,10 @@ public function testDoNothingWhenHtmlRequested() $request = new Request([], [], ['_api_respond' => true]); $request->setRequestFormat('html'); - $eventProphecy = $this->prophesize(ExceptionEvent::class); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->setResponse(Argument::type(Response::class))->shouldNotBeCalled(); - $listener = new ExceptionListener('foo:bar', null, false, class_exists(ErrorListener::class) ? $this->prophesize(ErrorListener::class)->reveal() : null); - $listener->onKernelException($eventProphecy->reveal()); + $event = new ExceptionEvent($this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, new \Exception()); + $listener->onKernelException($event); + + $this->assertNull($event->getResponse()); } } diff --git a/tests/EventListener/RespondListenerTest.php b/tests/EventListener/RespondListenerTest.php index fd397873464..3f800caefb1 100644 --- a/tests/EventListener/RespondListenerTest.php +++ b/tests/EventListener/RespondListenerTest.php @@ -19,7 +19,6 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; use ApiPlatform\Core\Tests\ProphecyTrait; use PHPUnit\Framework\TestCase; -use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ViewEvent; @@ -34,28 +33,25 @@ class RespondListenerTest extends TestCase public function testDoNotHandleResponse() { - $request = new Request(); - - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn(new Response()); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->setResponse(Argument::any())->shouldNotBeCalled(); - $listener = new RespondListener(); - $listener->onKernelView($eventProphecy->reveal()); + $event = new ViewEvent($this->prophesize(HttpKernelInterface::class)->reveal(), new Request(), HttpKernelInterface::MASTER_REQUEST, null); + $listener->onKernelView($event); + + $this->assertNull($event->getResponse()); } public function testDoNotHandleWhenRespondFlagIsFalse() { - $request = new Request([], [], ['_api_respond' => false]); - - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn('foo'); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->setResponse(Argument::any())->shouldNotBeCalled(); - $listener = new RespondListener(); - $listener->onKernelView($eventProphecy->reveal()); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_respond' => false]), + HttpKernelInterface::MASTER_REQUEST, + 'foo' + ); + $listener->onKernelView($event); + + $this->assertNull($event->getResponse()); } public function testCreate200Response() @@ -63,9 +59,8 @@ public function testCreate200Response() $request = new Request([], [], ['_api_respond' => true]); $request->setRequestFormat('xml'); - $kernelProphecy = $this->prophesize(HttpKernelInterface::class); $event = new ViewEvent( - $kernelProphecy->reveal(), + $this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, 'foo' @@ -85,13 +80,11 @@ public function testCreate200Response() public function testPost200WithoutLocation() { - $kernelProphecy = $this->prophesize(HttpKernelInterface::class); - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true, '_api_write_item_iri' => '/dummy_entities/1']); $request->setMethod('POST'); $event = new ViewEvent( - $kernelProphecy->reveal(), + $this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, 'bar' @@ -109,13 +102,11 @@ public function testPost200WithoutLocation() public function testPost301WithLocation() { - $kernelProphecy = $this->prophesize(HttpKernelInterface::class); - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true, '_api_write_item_iri' => '/dummy_entities/1']); $request->setMethod('POST'); $event = new ViewEvent( - $kernelProphecy->reveal(), + $this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, 'bar' @@ -134,14 +125,12 @@ public function testPost301WithLocation() public function testCreate201Response() { - $kernelProphecy = $this->prophesize(HttpKernelInterface::class); - $request = new Request([], [], ['_api_respond' => true, '_api_write_item_iri' => '/dummy_entities/1']); $request->setMethod('POST'); $request->setRequestFormat('xml'); $event = new ViewEvent( - $kernelProphecy->reveal(), + $this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, 'foo' @@ -164,14 +153,12 @@ public function testCreate201Response() public function testCreate204Response() { - $kernelProphecy = $this->prophesize(HttpKernelInterface::class); - $request = new Request([], [], ['_api_respond' => true]); $request->setRequestFormat('xml'); $request->setMethod('DELETE'); $event = new ViewEvent( - $kernelProphecy->reveal(), + $this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, 'foo' @@ -191,13 +178,9 @@ public function testCreate204Response() public function testSetSunsetHeader() { - $kernelProphecy = $this->prophesize(HttpKernelInterface::class); - - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true]); - $event = new ViewEvent( - $kernelProphecy->reveal(), - $request, + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true]), HttpKernelInterface::MASTER_REQUEST, 'bar' ); @@ -215,13 +198,9 @@ public function testSetSunsetHeader() public function testSetCustomStatus() { - $kernelProphecy = $this->prophesize(HttpKernelInterface::class); - - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true]); - $event = new ViewEvent( - $kernelProphecy->reveal(), - $request, + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true]), HttpKernelInterface::MASTER_REQUEST, 'bar' ); @@ -236,14 +215,17 @@ public function testSetCustomStatus() public function testHandleResponse() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true]); + $listener = new RespondListener(); + $response = new Response(); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn($response); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->setResponse($response)->shouldBeCalled(); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get', '_api_respond' => true]), + HttpKernelInterface::MASTER_REQUEST, + $response + ); + $listener->onKernelView($event); - $listener = new RespondListener(); - $listener->onKernelView($eventProphecy->reveal()); + $this->assertSame($response, $event->getResponse()); } } diff --git a/tests/EventListener/SerializeListenerTest.php b/tests/EventListener/SerializeListenerTest.php index 05cb16f14aa..c5329baf2fb 100644 --- a/tests/EventListener/SerializeListenerTest.php +++ b/tests/EventListener/SerializeListenerTest.php @@ -23,8 +23,8 @@ use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ViewEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Serializer\Encoder\EncoderInterface; use Symfony\Component\Serializer\SerializerInterface; @@ -40,17 +40,20 @@ public function testDoNotSerializeWhenControllerResultIsResponse() $serializerProphecy = $this->prophesize(SerializerInterface::class); $serializerProphecy->serialize(Argument::cetera())->shouldNotBeCalled(); - $request = new Request(); - - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn(new Response()); - $eventProphecy->getRequest()->willReturn($request); - $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); $serializerContextBuilderProphecy->createFromRequest(Argument::cetera()); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request(), + HttpKernelInterface::MASTER_REQUEST, + null + ); + $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + $listener->onKernelView($event); + + $this->assertNull($event->getResponse()); } public function testDoNotSerializeWhenRespondFlagIsFalse() @@ -65,13 +68,17 @@ public function testDoNotSerializeWhenRespondFlagIsFalse() $request = new Request([], [], ['data' => $dummy, '_api_resource_class' => Dummy::class, '_api_collection_operation_name' => 'post', '_api_respond' => false]); $request->setMethod('POST'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn($dummy); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->setControllerResult(Argument::any())->shouldNotBeCalled(); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $dummy + ); $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + $listener->onKernelView($event); + + $this->assertNull($event->getResponse()); } public function testDoNotSerializeWhenDisabledInOperationAttribute() @@ -91,17 +98,20 @@ public function testDoNotSerializeWhenDisabledInOperationAttribute() $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn($resourceMetadata); $dummy = new Dummy(); - $request = new Request([], [], ['data' => $dummy, '_api_resource_class' => Dummy::class, '_api_collection_operation_name' => 'post']); $request->setMethod('POST'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn($dummy); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->setControllerResult(Argument::any())->shouldNotBeCalled(); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $dummy + ); $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + $listener->onKernelView($event); + + $this->assertNull($event->getResponse()); } public function testSerializeCollectionOperation() @@ -125,19 +135,22 @@ public function testSerializeCollectionOperation() ->willReturn('bar') ->shouldBeCalled(); - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); - $request->setRequestFormat('xml'); - - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn(new \stdClass())->shouldBeCalled(); - $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); - $eventProphecy->setControllerResult('bar')->shouldBeCalled(); - $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext)->shouldBeCalled(); + $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get']); + $request->setRequestFormat('xml'); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new \stdClass() + ); + $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + $listener->onKernelView($event); + + $this->assertSame('bar', $event->getControllerResult()); } public function testSerializeCollectionOperationWithOutputClassDisabled() @@ -145,19 +158,23 @@ public function testSerializeCollectionOperationWithOutputClassDisabled() $expectedContext = ['request_uri' => '', 'resource_class' => 'Foo', 'collection_operation_name' => 'post', 'output' => ['class' => null]]; $serializerProphecy = $this->prophesize(SerializerInterface::class); + $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); + $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext)->shouldBeCalled(); + $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_collection_operation_name' => 'get', '_api_output_class' => false]); $request->setRequestFormat('xml'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn(new \stdClass()); - $eventProphecy->getRequest()->willReturn($request); - $eventProphecy->setControllerResult(null)->shouldBeCalled(); - - $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); - $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext)->shouldBeCalled(); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new \stdClass() + ); $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + $listener->onKernelView($event); + + $this->assertNull($event->getControllerResult()); } public function testSerializeItemOperation() @@ -180,19 +197,22 @@ public function testSerializeItemOperation() ->willReturn('bar') ->shouldBeCalled(); - $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get']); - $request->setRequestFormat('xml'); - - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn(new \stdClass())->shouldBeCalled(); - $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); - $eventProphecy->setControllerResult('bar')->shouldBeCalled(); - $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); $serializerContextBuilderProphecy->createFromRequest(Argument::type(Request::class), true, Argument::type('array'))->willReturn($expectedContext)->shouldBeCalled(); + $request = new Request([], [], ['_api_resource_class' => 'Foo', '_api_item_operation_name' => 'get']); + $request->setRequestFormat('xml'); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new \stdClass() + ); + $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + $listener->onKernelView($event); + + $this->assertSame('bar', $event->getControllerResult()); } public function testEncode() @@ -202,17 +222,21 @@ public function testEncode() $serializerProphecy->encode(Argument::any(), 'xml')->willReturn('bar')->shouldBeCalled(); $serializerProphecy->serialize(Argument::cetera())->shouldNotBeCalled(); + $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); + $request = new Request([], [], ['_api_respond' => true]); $request->setRequestFormat('xml'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn([])->shouldBeCalled(); - $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); - $eventProphecy->setControllerResult('bar')->shouldBeCalled(); - - $serializerContextBuilderProphecy = $this->prophesize(SerializerContextBuilderInterface::class); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + [] + ); $listener = new SerializeListener($serializerProphecy->reveal(), $serializerContextBuilderProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + $listener->onKernelView($event); + + $this->assertSame('bar', $event->getControllerResult()); } } diff --git a/tests/Fixtures/TestBundle/Document/User.php b/tests/Fixtures/TestBundle/Document/User.php index ca3abe9a1a1..c625cda8b1e 100644 --- a/tests/Fixtures/TestBundle/Document/User.php +++ b/tests/Fixtures/TestBundle/Document/User.php @@ -19,8 +19,7 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordInput; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordOutput; use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; -use FOS\UserBundle\Model\User as BaseUser; -use FOS\UserBundle\Model\UserInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Serializer\Annotation\Groups; /** @@ -59,7 +58,7 @@ * @author Théo FIDRY * @author Kévin Dunglas */ -class User extends BaseUser +class User implements UserInterface { /** * @var int @@ -109,19 +108,27 @@ public function setFullname($fullname) return $this; } - /** - * @return string|null - */ - public function getFullname() + public function getUsername(): string { - return $this->fullname; + return (string) $this->email; } - /** - * {@inheritdoc} - */ - public function isUser(UserInterface $user = null) + public function getRoles(): array + { + return ['ROLE_USER']; + } + + public function getPassword() + { + return null; + } + + public function getSalt() + { + return null; + } + + public function eraseCredentials() { - return $user instanceof self && $user->id === $this->id; } } diff --git a/tests/Fixtures/TestBundle/Entity/Dummy.php b/tests/Fixtures/TestBundle/Entity/Dummy.php index bcc1593bea7..af81454acb1 100644 --- a/tests/Fixtures/TestBundle/Entity/Dummy.php +++ b/tests/Fixtures/TestBundle/Entity/Dummy.php @@ -98,7 +98,7 @@ class Dummy * @var \DateTime A dummy date * * @ORM\Column(type="datetime", nullable=true) - * @Assert\DateTime + * @ApiProperty(iri="http://schema.org/DateTime") */ public $dummyDate; diff --git a/tests/Fixtures/TestBundle/Entity/User.php b/tests/Fixtures/TestBundle/Entity/User.php index 5a6b0261926..1b907fd6680 100644 --- a/tests/Fixtures/TestBundle/Entity/User.php +++ b/tests/Fixtures/TestBundle/Entity/User.php @@ -19,8 +19,7 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordInput; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Dto\RecoverPasswordOutput; use Doctrine\ORM\Mapping as ORM; -use FOS\UserBundle\Model\User as BaseUser; -use FOS\UserBundle\Model\UserInterface; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Serializer\Annotation\Groups; /** @@ -60,7 +59,7 @@ * @author Théo FIDRY * @author Kévin Dunglas */ -class User extends BaseUser +class User implements UserInterface { /** * @var int @@ -69,36 +68,61 @@ class User extends BaseUser * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ - protected $id; + private $id; /** - * @var string + * @var string|null * * @Groups({"user"}) */ - protected $email; + private $email; /** - * @var string + * @var string|null * * @ORM\Column(type="string", length=255, nullable=true) * @Groups({"user"}) */ - protected $fullname; + private $fullname; /** - * @var string + * @var string|null * * @Groups({"user-write"}) */ - protected $plainPassword; + private $plainPassword; /** * @var string * * @Groups({"user"}) */ - protected $username; + private $username; + + public function getId(): int + { + return $this->id; + } + + public function getEmail(): string + { + return $this->email; + } + + public function setEmail(string $email): void + { + $this->email = $email; + } + + public function getPlainPassword(): ?string + { + return $this->plainPassword; + } + + public function setPlainPassword(string $plainPassword): void + { + $this->plainPassword = $plainPassword; + } /** * @param string|null $fullname @@ -120,11 +144,27 @@ public function getFullname() return $this->fullname; } - /** - * {@inheritdoc} - */ - public function isUser(UserInterface $user = null) + public function getUsername(): string + { + return (string) $this->email; + } + + public function getRoles(): array + { + return ['ROLE_USER']; + } + + public function getPassword() + { + return null; + } + + public function getSalt() + { + return null; + } + + public function eraseCredentials() { - return $user instanceof self && $user->id === $this->id; } } diff --git a/tests/Fixtures/app/AppKernel.php b/tests/Fixtures/app/AppKernel.php index e5d2e9b52de..dc387c557cb 100644 --- a/tests/Fixtures/app/AppKernel.php +++ b/tests/Fixtures/app/AppKernel.php @@ -19,7 +19,7 @@ use Doctrine\Bundle\MongoDBBundle\DoctrineMongoDBBundle; use Doctrine\Common\Inflector\Inflector; use Doctrine\Inflector\InflectorFactory; -use FOS\UserBundle\FOSUserBundle; +use FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle; use Nelmio\ApiDocBundle\NelmioApiDocBundle; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; @@ -31,6 +31,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; use Symfony\Component\Routing\RouteCollectionBuilder; use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; use Symfony\Component\Security\Core\User\UserInterface; @@ -67,20 +68,20 @@ public function registerBundles(): array new MercureBundle(), new ApiPlatformBundle(), new SecurityBundle(), - new FOSUserBundle(), new WebProfilerBundle(), + new FriendsOfBehatSymfonyExtensionBundle(), ]; if (class_exists(DoctrineMongoDBBundle::class)) { $bundles[] = new DoctrineMongoDBBundle(); } - if ('elasticsearch' !== $this->getEnvironment()) { - $bundles[] = new TestBundle(); + if (class_exists(NelmioApiDocBundle::class)) { + $bundles[] = new NelmioApiDocBundle(); } - if ($_SERVER['LEGACY'] ?? false) { - $bundles[] = new NelmioApiDocBundle(); + if ('elasticsearch' !== $this->getEnvironment()) { + $bundles[] = new TestBundle(); } return $bundles; @@ -91,11 +92,14 @@ public function getProjectDir() return __DIR__; } - protected function configureRoutes(RouteCollectionBuilder $routes) + /** + * @param RoutingConfigurator|RouteCollectionBuilder $routes + */ + protected function configureRoutes($routes) { $routes->import(__DIR__."/config/routing_{$this->getEnvironment()}.yml"); - if ($_SERVER['LEGACY'] ?? false) { + if (class_exists(NelmioApiDocBundle::class)) { $routes->import('@NelmioApiDocBundle/Resources/config/routing.yml', '/nelmioapidoc'); } } @@ -117,7 +121,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load 'providers' => [ 'chain_provider' => [ 'chain' => [ - 'providers' => ['in_memory', 'fos_userbundle'], + 'providers' => ['in_memory', 'entity'], ], ], 'in_memory' => [ @@ -128,7 +132,12 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load ], ], ], - 'fos_userbundle' => ['id' => 'fos_user.user_provider.username_email'], + 'entity' => [ + 'entity' => [ + 'class' => User::class, + 'property' => 'email', + ], + ], ], 'firewalls' => [ 'dev' => [ @@ -168,7 +177,7 @@ protected function configureContainer(ContainerBuilder $c, LoaderInterface $load } $c->prependExtensionConfig('twig', $twigConfig); - if ($_SERVER['LEGACY'] ?? false) { + if (class_exists(NelmioApiDocBundle::class)) { $c->prependExtensionConfig('nelmio_api_doc', [ 'sandbox' => [ 'accept_type' => 'application/json', diff --git a/tests/Fixtures/app/config/config_behat_mongodb.yml b/tests/Fixtures/app/config/config_behat_mongodb.yml new file mode 100644 index 00000000000..7c69457562f --- /dev/null +++ b/tests/Fixtures/app/config/config_behat_mongodb.yml @@ -0,0 +1,15 @@ +services: + _defaults: + autowire: true + autoconfigure: true + + ApiPlatform\Core\Tests\Behat\CommandContext: ~ + ApiPlatform\Core\Tests\Behat\DoctrineContext: + $doctrine: '@doctrine_mongodb' + ApiPlatform\Core\Tests\Behat\HttpCacheContext: ~ + ApiPlatform\Core\Tests\Behat\HydraContext: ~ + ApiPlatform\Core\Tests\Behat\JsonApiContext: + $doctrine: '@doctrine_mongodb' + $jsonApiSchemaFile: '%kernel.project_dir%/../JsonSchema/jsonapi.json' + ApiPlatform\Core\Tests\Behat\JsonHalContext: + $schemaFile: '%kernel.project_dir%/../JsonHal/jsonhal.json' diff --git a/tests/Fixtures/app/config/config_behat_orm.yml b/tests/Fixtures/app/config/config_behat_orm.yml new file mode 100644 index 00000000000..4133d556f9f --- /dev/null +++ b/tests/Fixtures/app/config/config_behat_orm.yml @@ -0,0 +1,15 @@ +services: + _defaults: + autowire: true + autoconfigure: true + + ApiPlatform\Core\Tests\Behat\CommandContext: ~ + ApiPlatform\Core\Tests\Behat\DoctrineContext: + $doctrine: '@doctrine' + ApiPlatform\Core\Tests\Behat\HttpCacheContext: ~ + ApiPlatform\Core\Tests\Behat\HydraContext: ~ + ApiPlatform\Core\Tests\Behat\JsonApiContext: + $doctrine: '@doctrine' + $jsonApiSchemaFile: '%kernel.project_dir%/../JsonSchema/jsonapi.json' + ApiPlatform\Core\Tests\Behat\JsonHalContext: + $schemaFile: '%kernel.project_dir%/../JsonHal/jsonhal.json' diff --git a/tests/Fixtures/app/config/config_common.yml b/tests/Fixtures/app/config/config_common.yml index e3f614ad159..c011f1e3faf 100644 --- a/tests/Fixtures/app/config/config_common.yml +++ b/tests/Fixtures/app/config/config_common.yml @@ -7,10 +7,11 @@ framework: test: ~ session: storage_id: 'session.storage.mock_file' - form: ~ # For FOSUser profiler: enabled: true collect: false + router: + utf8: true web_profiler: toolbar: true @@ -57,7 +58,6 @@ api_platform: enabled: true nesting_separator: __ name_converter: 'app.name_converter' - enable_fos_user: true collection: order_parameter_name: 'order' order: 'ASC' @@ -123,9 +123,6 @@ services: tags: - { name: 'serializer.normalizer' } - fos_user.mailer.default: - class: 'ApiPlatform\Core\Tests\Mock\FosUser\MailerMock' - app.name_converter: class: 'ApiPlatform\Core\Tests\Fixtures\TestBundle\Serializer\NameConverter\CustomConverter' @@ -143,6 +140,8 @@ services: ApiPlatform\Core\Tests\Fixtures\TestBundle\Controller\: resource: '../../TestBundle/Controller' + autowire: true + autoconfigure: true tags: ['controller.service_arguments'] app.config_dummy_resource.action: diff --git a/tests/Fixtures/app/config/config_elasticsearch.yml b/tests/Fixtures/app/config/config_elasticsearch.yml index abb0610ccf3..33162ed0a5e 100644 --- a/tests/Fixtures/app/config/config_elasticsearch.yml +++ b/tests/Fixtures/app/config/config_elasticsearch.yml @@ -14,3 +14,10 @@ services: test.api_platform.elasticsearch.client: parent: api_platform.elasticsearch.client public: true + + ApiPlatform\Core\Tests\Behat\ElasticsearchContext: + public: true + arguments: + $client: '@test.api_platform.elasticsearch.client' + $elasticsearchMappingsPath: '%kernel.project_dir%/../Elasticsearch/Mappings/' + $elasticsearchFixturesPath: '%kernel.project_dir%/../Elasticsearch/Fixtures/' diff --git a/tests/Fixtures/app/config/config_mongodb.yml b/tests/Fixtures/app/config/config_mongodb.yml index 3b1e3d353d2..15565a806d3 100644 --- a/tests/Fixtures/app/config/config_mongodb.yml +++ b/tests/Fixtures/app/config/config_mongodb.yml @@ -1,5 +1,6 @@ imports: - { resource: config_common.yml } + - { resource: config_behat_mongodb.yml } parameters: env(MONGODB_DB): api_platform_test @@ -22,14 +23,6 @@ api_platform: - '%kernel.project_dir%/../TestBundle/Model' - '%kernel.project_dir%/config/api_resources_mongodb_odm.yaml' -fos_user: - db_driver: 'mongodb' - firewall_name: 'api' - user_class: 'ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\User' - from_email: - address: 'no-reply@les-tilleuls.coop' - sender_name: 'Kévin Dunglas' - services: app.my_dummy_resource.mongodb.boolean_filter: parent: 'api_platform.doctrine_mongodb.odm.boolean_filter' diff --git a/tests/Fixtures/app/config/config_test.yml b/tests/Fixtures/app/config/config_test.yml index 663fc25bd0f..6e4d2182897 100644 --- a/tests/Fixtures/app/config/config_test.yml +++ b/tests/Fixtures/app/config/config_test.yml @@ -1,5 +1,6 @@ imports: - { resource: config_common.yml } + - { resource: config_behat_orm.yml } api_platform: doctrine_mongodb_odm: false @@ -8,14 +9,6 @@ api_platform: - '%kernel.project_dir%/../TestBundle/Model' - '%kernel.project_dir%/config/api_resources_orm.yaml' -fos_user: - db_driver: 'orm' - firewall_name: 'api' - user_class: 'ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\User' - from_email: - address: 'no-reply@les-tilleuls.coop' - sender_name: 'Kévin Dunglas' - services: app.my_dummy_resource.search_filter: parent: 'api_platform.doctrine.orm.search_filter' diff --git a/tests/GraphQl/Action/EntrypointActionTest.php b/tests/GraphQl/Action/EntrypointActionTest.php index eb687bab3a2..049d42578b3 100644 --- a/tests/GraphQl/Action/EntrypointActionTest.php +++ b/tests/GraphQl/Action/EntrypointActionTest.php @@ -238,6 +238,8 @@ private function getEntrypointAction(array $variables = ['graphqlVariable']): En $executorProphecy->executeQuery(Argument::is($schema->reveal()), 'graphqlQuery', null, null, $variables, 'graphqlOperationName')->willReturn($executionResultProphecy->reveal()); $twigProphecy = $this->prophesize(TwigEnvironment::class); + $twigProphecy->render(Argument::cetera())->willReturn(''); + $routerProphecy = $this->prophesize(RouterInterface::class); $graphiQlAction = new GraphiQlAction($twigProphecy->reveal(), $routerProphecy->reveal(), true); diff --git a/tests/GraphQl/Action/GraphQlPlaygroundActionTest.php b/tests/GraphQl/Action/GraphQlPlaygroundActionTest.php index 9d5ce6923c2..ecd0d16eb32 100644 --- a/tests/GraphQl/Action/GraphQlPlaygroundActionTest.php +++ b/tests/GraphQl/Action/GraphQlPlaygroundActionTest.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\GraphQl\Action\GraphQlPlaygroundAction; use ApiPlatform\Core\Tests\ProphecyTrait; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -50,6 +51,7 @@ public function testDisabledAction(): void private function getGraphQlPlaygroundAction(bool $enabled): GraphQlPlaygroundAction { $twigProphecy = $this->prophesize(TwigEnvironment::class); + $twigProphecy->render(Argument::cetera())->willReturn(''); $routerProphecy = $this->prophesize(RouterInterface::class); return new GraphQlPlaygroundAction($twigProphecy->reveal(), $routerProphecy->reveal(), $enabled, ''); diff --git a/tests/GraphQl/Action/GraphiQlActionTest.php b/tests/GraphQl/Action/GraphiQlActionTest.php index f3df3780e92..f20c7978247 100644 --- a/tests/GraphQl/Action/GraphiQlActionTest.php +++ b/tests/GraphQl/Action/GraphiQlActionTest.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\GraphQl\Action\GraphiQlAction; use ApiPlatform\Core\Tests\ProphecyTrait; use PHPUnit\Framework\TestCase; +use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -50,6 +51,7 @@ public function testDisabledAction(): void private function getGraphiQlAction(bool $enabled): GraphiQlAction { $twigProphecy = $this->prophesize(TwigEnvironment::class); + $twigProphecy->render(Argument::cetera())->willReturn(''); $routerProphecy = $this->prophesize(RouterInterface::class); return new GraphiQlAction($twigProphecy->reveal(), $routerProphecy->reveal(), $enabled, ''); diff --git a/tests/HttpCache/EventListener/AddHeadersListenerTest.php b/tests/HttpCache/EventListener/AddHeadersListenerTest.php index 19f889bcc8a..3a55f9556b5 100644 --- a/tests/HttpCache/EventListener/AddHeadersListenerTest.php +++ b/tests/HttpCache/EventListener/AddHeadersListenerTest.php @@ -22,6 +22,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; /** * @author Kévin Dunglas @@ -34,15 +35,16 @@ public function testDoNotSetHeaderWhenMethodNotCacheable() { $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $request->setMethod('PUT'); - $response = new Response(); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldNotBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddHeadersListener(true); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertNull($response->getEtag()); } @@ -50,63 +52,66 @@ public function testDoNotSetHeaderWhenMethodNotCacheable() public function testDoNotSetHeaderOnUnsuccessfulResponse() { $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); - $response = new Response('{}', Response::HTTP_BAD_REQUEST); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddHeadersListener(true); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertNull($response->getEtag()); } public function testDoNotSetHeaderWhenNotAnApiOperation() { - $request = new Request(); $response = new Response(); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldNotBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request(), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddHeadersListener(true); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertNull($response->getEtag()); } public function testDoNotSetHeaderWhenNoContent() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response(); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); - + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddHeadersListener(true); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertNull($response->getEtag()); } public function testAddHeaders() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response('some content', 200, ['Vary' => ['Accept', 'Cookie']]); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $factory = $this->prophesize(ResourceMetadataFactoryInterface::class); $factory->create(Dummy::class)->willReturn(new ResourceMetadata())->shouldBeCalled(); $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('"9893532233caff98cd083a116b013c0b"', $response->getEtag()); $this->assertSame('max-age=100, public, s-maxage=200', $response->headers->get('Cache-Control')); @@ -115,22 +120,24 @@ public function testAddHeaders() public function testDoNotSetHeaderWhenAlreadySet() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response('some content', 200, ['Vary' => ['Accept', 'Cookie']]); $response->setEtag('etag'); $response->setMaxAge(300); // This also calls setPublic $response->setSharedMaxAge(400); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $factory = $this->prophesize(ResourceMetadataFactoryInterface::class); $factory->create(Dummy::class)->willReturn(new ResourceMetadata())->shouldBeCalled(); $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('"etag"', $response->getEtag()); $this->assertSame('max-age=300, public, s-maxage=400', $response->headers->get('Cache-Control')); @@ -139,19 +146,20 @@ public function testDoNotSetHeaderWhenAlreadySet() public function testSetHeadersFromResourceMetadata() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response('some content', 200, ['Vary' => ['Accept', 'Cookie']]); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $metadata = new ResourceMetadata(null, null, null, null, null, ['cache_headers' => ['max_age' => 123, 'shared_max_age' => 456, 'vary' => ['Vary-1', 'Vary-2']]]); $factory = $this->prophesize(ResourceMetadataFactoryInterface::class); $factory->create(Dummy::class)->willReturn($metadata)->shouldBeCalled(); $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], true, $factory->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('max-age=123, public, s-maxage=456', $response->headers->get('Cache-Control')); $this->assertSame(['Vary-1', 'Vary-2'], $response->getVary()); @@ -159,12 +167,13 @@ public function testSetHeadersFromResourceMetadata() public function testSetHeadersFromResourceMetadataMarkedAsPrivate() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response('some content', 200); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $metadata = new ResourceMetadata(null, null, null, null, null, [ 'cache_headers' => [ @@ -177,7 +186,7 @@ public function testSetHeadersFromResourceMetadataMarkedAsPrivate() $factory->create(Dummy::class)->willReturn($metadata)->shouldBeCalled(); $listener = new AddHeadersListener(true, 100, 200, [], true, $factory->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('max-age=123, private', $response->headers->get('Cache-Control')); @@ -187,12 +196,13 @@ public function testSetHeadersFromResourceMetadataMarkedAsPrivate() public function testSetHeadersFromResourceMetadataMarkedAsPublic() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response('some content', 200); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $metadata = new ResourceMetadata(null, null, null, null, null, [ 'cache_headers' => [ @@ -205,19 +215,20 @@ public function testSetHeadersFromResourceMetadataMarkedAsPublic() $factory->create(Dummy::class)->willReturn($metadata)->shouldBeCalled(); $listener = new AddHeadersListener(true, 100, 200, [], true, $factory->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('max-age=123, public, s-maxage=456', $response->headers->get('Cache-Control')); } public function testSetHeadersFromResourceMetadataWithNoPrivacy() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response('some content', 200); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $metadata = new ResourceMetadata(null, null, null, null, null, [ 'cache_headers' => [ @@ -229,19 +240,20 @@ public function testSetHeadersFromResourceMetadataWithNoPrivacy() $factory->create(Dummy::class)->willReturn($metadata)->shouldBeCalled(); $listener = new AddHeadersListener(true, 100, 200, [], true, $factory->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('max-age=123, public, s-maxage=456', $response->headers->get('Cache-Control')); } public function testSetHeadersFromResourceMetadataWithNoPrivacyDefaultsPrivate() { - $request = new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); $response = new Response('some content', 200); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $metadata = new ResourceMetadata(null, null, null, null, null, [ 'cache_headers' => [ @@ -253,7 +265,7 @@ public function testSetHeadersFromResourceMetadataWithNoPrivacyDefaultsPrivate() $factory->create(Dummy::class)->willReturn($metadata)->shouldBeCalled(); $listener = new AddHeadersListener(true, 100, 200, ['Accept', 'Accept-Encoding'], false, $factory->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('max-age=123, private', $response->headers->get('Cache-Control')); diff --git a/tests/HttpCache/EventListener/AddTagsListenerTest.php b/tests/HttpCache/EventListener/AddTagsListenerTest.php index 4bfa77c9c9e..38c7298eb5a 100644 --- a/tests/HttpCache/EventListener/AddTagsListenerTest.php +++ b/tests/HttpCache/EventListener/AddTagsListenerTest.php @@ -21,6 +21,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; /** * @author Kévin Dunglas @@ -40,12 +41,15 @@ public function testDoNotSetHeaderWhenMethodNotCacheable() $response->setPublic(); $response->setEtag('foo'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertFalse($response->headers->has('Cache-Tags')); } @@ -55,15 +59,16 @@ public function testDoNotSetHeaderWhenResponseNotCacheable() $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $request = new Request([], [], ['_resources' => ['/foo', '/bar'], '_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); - $response = new Response(); - - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertFalse($response->headers->has('Cache-Tags')); } @@ -72,18 +77,19 @@ public function testDoNotSetHeaderWhenNotAnApiOperation() { $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $request = new Request([], [], ['_resources' => ['/foo', '/bar']]); - $response = new Response(); $response->setPublic(); $response->setEtag('foo'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_resources' => ['/foo', '/bar']]), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertFalse($response->headers->has('Cache-Tags')); } @@ -92,18 +98,19 @@ public function testDoNotSetHeaderWhenEmptyTagList() { $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $request = new Request([], [], ['_resources' => [], '_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); - $response = new Response(); $response->setPublic(); $response->setEtag('foo'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_resources' => [], '_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertFalse($response->headers->has('Cache-Tags')); } @@ -112,18 +119,19 @@ public function testAddTags() { $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); - $request = new Request([], [], ['_resources' => ['/foo', '/bar'], '_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']); - $response = new Response(); $response->setPublic(); $response->setEtag('foo'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_resources' => ['/foo', '/bar'], '_api_resource_class' => Dummy::class, '_api_item_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('/foo,/bar', $response->headers->get('Cache-Tags')); } @@ -133,18 +141,19 @@ public function testAddCollectionIri() $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $iriConverterProphecy->getIriFromResourceClass(Dummy::class)->willReturn('/dummies')->shouldBeCalled(); - $request = new Request([], [], ['_resources' => ['/foo', '/bar'], '_api_resource_class' => Dummy::class, '_api_collection_operation_name' => 'get']); - $response = new Response(); $response->setPublic(); $response->setEtag('foo'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_resources' => ['/foo', '/bar'], '_api_resource_class' => Dummy::class, '_api_collection_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('/foo,/bar,/dummies', $response->headers->get('Cache-Tags')); } @@ -154,18 +163,19 @@ public function testAddCollectionIriWhenCollectionIsEmpty() $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $iriConverterProphecy->getIriFromResourceClass(Dummy::class)->willReturn('/dummies')->shouldBeCalled(); - $request = new Request([], [], ['_resources' => [], '_api_resource_class' => Dummy::class, '_api_collection_operation_name' => 'get']); - $response = new Response(); $response->setPublic(); $response->setEtag('foo'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_resources' => [], '_api_resource_class' => Dummy::class, '_api_collection_operation_name' => 'get']), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('/dummies', $response->headers->get('Cache-Tags')); } @@ -175,18 +185,19 @@ public function testAddSubResourceCollectionIri() $iriConverterProphecy = $this->prophesize(IriConverterInterface::class); $iriConverterProphecy->getIriFromResourceClass(Dummy::class)->willReturn('/dummies')->shouldBeCalled(); - $request = new Request([], [], ['_resources' => ['/foo', '/bar'], '_api_resource_class' => Dummy::class, '_api_subresource_operation_name' => 'api_dummies_relatedDummies_get_subresource', '_api_subresource_context' => ['collection' => true]]); - $response = new Response(); $response->setPublic(); $response->setEtag('foo'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); - $event->getResponse()->willReturn($response)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + new Request([], [], ['_resources' => ['/foo', '/bar'], '_api_resource_class' => Dummy::class, '_api_subresource_operation_name' => 'api_dummies_relatedDummies_get_subresource', '_api_subresource_context' => ['collection' => true]]), + HttpKernelInterface::MASTER_REQUEST, + $response + ); $listener = new AddTagsListener($iriConverterProphecy->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame('/foo,/bar,/dummies', $response->headers->get('Cache-Tags')); } diff --git a/tests/Hydra/EventListener/AddLinkHeaderListenerTest.php b/tests/Hydra/EventListener/AddLinkHeaderListenerTest.php index a55d3c116b8..45a070d6d79 100644 --- a/tests/Hydra/EventListener/AddLinkHeaderListenerTest.php +++ b/tests/Hydra/EventListener/AddLinkHeaderListenerTest.php @@ -20,7 +20,9 @@ use Fig\Link\Link; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\WebLink\HttpHeaderSerializer; /** @@ -38,11 +40,15 @@ public function testAddLinkHeader(string $expected, Request $request) $urlGenerator = $this->prophesize(UrlGeneratorInterface::class); $urlGenerator->generate('api_doc', ['_format' => 'jsonld'], UrlGeneratorInterface::ABS_URL)->willReturn('http://example.com/docs')->shouldBeCalled(); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new Response() + ); $listener = new AddLinkHeaderListener($urlGenerator->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertSame($expected, (new HttpHeaderSerializer())->serialize($request->attributes->get('_links')->getLinks())); } @@ -60,12 +66,16 @@ public function testSkipWhenPreflightRequest(): void $request->setMethod('OPTIONS'); $request->headers->set('Access-Control-Request-Method', 'POST'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new Response() + ); $urlGenerator = $this->prophesize(UrlGeneratorInterface::class); $listener = new AddLinkHeaderListener($urlGenerator->reveal()); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertFalse($request->attributes->has('_links')); } diff --git a/tests/JsonLd/Serializer/ObjectNormalizerTest.php b/tests/JsonLd/Serializer/ObjectNormalizerTest.php index bcc77a7ab20..8803496a8fe 100644 --- a/tests/JsonLd/Serializer/ObjectNormalizerTest.php +++ b/tests/JsonLd/Serializer/ObjectNormalizerTest.php @@ -48,7 +48,7 @@ public function testNormalize() '@id' => '_:1234', ]); - $normalizer = new ObjectNormalizer( + $normalizer = new ObjectNormalizer( // @phpstan-ignore-line $serializerProphecy->reveal(), $iriConverterProphecy->reveal(), $contextBuilderProphecy->reveal() @@ -77,7 +77,7 @@ public function testNormalizeEmptyArray() $contextBuilderProphecy = $this->prophesize(AnonymousContextBuilderInterface::class); $contextBuilderProphecy->getAnonymousResourceContext($dummy, Argument::type('array'))->shouldNotBeCalled(); - $normalizer = new ObjectNormalizer( + $normalizer = new ObjectNormalizer( // @phpstan-ignore-line $serializerProphecy->reveal(), $iriConverterProphecy->reveal(), $contextBuilderProphecy->reveal() @@ -101,7 +101,7 @@ public function testNormalizeWithOutput() $contextBuilderProphecy = $this->prophesize(AnonymousContextBuilderInterface::class); $contextBuilderProphecy->getAnonymousResourceContext($dummy, ['iri' => '/dummy/1234', 'api_resource' => $dummy])->shouldBeCalled()->willReturn(['@id' => '/dummy/1234', '@type' => 'Dummy', '@context' => []]); - $normalizer = new ObjectNormalizer( + $normalizer = new ObjectNormalizer( // @phpstan-ignore-line $serializerProphecy->reveal(), $iriConverterProphecy->reveal(), $contextBuilderProphecy->reveal() @@ -131,7 +131,7 @@ public function testNormalizeWithContext() $contextBuilderProphecy = $this->prophesize(AnonymousContextBuilderInterface::class); $contextBuilderProphecy->getAnonymousResourceContext($dummy, ['iri' => '/dummy/1234', 'api_resource' => $dummy, 'has_context' => true])->shouldBeCalled()->willReturn(['@id' => '/dummy/1234', '@type' => 'Dummy']); - $normalizer = new ObjectNormalizer( + $normalizer = new ObjectNormalizer( // @phpstan-ignore-line $serializerProphecy->reveal(), $iriConverterProphecy->reveal(), $contextBuilderProphecy->reveal() diff --git a/tests/Mercure/EventListener/AddLinkHeaderListenerTest.php b/tests/Mercure/EventListener/AddLinkHeaderListenerTest.php index 7392b1f5666..2044689f4ec 100644 --- a/tests/Mercure/EventListener/AddLinkHeaderListenerTest.php +++ b/tests/Mercure/EventListener/AddLinkHeaderListenerTest.php @@ -22,7 +22,9 @@ use Fig\Link\Link; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\WebLink\HttpHeaderSerializer; /** @@ -40,12 +42,15 @@ public function testAddLinkHeader(string $expected, Request $request) $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata(null, null, null, null, null, ['mercure' => true])); - $listener = new AddLinkHeaderListener($resourceMetadataFactoryProphecy->reveal(), 'https://demo.mercure.rocks/hub'); - - $eventProphecy = $this->prophesize(ResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new Response() + ); - $listener->onKernelResponse($eventProphecy->reveal()); + $listener = new AddLinkHeaderListener($resourceMetadataFactoryProphecy->reveal(), 'https://demo.mercure.rocks/hub'); + $listener->onKernelResponse($event); $this->assertSame($expected, (new HttpHeaderSerializer())->serialize($request->attributes->get('_links')->getLinks())); } @@ -66,12 +71,15 @@ public function testDoNotAddHeader(Request $request) $resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class); $resourceMetadataFactoryProphecy->create(Dummy::class)->willReturn(new ResourceMetadata()); - $listener = new AddLinkHeaderListener($resourceMetadataFactoryProphecy->reveal(), 'https://demo.mercure.rocks/hub'); - - $eventProphecy = $this->prophesize(ResponseEvent::class); - $eventProphecy->getRequest()->willReturn($request)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new Response() + ); - $listener->onKernelResponse($eventProphecy->reveal()); + $listener = new AddLinkHeaderListener($resourceMetadataFactoryProphecy->reveal(), 'https://demo.mercure.rocks/hub'); + $listener->onKernelResponse($event); $this->assertNull($request->attributes->get('_links')); } @@ -90,12 +98,16 @@ public function testSkipWhenPreflightRequest(): void $request->setMethod('OPTIONS'); $request->headers->set('Access-Control-Request-Method', 'POST'); - $event = $this->prophesize(ResponseEvent::class); - $event->getRequest()->willReturn($request)->shouldBeCalled(); + $event = new ResponseEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + new Response() + ); $resourceMetadataFactory = $this->prophesize(ResourceMetadataFactoryInterface::class); $listener = new AddLinkHeaderListener($resourceMetadataFactory->reveal(), 'http://example.com/.well-known/mercure'); - $listener->onKernelResponse($event->reveal()); + $listener->onKernelResponse($event); $this->assertFalse($request->attributes->has('_links')); } diff --git a/tests/Mock/FosUser/MailerMock.php b/tests/Mock/FosUser/MailerMock.php deleted file mode 100644 index d65e6fa1629..00000000000 --- a/tests/Mock/FosUser/MailerMock.php +++ /dev/null @@ -1,37 +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 ApiPlatform\Core\Tests\Mock\FosUser; - -use FOS\UserBundle\Mailer\MailerInterface; -use FOS\UserBundle\Model\UserInterface; - -/** - * @author Théo FIDRY - */ -class MailerMock implements MailerInterface -{ - /** - * Sends an email to a user to confirm the account creation. - */ - public function sendConfirmationEmailMessage(UserInterface $user) - { - } - - /** - * Sends an email to a user to confirm the password reset. - */ - public function sendResettingEmailMessage(UserInterface $user) - { - } -} diff --git a/tests/Validator/EventListener/ValidateListenerTest.php b/tests/Validator/EventListener/ValidateListenerTest.php index f34ce95abbc..b5cdaa9046b 100644 --- a/tests/Validator/EventListener/ValidateListenerTest.php +++ b/tests/Validator/EventListener/ValidateListenerTest.php @@ -23,7 +23,6 @@ use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ViewEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -47,12 +46,10 @@ public function testNotAnApiPlatformRequest() $request = new Request(); $request->setMethod('POST'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn([]); - $eventProphecy->getRequest()->willReturn($request); - $listener = new ValidateListener($validatorProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal()); - $listener->onKernelView($eventProphecy->reveal()); + + $event = new ViewEvent($this->prophesize(HttpKernelInterface::class)->reveal(), $request, HttpKernelInterface::MASTER_REQUEST, []); + $listener->onKernelView($event); } public function testValidatorIsCalled() @@ -82,14 +79,15 @@ public function testDoNotValidateWhenControllerResultIsResponse() $request = new Request([], [], ['data' => $dummy, '_api_resource_class' => DummyEntity::class, '_api_collection_operation_name' => 'post', '_api_receive' => false]); $request->setMethod('POST'); - $response = new Response(); - - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn($response); - $eventProphecy->getRequest()->willReturn($request); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $dummy + ); $validationViewListener = new ValidateListener($validatorProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal()); - $validationViewListener->onKernelView($eventProphecy->reveal()); + $validationViewListener->onKernelView($event); } public function testDoNotValidateWhenReceiveFlagIsFalse() @@ -104,12 +102,15 @@ public function testDoNotValidateWhenReceiveFlagIsFalse() $request = new Request([], [], ['data' => $dummy, '_api_resource_class' => DummyEntity::class, '_api_collection_operation_name' => 'post', '_api_receive' => false]); $request->setMethod('POST'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn($dummy); - $eventProphecy->getRequest()->willReturn($request); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $dummy + ); $validationViewListener = new ValidateListener($validatorProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal()); - $validationViewListener->onKernelView($eventProphecy->reveal()); + $validationViewListener->onKernelView($event); } public function testDoNotValidateWhenDisabledInOperationAttribute() @@ -131,12 +132,15 @@ public function testDoNotValidateWhenDisabledInOperationAttribute() $request = new Request([], [], ['data' => $dummy, '_api_resource_class' => DummyEntity::class, '_api_collection_operation_name' => 'post']); $request->setMethod('POST'); - $eventProphecy = $this->prophesize(ViewEvent::class); - $eventProphecy->getControllerResult()->willReturn($dummy); - $eventProphecy->getRequest()->willReturn($request); + $event = new ViewEvent( + $this->prophesize(HttpKernelInterface::class)->reveal(), + $request, + HttpKernelInterface::MASTER_REQUEST, + $dummy + ); $validationViewListener = new ValidateListener($validatorProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal()); - $validationViewListener->onKernelView($eventProphecy->reveal()); + $validationViewListener->onKernelView($event); } public function testThrowsValidationExceptionWithViolationsFound()